blob: 78161d97c688f30cecae5517927c3e4d354c4933 [file] [log] [blame]
/*
* 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)