| /* |
| * Copyright (C) 2016 Igalia S.L. |
| * Copyright (C) 2008 Apple Inc. All Rights Reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #include "ScrollbarThemeGtk.h" |
| |
| #if !USE(GTK4) |
| |
| #include "GRefPtrGtk.h" |
| #include "GraphicsContextCairo.h" |
| #include "PlatformMouseEvent.h" |
| #include "RenderThemeScrollbar.h" |
| #include "ScrollView.h" |
| #include "Scrollbar.h" |
| #include <cstdlib> |
| #include <gtk/gtk.h> |
| |
| namespace WebCore { |
| |
| ScrollbarTheme& ScrollbarTheme::nativeTheme() |
| { |
| static ScrollbarThemeGtk theme; |
| return theme; |
| } |
| |
| ScrollbarThemeGtk::~ScrollbarThemeGtk() = default; |
| |
| static void themeChangedCallback() |
| { |
| ScrollbarTheme::theme().themeChanged(); |
| } |
| |
| ScrollbarThemeGtk::ScrollbarThemeGtk() |
| { |
| static bool themeMonitorInitialized = false; |
| if (!themeMonitorInitialized) { |
| g_signal_connect(gtk_settings_get_default(), "notify::gtk-theme-name", G_CALLBACK(themeChangedCallback), nullptr); |
| g_signal_connect(gtk_settings_get_default(), "notify::gtk-overlay-scrolling", G_CALLBACK(themeChangedCallback), nullptr); |
| themeMonitorInitialized = true; |
| updateThemeProperties(); |
| } |
| } |
| |
| void ScrollbarThemeGtk::setUseSystemAppearance(bool useSystemAppearance) |
| { |
| if (m_useSystemAppearance == useSystemAppearance) |
| return; |
| |
| m_useSystemAppearance = useSystemAppearance; |
| |
| RenderThemeScrollbar::clearCache(); |
| if (m_useSystemAppearance) |
| updateThemeProperties(); |
| } |
| |
| void ScrollbarThemeGtk::themeChanged() |
| { |
| if (!m_useSystemAppearance) |
| return; |
| |
| RenderThemeScrollbar::clearCache(); |
| updateThemeProperties(); |
| } |
| |
| void ScrollbarThemeGtk::updateThemeProperties() |
| { |
| RELEASE_ASSERT(m_useSystemAppearance); |
| auto& scrollbar = static_cast<RenderThemeScrollbar&>(RenderThemeScrollbar::getOrCreate(RenderThemeScrollbar::Type::VerticalScrollbarRight)); |
| m_hasBackButtonStartPart = scrollbar.stepper(RenderThemeScrollbarGadget::Steppers::Backward); |
| m_hasForwardButtonEndPart = scrollbar.stepper(RenderThemeScrollbarGadget::Steppers::Forward); |
| m_hasBackButtonEndPart = scrollbar.stepper(RenderThemeScrollbarGadget::Steppers::SecondaryBackward); |
| m_hasForwardButtonStartPart = scrollbar.stepper(RenderThemeScrollbarGadget::Steppers::SecondaryForward); |
| } |
| |
| bool ScrollbarThemeGtk::hasButtons(Scrollbar& scrollbar) |
| { |
| if (!m_useSystemAppearance) |
| return ScrollbarThemeAdwaita::hasButtons(scrollbar); |
| |
| return scrollbar.enabled() && (m_hasBackButtonStartPart || m_hasForwardButtonEndPart || m_hasBackButtonEndPart || m_hasForwardButtonStartPart); |
| } |
| |
| static GtkStateFlags scrollbarPartStateFlags(Scrollbar& scrollbar, ScrollbarPart part, bool painting = false) |
| { |
| unsigned stateFlags = 0; |
| switch (part) { |
| case AllParts: |
| if (!painting || scrollbar.hoveredPart() != NoPart) |
| stateFlags |= GTK_STATE_FLAG_PRELIGHT; |
| break; |
| case BackTrackPart: |
| case ForwardTrackPart: |
| if (scrollbar.hoveredPart() == BackTrackPart || scrollbar.hoveredPart() == ForwardTrackPart) |
| stateFlags |= GTK_STATE_FLAG_PRELIGHT; |
| if (scrollbar.pressedPart() == BackTrackPart || scrollbar.pressedPart() == ForwardTrackPart) |
| stateFlags |= GTK_STATE_FLAG_ACTIVE; |
| break; |
| case BackButtonStartPart: |
| case ForwardButtonStartPart: |
| case BackButtonEndPart: |
| case ForwardButtonEndPart: |
| if (((part == BackButtonStartPart || part == BackButtonEndPart) && !scrollbar.currentPos()) |
| || ((part == ForwardButtonEndPart || part == ForwardButtonStartPart) && scrollbar.currentPos() == scrollbar.maximum())) { |
| stateFlags |= GTK_STATE_FLAG_INSENSITIVE; |
| break; |
| } |
| FALLTHROUGH; |
| default: |
| if (scrollbar.hoveredPart() == part) |
| stateFlags |= GTK_STATE_FLAG_PRELIGHT; |
| |
| if (scrollbar.pressedPart() == part) |
| stateFlags |= GTK_STATE_FLAG_ACTIVE; |
| break; |
| } |
| |
| return static_cast<GtkStateFlags>(stateFlags); |
| } |
| |
| static RenderThemeScrollbar::Type widgetTypeForScrollbar(Scrollbar& scrollbar, GtkStateFlags scrollbarState) |
| { |
| if (scrollbar.orientation() == ScrollbarOrientation::Vertical) { |
| if (scrollbar.scrollableArea().shouldPlaceVerticalScrollbarOnLeft()) |
| return scrollbarState & GTK_STATE_FLAG_PRELIGHT ? RenderThemeScrollbar::Type::VerticalScrollbarLeft : RenderThemeScrollbar::Type::VerticalScrollIndicatorLeft; |
| return scrollbarState & GTK_STATE_FLAG_PRELIGHT ? RenderThemeScrollbar::Type::VerticalScrollbarRight : RenderThemeScrollbar::Type::VerticalScrollIndicatorRight; |
| } |
| return scrollbarState & GTK_STATE_FLAG_PRELIGHT ? RenderThemeScrollbar::Type::HorizontalScrollbar : RenderThemeScrollbar::Type::HorizontalScrollIndicator; |
| } |
| |
| static IntRect contentsRectangle(Scrollbar& scrollbar, RenderThemeScrollbar& scrollbarWidget) |
| { |
| GtkBorder scrollbarContentsBox = scrollbarWidget.scrollbar().contentsBox(); |
| GtkBorder contentsContentsBox = scrollbarWidget.contents().contentsBox(); |
| GtkBorder padding; |
| padding.left = scrollbarContentsBox.left + contentsContentsBox.left; |
| padding.right = scrollbarContentsBox.right + contentsContentsBox.right; |
| padding.top = scrollbarContentsBox.top + contentsContentsBox.top; |
| padding.bottom = scrollbarContentsBox.bottom + contentsContentsBox.bottom; |
| IntRect contentsRect = scrollbar.frameRect(); |
| contentsRect.move(padding.left, padding.top); |
| contentsRect.contract(padding.left + padding.right, padding.top + padding.bottom); |
| return contentsRect; |
| } |
| |
| IntRect ScrollbarThemeGtk::trackRect(Scrollbar& scrollbar, bool painting) |
| { |
| if (!m_useSystemAppearance) |
| return ScrollbarThemeAdwaita::trackRect(scrollbar, painting); |
| |
| auto scrollbarState = scrollbarPartStateFlags(scrollbar, AllParts); |
| auto& scrollbarWidget = static_cast<RenderThemeScrollbar&>(RenderThemeScrollbar::getOrCreate(widgetTypeForScrollbar(scrollbar, scrollbarState))); |
| scrollbarWidget.scrollbar().setState(scrollbarState); |
| |
| IntRect rect = contentsRectangle(scrollbar, scrollbarWidget); |
| if (auto* backwardStepper = scrollbarWidget.stepper(RenderThemeScrollbarGadget::Steppers::Backward)) { |
| backwardStepper->setState(scrollbarPartStateFlags(scrollbar, BackButtonStartPart)); |
| IntSize stepperSize = backwardStepper->preferredSize(); |
| if (scrollbar.orientation() == ScrollbarOrientation::Vertical) { |
| rect.move(0, stepperSize.height()); |
| rect.contract(0, stepperSize.height()); |
| } else { |
| rect.move(stepperSize.width(), 0); |
| rect.contract(stepperSize.width(), 0); |
| } |
| } |
| if (auto* secondaryForwardStepper = scrollbarWidget.stepper(RenderThemeScrollbarGadget::Steppers::SecondaryForward)) { |
| secondaryForwardStepper->setState(scrollbarPartStateFlags(scrollbar, ForwardButtonStartPart)); |
| IntSize stepperSize = secondaryForwardStepper->preferredSize(); |
| if (scrollbar.orientation() == ScrollbarOrientation::Vertical) { |
| rect.move(0, stepperSize.height()); |
| rect.contract(0, stepperSize.height()); |
| } else { |
| rect.move(stepperSize.width(), 0); |
| rect.contract(stepperSize.width(), 0); |
| } |
| } |
| if (auto* secondaryBackwardStepper = scrollbarWidget.stepper(RenderThemeScrollbarGadget::Steppers::SecondaryBackward)) { |
| secondaryBackwardStepper->setState(scrollbarPartStateFlags(scrollbar, BackButtonEndPart)); |
| if (scrollbar.orientation() == ScrollbarOrientation::Vertical) |
| rect.contract(0, secondaryBackwardStepper->preferredSize().height()); |
| else |
| rect.contract(secondaryBackwardStepper->preferredSize().width(), 0); |
| } |
| if (auto* forwardStepper = scrollbarWidget.stepper(RenderThemeScrollbarGadget::Steppers::Forward)) { |
| forwardStepper->setState(scrollbarPartStateFlags(scrollbar, ForwardButtonEndPart)); |
| if (scrollbar.orientation() == ScrollbarOrientation::Vertical) |
| rect.contract(0, forwardStepper->preferredSize().height()); |
| else |
| rect.contract(forwardStepper->preferredSize().width(), 0); |
| } |
| |
| if (scrollbar.orientation() == ScrollbarOrientation::Vertical) |
| return scrollbar.height() < rect.height() ? IntRect() : rect; |
| |
| return scrollbar.width() < rect.width() ? IntRect() : rect; |
| } |
| |
| IntRect ScrollbarThemeGtk::backButtonRect(Scrollbar& scrollbar, ScrollbarPart part, bool painting) |
| { |
| if (!m_useSystemAppearance) |
| return ScrollbarThemeAdwaita::backButtonRect(scrollbar, part, painting); |
| |
| ASSERT(part == BackButtonStartPart || part == BackButtonEndPart); |
| if ((part == BackButtonEndPart && !m_hasBackButtonEndPart) || (part == BackButtonStartPart && !m_hasBackButtonStartPart)) |
| return IntRect(); |
| |
| auto scrollbarState = scrollbarPartStateFlags(scrollbar, AllParts); |
| auto& scrollbarWidget = static_cast<RenderThemeScrollbar&>(RenderThemeScrollbar::getOrCreate(widgetTypeForScrollbar(scrollbar, scrollbarState))); |
| scrollbarWidget.scrollbar().setState(scrollbarState); |
| |
| IntRect rect = contentsRectangle(scrollbar, scrollbarWidget); |
| if (part == BackButtonStartPart) { |
| auto* backwardStepper = scrollbarWidget.stepper(RenderThemeScrollbarGadget::Steppers::Backward); |
| ASSERT(backwardStepper); |
| backwardStepper->setState(scrollbarPartStateFlags(scrollbar, BackButtonStartPart)); |
| return IntRect(rect.location(), backwardStepper->preferredSize()); |
| } |
| |
| if (auto* secondaryForwardStepper = scrollbarWidget.stepper(RenderThemeScrollbarGadget::Steppers::SecondaryForward)) { |
| secondaryForwardStepper->setState(scrollbarPartStateFlags(scrollbar, ForwardButtonStartPart)); |
| IntSize preferredSize = secondaryForwardStepper->preferredSize(); |
| if (scrollbar.orientation() == ScrollbarOrientation::Vertical) { |
| rect.move(0, preferredSize.height()); |
| rect.contract(0, preferredSize.height()); |
| } else { |
| rect.move(preferredSize.width(), 0); |
| rect.contract(0, preferredSize.width()); |
| } |
| } |
| |
| if (auto* secondaryBackwardStepper = scrollbarWidget.stepper(RenderThemeScrollbarGadget::Steppers::SecondaryBackward)) { |
| secondaryBackwardStepper->setState(scrollbarPartStateFlags(scrollbar, BackButtonEndPart)); |
| if (scrollbar.orientation() == ScrollbarOrientation::Vertical) |
| rect.contract(0, secondaryBackwardStepper->preferredSize().height()); |
| else |
| rect.contract(secondaryBackwardStepper->preferredSize().width(), 0); |
| } |
| |
| auto* forwardStepper = scrollbarWidget.stepper(RenderThemeScrollbarGadget::Steppers::Forward); |
| ASSERT(forwardStepper); |
| forwardStepper->setState(scrollbarPartStateFlags(scrollbar, ForwardButtonEndPart)); |
| IntSize preferredSize = forwardStepper->preferredSize(); |
| if (scrollbar.orientation() == ScrollbarOrientation::Vertical) |
| rect.move(0, rect.height() - preferredSize.height()); |
| else |
| rect.move(rect.width() - preferredSize.width(), 0); |
| |
| return IntRect(rect.location(), preferredSize); |
| } |
| |
| IntRect ScrollbarThemeGtk::forwardButtonRect(Scrollbar& scrollbar, ScrollbarPart part, bool painting) |
| { |
| if (!m_useSystemAppearance) |
| return ScrollbarThemeAdwaita::forwardButtonRect(scrollbar, part, painting); |
| |
| ASSERT(part == ForwardButtonStartPart || part == ForwardButtonEndPart); |
| if ((part == ForwardButtonStartPart && !m_hasForwardButtonStartPart) || (part == ForwardButtonEndPart && !m_hasForwardButtonEndPart)) |
| return IntRect(); |
| |
| auto scrollbarState = scrollbarPartStateFlags(scrollbar, AllParts); |
| auto& scrollbarWidget = static_cast<RenderThemeScrollbar&>(RenderThemeScrollbar::getOrCreate(widgetTypeForScrollbar(scrollbar, scrollbarState))); |
| scrollbarWidget.scrollbar().setState(scrollbarState); |
| |
| IntRect rect = contentsRectangle(scrollbar, scrollbarWidget); |
| if (auto* backwardStepper = scrollbarWidget.stepper(RenderThemeScrollbarGadget::Steppers::Backward)) { |
| backwardStepper->setState(scrollbarPartStateFlags(scrollbar, BackButtonStartPart)); |
| IntSize preferredSize = backwardStepper->preferredSize(); |
| if (scrollbar.orientation() == ScrollbarOrientation::Vertical) { |
| rect.move(0, preferredSize.height()); |
| rect.contract(0, preferredSize.height()); |
| } else { |
| rect.move(preferredSize.width(), 0); |
| rect.contract(preferredSize.width(), 0); |
| } |
| } |
| |
| if (auto* secondaryForwardStepper = scrollbarWidget.stepper(RenderThemeScrollbarGadget::Steppers::SecondaryForward)) { |
| secondaryForwardStepper->setState(scrollbarPartStateFlags(scrollbar, ForwardButtonStartPart)); |
| IntSize preferredSize = secondaryForwardStepper->preferredSize(); |
| if (part == ForwardButtonStartPart) |
| return IntRect(rect.location(), preferredSize); |
| |
| if (scrollbar.orientation() == ScrollbarOrientation::Vertical) { |
| rect.move(0, preferredSize.height()); |
| rect.contract(0, preferredSize.height()); |
| } else { |
| rect.move(preferredSize.width(), 0); |
| rect.contract(preferredSize.width(), 0); |
| } |
| } |
| |
| auto* forwardStepper = scrollbarWidget.stepper(RenderThemeScrollbarGadget::Steppers::Forward); |
| ASSERT(forwardStepper); |
| forwardStepper->setState(scrollbarPartStateFlags(scrollbar, ForwardButtonEndPart)); |
| IntSize preferredSize = forwardStepper->preferredSize(); |
| if (scrollbar.orientation() == ScrollbarOrientation::Vertical) |
| rect.move(0, rect.height() - preferredSize.height()); |
| else |
| rect.move(rect.width() - preferredSize.width(), 0); |
| |
| return IntRect(rect.location(), preferredSize); |
| } |
| |
| bool ScrollbarThemeGtk::paint(Scrollbar& scrollbar, GraphicsContext& graphicsContext, const IntRect& damageRect) |
| { |
| if (!m_useSystemAppearance) |
| return ScrollbarThemeAdwaita::paint(scrollbar, graphicsContext, damageRect); |
| |
| if (graphicsContext.paintingDisabled()) |
| return false; |
| |
| if (!scrollbar.enabled() && usesOverlayScrollbars()) |
| return true; |
| |
| double opacity = scrollbar.hoveredPart() == NoPart ? scrollbar.opacity() : 1; |
| if (!opacity) |
| return true; |
| |
| IntRect rect = scrollbar.frameRect(); |
| if (!rect.intersects(damageRect)) |
| return true; |
| |
| auto scrollbarState = scrollbarPartStateFlags(scrollbar, AllParts, true); |
| auto& scrollbarWidget = static_cast<RenderThemeScrollbar&>(RenderThemeScrollbar::getOrCreate(widgetTypeForScrollbar(scrollbar, scrollbarState))); |
| auto& scrollbarGadget = scrollbarWidget.scrollbar(); |
| scrollbarGadget.setState(scrollbarState); |
| if (usesOverlayScrollbars()) |
| opacity *= scrollbarGadget.opacity(); |
| if (!opacity) |
| return true; |
| |
| auto& trough = scrollbarWidget.trough(); |
| trough.setState(scrollbarPartStateFlags(scrollbar, BackTrackPart)); |
| |
| auto* backwardStepper = scrollbarWidget.stepper(RenderThemeScrollbarGadget::Steppers::Backward); |
| if (backwardStepper) |
| backwardStepper->setState(scrollbarPartStateFlags(scrollbar, BackButtonStartPart)); |
| auto* secondaryForwardStepper = scrollbarWidget.stepper(RenderThemeScrollbarGadget::Steppers::SecondaryForward); |
| if (secondaryForwardStepper) |
| secondaryForwardStepper->setState(scrollbarPartStateFlags(scrollbar, ForwardButtonStartPart)); |
| auto* secondaryBackwardStepper = scrollbarWidget.stepper(RenderThemeScrollbarGadget::Steppers::SecondaryBackward); |
| if (secondaryBackwardStepper) |
| secondaryBackwardStepper->setState(scrollbarPartStateFlags(scrollbar, BackButtonEndPart)); |
| auto* forwardStepper = scrollbarWidget.stepper(RenderThemeScrollbarGadget::Steppers::Forward); |
| if (forwardStepper) |
| forwardStepper->setState(scrollbarPartStateFlags(scrollbar, ForwardButtonEndPart)); |
| |
| IntSize preferredSize = scrollbarWidget.contents().preferredSize(); |
| int thumbSize = thumbLength(scrollbar); |
| if (thumbSize) { |
| scrollbarWidget.slider().setState(scrollbarPartStateFlags(scrollbar, ThumbPart)); |
| preferredSize = preferredSize.expandedTo(scrollbarWidget.slider().preferredSize()); |
| } |
| preferredSize += scrollbarGadget.preferredSize() - scrollbarGadget.minimumSize(); |
| |
| FloatRect contentsRect(rect); |
| if (usesOverlayScrollbars()) { |
| // When using overlay scrollbars we always claim the size of the scrollbar when hovered, so when |
| // drawing the indicator we need to adjust the rectangle to its actual size in indicator mode. |
| if (scrollbar.orientation() == ScrollbarOrientation::Vertical) { |
| if (rect.width() != preferredSize.width()) { |
| if (!scrollbar.scrollableArea().shouldPlaceVerticalScrollbarOnLeft()) |
| contentsRect.move(std::abs(rect.width() - preferredSize.width()), 0); |
| contentsRect.setWidth(preferredSize.width()); |
| } |
| } else { |
| if (rect.height() != preferredSize.height()) { |
| contentsRect.move(0, std::abs(rect.height() - preferredSize.height())); |
| contentsRect.setHeight(preferredSize.height()); |
| } |
| } |
| } |
| |
| if (opacity != 1) { |
| graphicsContext.save(); |
| graphicsContext.clip(damageRect); |
| graphicsContext.beginTransparencyLayer(opacity); |
| } |
| |
| scrollbarGadget.render(graphicsContext.platformContext()->cr(), contentsRect, &contentsRect); |
| scrollbarWidget.contents().render(graphicsContext.platformContext()->cr(), contentsRect, &contentsRect); |
| |
| if (backwardStepper) { |
| FloatRect buttonRect = contentsRect; |
| if (scrollbar.orientation() == ScrollbarOrientation::Vertical) |
| buttonRect.setHeight(backwardStepper->preferredSize().height()); |
| else |
| buttonRect.setWidth(backwardStepper->preferredSize().width()); |
| static_cast<RenderThemeScrollbarGadget&>(scrollbarGadget).renderStepper(graphicsContext.platformContext()->cr(), buttonRect, backwardStepper, |
| scrollbar.orientation() == ScrollbarOrientation::Vertical ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL, RenderThemeScrollbarGadget::Steppers::Backward); |
| if (scrollbar.orientation() == ScrollbarOrientation::Vertical) { |
| contentsRect.move(0, buttonRect.height()); |
| contentsRect.contract(0, buttonRect.height()); |
| } else { |
| contentsRect.move(buttonRect.width(), 0); |
| contentsRect.contract(buttonRect.width(), 0); |
| } |
| } |
| if (secondaryForwardStepper) { |
| FloatRect buttonRect = contentsRect; |
| if (scrollbar.orientation() == ScrollbarOrientation::Vertical) |
| buttonRect.setHeight(secondaryForwardStepper->preferredSize().height()); |
| else |
| buttonRect.setWidth(secondaryForwardStepper->preferredSize().width()); |
| static_cast<RenderThemeScrollbarGadget&>(scrollbarGadget).renderStepper(graphicsContext.platformContext()->cr(), buttonRect, secondaryForwardStepper, |
| scrollbar.orientation() == ScrollbarOrientation::Vertical ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL, RenderThemeScrollbarGadget::Steppers::SecondaryForward); |
| if (scrollbar.orientation() == ScrollbarOrientation::Vertical) { |
| contentsRect.move(0, buttonRect.height()); |
| contentsRect.contract(0, buttonRect.height()); |
| } else { |
| contentsRect.move(buttonRect.width(), 0); |
| contentsRect.contract(buttonRect.width(), 0); |
| } |
| } |
| if (secondaryBackwardStepper) { |
| FloatRect buttonRect = contentsRect; |
| if (scrollbar.orientation() == ScrollbarOrientation::Vertical) { |
| buttonRect.setHeight(secondaryBackwardStepper->preferredSize().height()); |
| buttonRect.move(0, contentsRect.height() - buttonRect.height()); |
| } else { |
| buttonRect.setWidth(secondaryBackwardStepper->preferredSize().width()); |
| buttonRect.move(contentsRect.width() - buttonRect.width(), 0); |
| } |
| static_cast<RenderThemeScrollbarGadget&>(scrollbarGadget).renderStepper(graphicsContext.platformContext()->cr(), buttonRect, secondaryBackwardStepper, |
| scrollbar.orientation() == ScrollbarOrientation::Vertical ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL, RenderThemeScrollbarGadget::Steppers::SecondaryBackward); |
| if (scrollbar.orientation() == ScrollbarOrientation::Vertical) |
| contentsRect.contract(0, buttonRect.height()); |
| else |
| contentsRect.contract(buttonRect.width(), 0); |
| } |
| if (forwardStepper) { |
| FloatRect buttonRect = contentsRect; |
| if (scrollbar.orientation() == ScrollbarOrientation::Vertical) { |
| buttonRect.setHeight(forwardStepper->preferredSize().height()); |
| buttonRect.move(0, contentsRect.height() - buttonRect.height()); |
| } else { |
| buttonRect.setWidth(forwardStepper->preferredSize().width()); |
| buttonRect.move(contentsRect.width() - buttonRect.width(), 0); |
| } |
| static_cast<RenderThemeScrollbarGadget&>(scrollbarGadget).renderStepper(graphicsContext.platformContext()->cr(), buttonRect, forwardStepper, |
| scrollbar.orientation() == ScrollbarOrientation::Vertical ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL, RenderThemeScrollbarGadget::Steppers::Forward); |
| if (scrollbar.orientation() == ScrollbarOrientation::Vertical) |
| contentsRect.contract(0, buttonRect.height()); |
| else |
| contentsRect.contract(buttonRect.width(), 0); |
| } |
| |
| trough.render(graphicsContext.platformContext()->cr(), contentsRect, &contentsRect); |
| |
| if (thumbSize) { |
| if (scrollbar.orientation() == ScrollbarOrientation::Vertical) { |
| contentsRect.move(0, thumbPosition(scrollbar)); |
| contentsRect.setWidth(scrollbarWidget.slider().preferredSize().width()); |
| contentsRect.setHeight(thumbSize); |
| } else { |
| contentsRect.move(thumbPosition(scrollbar), 0); |
| contentsRect.setWidth(thumbSize); |
| contentsRect.setHeight(scrollbarWidget.slider().preferredSize().height()); |
| } |
| if (contentsRect.intersects(damageRect)) |
| scrollbarWidget.slider().render(graphicsContext.platformContext()->cr(), contentsRect); |
| } |
| |
| if (opacity != 1) { |
| graphicsContext.endTransparencyLayer(); |
| graphicsContext.restore(); |
| } |
| |
| return true; |
| } |
| |
| ScrollbarButtonPressAction ScrollbarThemeGtk::handleMousePressEvent(Scrollbar&, const PlatformMouseEvent& event, ScrollbarPart pressedPart) |
| { |
| gboolean warpSlider = FALSE; |
| switch (pressedPart) { |
| case BackTrackPart: |
| case ForwardTrackPart: |
| g_object_get(gtk_settings_get_default(), |
| "gtk-primary-button-warps-slider", |
| &warpSlider, nullptr); |
| // The shift key or middle/right button reverses the sense. |
| if (event.shiftKey() || event.button() != LeftButton) |
| warpSlider = !warpSlider; |
| return warpSlider ? |
| ScrollbarButtonPressAction::CenterOnThumb: |
| ScrollbarButtonPressAction::Scroll; |
| case ThumbPart: |
| if (event.button() != RightButton) |
| return ScrollbarButtonPressAction::StartDrag; |
| break; |
| case BackButtonStartPart: |
| case ForwardButtonStartPart: |
| case BackButtonEndPart: |
| case ForwardButtonEndPart: |
| return ScrollbarButtonPressAction::Scroll; |
| default: |
| break; |
| } |
| |
| return ScrollbarButtonPressAction::None; |
| } |
| |
| int ScrollbarThemeGtk::scrollbarThickness(ScrollbarControlSize controlSize, ScrollbarExpansionState expansionState) |
| { |
| if (!m_useSystemAppearance) |
| return ScrollbarThemeAdwaita::scrollbarThickness(controlSize, expansionState); |
| |
| auto& scrollbarWidget = static_cast<RenderThemeScrollbar&>(RenderThemeScrollbar::getOrCreate(RenderThemeScrollbar::Type::VerticalScrollbarRight)); |
| scrollbarWidget.scrollbar().setState(GTK_STATE_FLAG_PRELIGHT); |
| IntSize contentsPreferredSize = scrollbarWidget.contents().preferredSize(); |
| contentsPreferredSize = contentsPreferredSize.expandedTo(scrollbarWidget.slider().preferredSize()); |
| IntSize preferredSize = contentsPreferredSize + scrollbarWidget.scrollbar().preferredSize() - scrollbarWidget.scrollbar().minimumSize(); |
| return preferredSize.width(); |
| } |
| |
| int ScrollbarThemeGtk::minimumThumbLength(Scrollbar& scrollbar) |
| { |
| if (!m_useSystemAppearance) |
| return ScrollbarThemeAdwaita::minimumThumbLength(scrollbar); |
| |
| auto& scrollbarWidget = static_cast<RenderThemeScrollbar&>(RenderThemeScrollbar::getOrCreate(RenderThemeScrollbar::Type::VerticalScrollbarRight)); |
| scrollbarWidget.scrollbar().setState(GTK_STATE_FLAG_PRELIGHT); |
| IntSize minSize = scrollbarWidget.slider().minimumSize(); |
| return scrollbar.orientation() == ScrollbarOrientation::Vertical ? minSize.height() : minSize.width(); |
| } |
| |
| } // namespace WebCore |
| |
| #endif // !USE(GTK4) |