bool RenderThemeGtk::paintSliderTrack(RenderObject* object, const PaintInfo& info, const IntRect& rect) { if (info.context->paintingDisabled()) return false; ControlPart part = object->style()->appearance(); ASSERT(part == SliderHorizontalPart || part == SliderVerticalPart); // We shrink the trough rect slightly to make room for the focus indicator. IntRect troughRect(IntPoint(), rect.size()); // This is relative to rect. GtkWidget* widget = 0; if (part == SliderVerticalPart) { widget = gtkVScale(); troughRect.inflateY(-gtk_widget_get_style(widget)->ythickness); } else { widget = gtkHScale(); troughRect.inflateX(-gtk_widget_get_style(widget)->xthickness); } gtk_widget_set_direction(widget, gtkTextDirection(object->style()->direction())); WidgetRenderingContext widgetContext(info.context, rect); widgetContext.gtkPaintBox(troughRect, widget, GTK_STATE_ACTIVE, GTK_SHADOW_OUT, "trough"); if (isFocused(object)) widgetContext.gtkPaintFocus(IntRect(IntPoint(), rect.size()), widget, getGtkStateType(object), "trough"); return false; }
bool RenderThemeGtk::paintSliderThumb(RenderObject* object, const PaintInfo& info, const IntRect& rect) { if (info.context->paintingDisabled()) return false; ControlPart part = object->style()->appearance(); ASSERT(part == SliderThumbHorizontalPart || part == SliderThumbVerticalPart); GtkWidget* widget = 0; const char* detail = 0; GtkOrientation orientation; if (part == SliderThumbVerticalPart) { widget = gtkVScale(); detail = "vscale"; orientation = GTK_ORIENTATION_VERTICAL; } else { widget = gtkHScale(); detail = "hscale"; orientation = GTK_ORIENTATION_HORIZONTAL; } gtk_widget_set_direction(widget, gtkTextDirection(object->style()->direction())); // Only some themes have slider thumbs respond to clicks and some don't. This information is // gathered via the 'activate-slider' property, but it's deprecated in GTK+ 2.22 and removed in // GTK+ 3.x. The drawback of not honoring it is that slider thumbs change color when you click // on them. IntRect thumbRect(IntPoint(), rect.size()); WidgetRenderingContext widgetContext(info.context, rect); widgetContext.gtkPaintSlider(thumbRect, widget, getGtkStateType(object), GTK_SHADOW_OUT, detail, orientation); return false; }
void ScrollbarThemeGtk::paintButton(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect, ScrollbarPart part) { int flags = 0; if (scrollbar->orientation() == VerticalScrollbar) flags |= MOZ_GTK_STEPPER_VERTICAL; if (part == ForwardButtonEndPart) flags |= (MOZ_GTK_STEPPER_DOWN | MOZ_GTK_STEPPER_BOTTOM); if (part == ForwardButtonStartPart) flags |= MOZ_GTK_STEPPER_DOWN; GtkWidgetState state; state.focused = TRUE; state.isDefault = TRUE; state.canDefault = TRUE; state.depressed = FALSE; if ((BackButtonStartPart == part && scrollbar->currentPos()) || (BackButtonEndPart == part && scrollbar->currentPos()) || (ForwardButtonEndPart == part && scrollbar->currentPos() != scrollbar->maximum()) || (ForwardButtonStartPart == part && scrollbar->currentPos() != scrollbar->maximum())) { state.disabled = FALSE; state.active = part == scrollbar->pressedPart(); state.inHover = part == scrollbar->hoveredPart(); } else { state.disabled = TRUE; state.active = FALSE; state.inHover = FALSE; } WidgetRenderingContext widgetContext(context, rect); widgetContext.paintMozillaWidget(MOZ_GTK_SCROLLBAR_BUTTON, &state, flags); }
bool RenderThemeGtk::paintRenderObject(GtkThemeWidgetType type, RenderObject* renderObject, GraphicsContext* context, const IntRect& rect, int flags) { // Painting is disabled so just claim to have succeeded if (context->paintingDisabled()) return false; GtkWidgetState widgetState; widgetState.active = isPressed(renderObject); widgetState.focused = isFocused(renderObject); // https://bugs.webkit.org/show_bug.cgi?id=18364 // The Mozilla theme drawing code, only paints a button as pressed when it's pressed // while hovered. Until we move away from the Mozila code, work-around the issue by // forcing a pressed button into the hovered state. This ensures that buttons activated // via the keyboard have the proper rendering. widgetState.inHover = isHovered(renderObject) || (type == MOZ_GTK_BUTTON && isPressed(renderObject)); // FIXME: Disabled does not always give the correct appearance for ReadOnly widgetState.disabled = !isEnabled(renderObject) || isReadOnlyControl(renderObject); widgetState.isDefault = false; widgetState.canDefault = false; widgetState.depressed = false; WidgetRenderingContext widgetContext(context, rect); return !widgetContext.paintMozillaWidget(type, &widgetState, flags, gtkTextDirection(renderObject->style()->direction())); }
void ScrollbarThemeGtk::paintThumb(GraphicsContext* context, ScrollbarThemeClient* scrollbar, const IntRect& rect) { GtkWidget* widget = getWidgetForScrollbar(scrollbar); gboolean activateSlider; gtk_widget_style_get(widget, "activate-slider", &activateSlider, NULL); GtkStateType stateType = GTK_STATE_NORMAL; GtkShadowType shadowType = GTK_SHADOW_OUT; if (activateSlider && scrollbar->pressedPart() == ThumbPart) { stateType = GTK_STATE_ACTIVE; shadowType = GTK_SHADOW_IN; } else if (scrollbar->pressedPart() == ThumbPart || scrollbar->hoveredPart() == ThumbPart) stateType = GTK_STATE_PRELIGHT; // The adjustment controls the rendering of the scrollbar thumb. If it's not set // properly the theme may not draw the thumb borders properly. GtkAdjustment* adjustment = gtk_range_get_adjustment(GTK_RANGE(widget)); gtk_adjustment_set_value(adjustment, scrollbar->currentPos()); gtk_adjustment_set_lower(adjustment, 0); gtk_adjustment_set_upper(adjustment, scrollbar->maximum()); GtkOrientation orientation = GTK_ORIENTATION_HORIZONTAL; if (scrollbar->orientation() == VerticalScrollbar) { gtk_adjustment_set_page_size(adjustment, rect.height()); orientation = GTK_ORIENTATION_VERTICAL; } else gtk_adjustment_set_page_size(adjustment, rect.width()); WidgetRenderingContext widgetContext(context, rect); IntRect sliderRect(IntPoint(), rect.size()); widgetContext.gtkPaintSlider(sliderRect, widget, stateType, shadowType, "slider", orientation); }
void ScrollbarThemeGtk::paintScrollbarBackground(GraphicsContext* context, Scrollbar* scrollbar) { // This is unused by the moz_gtk_scrollecd_window_paint. GtkWidgetState state; IntRect fullScrollbarRect = IntRect(scrollbar->x(), scrollbar->y(), scrollbar->width(), scrollbar->height()); WidgetRenderingContext widgetContext(context, fullScrollbarRect); widgetContext.paintMozillaWidget(MOZ_GTK_SCROLLED_WINDOW, &state, 0); }
void ScrollbarThemeGtk::paintScrollbarBackground(GraphicsContext* context, ScrollbarThemeClient* scrollbar) { IntRect fullScrollbarRect = IntRect(scrollbar->x(), scrollbar->y(), scrollbar->width(), scrollbar->height()); WidgetRenderingContext widgetContext(context, fullScrollbarRect); widgetContext.gtkPaintBox(fullScrollbarRect, getWidgetForScrollbar(scrollbar), GTK_STATE_NORMAL, GTK_SHADOW_IN, "scrolled_window"); }
bool RenderThemeGtk::paintMenuList(RenderObject* object, const PaintInfo& info, const IntRect& rect) { if (paintButton(object, info, rect)) return true; // Menu list button painting strategy. // For buttons with appears-as-list set to false (having a separator): // | left border | Button text | xthickness | vseparator | xthickness | arrow | xthickness | right border | // For buttons with appears-as-list set to true (not having a separator): // | left border | Button text | arrow | xthickness | right border | int leftBorder = 0, rightBorder = 0, bottomBorder = 0, topBorder = 0; getButtonInnerBorder(gtkComboBoxButton(), leftBorder, topBorder, rightBorder, bottomBorder); RenderStyle* style = &object->style(); int arrowSize = comboBoxArrowSize(style); GtkStyle* buttonStyle = gtk_widget_get_style(gtkComboBoxButton()); IntRect arrowRect(0, (rect.height() - arrowSize) / 2, arrowSize, arrowSize); if (style->direction() == RTL) arrowRect.setX(leftBorder + buttonStyle->xthickness); else arrowRect.setX(rect.width() - rightBorder - buttonStyle->xthickness - arrowSize); GtkShadowType shadowType = isPressed(object) ? GTK_SHADOW_IN : GTK_SHADOW_OUT; WidgetRenderingContext widgetContext(info.context, rect); GtkStateType stateType = getGtkStateType(this, object); widgetContext.gtkPaintArrow(arrowRect, gtkComboBoxArrow(), stateType, shadowType, GTK_ARROW_DOWN, "arrow"); // Some combo boxes do not have a separator. GtkWidget* separator = gtkComboBoxSeparator(); if (!separator) return false; // We want to decrease the height of the separator based on the focus padding of the button. gint focusPadding = 0, focusWidth = 0; gtk_widget_style_get(gtkComboBoxButton(), "focus-line-width", &focusWidth, "focus-padding", &focusPadding, NULL); topBorder += focusPadding + focusWidth; bottomBorder += focusPadding + focusWidth; int separatorWidth = getComboBoxSeparatorWidth(); IntRect separatorRect(0, topBorder, separatorWidth, rect.height() - topBorder - bottomBorder); if (style->direction() == RTL) separatorRect.setX(arrowRect.x() + arrowRect.width() + buttonStyle->xthickness + separatorWidth); else separatorRect.setX(arrowRect.x() - buttonStyle->xthickness - separatorWidth); gboolean hasWideSeparators = FALSE; gtk_widget_style_get(separator, "wide-separators", &hasWideSeparators, NULL); if (hasWideSeparators) widgetContext.gtkPaintBox(separatorRect, separator, GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_OUT, "vseparator"); else widgetContext.gtkPaintVLine(separatorRect, separator, GTK_STATE_NORMAL, "vseparator"); return false; }
bool RenderThemeGtk::paintButton(RenderObject* object, const PaintInfo& info, const IntRect& rect) { if (info.context->paintingDisabled()) return false; GtkWidget* widget = gtkButton(); IntRect buttonRect(IntPoint(), rect.size()); IntRect focusRect(buttonRect); GtkStateType state = getGtkStateType(object); gtk_widget_set_state(widget, state); gtk_widget_set_direction(widget, gtkTextDirection(object->style()->direction())); if (isFocused(object)) { if (isEnabled(object)) { #if !GTK_CHECK_VERSION(2, 22, 0) GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS); #endif g_object_set(widget, "has-focus", TRUE, NULL); } gboolean interiorFocus = 0, focusWidth = 0, focusPadding = 0; gtk_widget_style_get(widget, "interior-focus", &interiorFocus, "focus-line-width", &focusWidth, "focus-padding", &focusPadding, NULL); // If we are using exterior focus, we shrink the button rect down before // drawing. If we are using interior focus we shrink the focus rect. This // approach originates from the Mozilla theme drawing code (gtk2drawing.c). if (interiorFocus) { GtkStyle* style = gtk_widget_get_style(widget); focusRect.inflateX(-style->xthickness - focusPadding); focusRect.inflateY(-style->ythickness - focusPadding); } else { buttonRect.inflateX(-focusWidth - focusPadding); buttonRect.inflateY(-focusPadding - focusPadding); } } WidgetRenderingContext widgetContext(info.context, rect); GtkShadowType shadowType = state == GTK_STATE_ACTIVE ? GTK_SHADOW_IN : GTK_SHADOW_OUT; widgetContext.gtkPaintBox(buttonRect, widget, state, shadowType, "button"); if (isFocused(object)) widgetContext.gtkPaintFocus(focusRect, widget, state, "button"); #if !GTK_CHECK_VERSION(2, 22, 0) GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS); #endif g_object_set(widget, "has-focus", FALSE, NULL); return false; }
void ScrollbarThemeGtk::paintTrackBackground(GraphicsContext* context, ScrollbarThemeClient* scrollbar, const IntRect& rect) { // Paint the track background. If the trough-under-steppers property is true, this // should be the full size of the scrollbar, but if is false, it should only be the // track rect. IntRect fullScrollbarRect(rect); if (m_troughUnderSteppers) fullScrollbarRect = IntRect(scrollbar->x(), scrollbar->y(), scrollbar->width(), scrollbar->height()); WidgetRenderingContext widgetContext(context, fullScrollbarRect); IntRect paintRect(IntPoint(), fullScrollbarRect.size()); widgetContext.gtkPaintBox(paintRect, getWidgetForScrollbar(scrollbar), GTK_STATE_ACTIVE, GTK_SHADOW_IN, "trough"); }
void ScrollbarThemeGtk::paintThumb(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect) { GtkWidgetState state; state.focused = FALSE; state.isDefault = FALSE; state.canDefault = FALSE; state.disabled = FALSE; state.active = scrollbar->pressedPart() == ThumbPart; state.inHover = scrollbar->hoveredPart() == ThumbPart; state.maxpos = scrollbar->maximum(); state.curpos = scrollbar->currentPos(); GtkThemeWidgetType type = scrollbar->orientation() == VerticalScrollbar ? MOZ_GTK_SCROLLBAR_THUMB_VERTICAL : MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL; WidgetRenderingContext widgetContext(context, rect); widgetContext.paintMozillaWidget(type, &state, 0); }
bool RenderThemeGtk::paintTextField(RenderObject* renderObject, const PaintInfo& info, const IntRect& rect) { GtkWidget* widget = gtkEntry(); bool enabled = isEnabled(renderObject) && !isReadOnlyControl(renderObject); GtkStateType backgroundState = enabled ? GTK_STATE_NORMAL : GTK_STATE_INSENSITIVE; gtk_widget_set_sensitive(widget, enabled); gtk_widget_set_direction(widget, gtkTextDirection(renderObject->style().direction())); setWidgetHasFocus(widget, isFocused(renderObject)); WidgetRenderingContext widgetContext(info.context, rect); IntRect textFieldRect(IntPoint(), rect.size()); // The entry background is only painted over the interior part of the GTK+ entry, not // the entire frame. This happens in the Mozilla theme drawing code as well. IntRect interiorRect(textFieldRect); GtkStyle* style = gtk_widget_get_style(widget); interiorRect.inflateX(-style->xthickness); interiorRect.inflateY(-style->ythickness); widgetContext.gtkPaintFlatBox(interiorRect, widget, backgroundState, GTK_SHADOW_NONE, "entry_bg"); // This is responsible for drawing the actual frame. widgetContext.gtkPaintShadow(textFieldRect, widget, GTK_STATE_NORMAL, GTK_SHADOW_IN, "entry"); gboolean interiorFocus; gint focusWidth; gtk_widget_style_get(widget, "interior-focus", &interiorFocus, "focus-line-width", &focusWidth, NULL); if (isFocused(renderObject) && !interiorFocus) { // When GTK+ paints a text entry with focus, it shrinks the size of the frame area by the // focus width and paints over the previously unfocused text entry. We need to emulate that // by drawing both the unfocused frame above and the focused frame here. IntRect shadowRect(textFieldRect); shadowRect.inflate(-focusWidth); widgetContext.gtkPaintShadow(shadowRect, widget, GTK_STATE_NORMAL, GTK_SHADOW_IN, "entry"); widgetContext.gtkPaintFocus(textFieldRect, widget, GTK_STATE_NORMAL, "entry"); } return false; }
bool RenderThemeGtk::paintProgressBar(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect) { GtkWidget* widget = gtkProgressBar(); gtk_widget_set_direction(widget, gtkTextDirection(renderObject->style().direction())); WidgetRenderingContext widgetContext(paintInfo.context, rect); IntRect fullProgressBarRect(IntPoint(), rect.size()); widgetContext.gtkPaintBox(fullProgressBarRect, widget, GTK_STATE_NORMAL, GTK_SHADOW_IN, "trough"); GtkStyle* style = gtk_widget_get_style(widget); IntRect progressRect(fullProgressBarRect); progressRect.inflateX(-style->xthickness); progressRect.inflateY(-style->ythickness); progressRect = RenderThemeGtk::calculateProgressRect(renderObject, progressRect); if (!progressRect.isEmpty()) widgetContext.gtkPaintBox(progressRect, widget, GTK_STATE_PRELIGHT, GTK_SHADOW_OUT, "bar"); return false; }
void ScrollbarThemeGtk::paintTrackBackground(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect) { GtkWidgetState state; state.focused = FALSE; state.isDefault = FALSE; state.canDefault = FALSE; state.disabled = FALSE; state.active = FALSE; state.inHover = FALSE; // Paint the track background. If the trough-under-steppers property is true, this // should be the full size of the scrollbar, but if is false, it should only be the // track rect. IntRect fullScrollbarRect = rect; if (m_troughUnderSteppers) fullScrollbarRect = IntRect(scrollbar->x(), scrollbar->y(), scrollbar->width(), scrollbar->height()); GtkThemeWidgetType type = scrollbar->orientation() == VerticalScrollbar ? MOZ_GTK_SCROLLBAR_TRACK_VERTICAL : MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL; WidgetRenderingContext widgetContext(context, fullScrollbarRect); widgetContext.paintMozillaWidget(type, &state, 0); }
static void paintToggle(RenderThemeGtk* theme, RenderObject* renderObject, const PaintInfo& info, const IntRect& rect, GtkWidget* widget) { // We do not call gtk_toggle_button_set_active here, because some themes begin a series of // animation frames in a "toggled" signal handler. This puts some checkboxes in a half-way // checked state. Every GTK+ theme I tested merely looks at the shadow type (and not the // 'active' property) to determine whether or not to draw the check. gtk_widget_set_sensitive(widget, theme->isEnabled(renderObject) && !theme->isReadOnlyControl(renderObject)); gtk_widget_set_direction(widget, gtkTextDirection(renderObject->style().direction())); bool indeterminate = theme->isIndeterminate(renderObject); gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(widget), indeterminate); GtkShadowType shadowType = GTK_SHADOW_OUT; if (indeterminate) // This originates from the Mozilla code. shadowType = GTK_SHADOW_ETCHED_IN; else if (theme->isChecked(renderObject)) shadowType = GTK_SHADOW_IN; WidgetRenderingContext widgetContext(info.context, rect); IntRect buttonRect(IntPoint(), rect.size()); GtkStateType toggleState = getGtkStateType(theme, renderObject); const char* detail = 0; if (GTK_IS_RADIO_BUTTON(widget)) { detail = "radiobutton"; widgetContext.gtkPaintOption(buttonRect, widget, toggleState, shadowType, detail); } else { detail = "checkbutton"; widgetContext.gtkPaintCheck(buttonRect, widget, toggleState, shadowType, detail); } if (theme->isFocused(renderObject)) { IntRect focusRect(buttonRect); adjustRectForFocus(widget, focusRect, true); widgetContext.gtkPaintFocus(focusRect, widget, toggleState, detail); } }
void ScrollbarThemeGtk::paintButton(GraphicsContext* context, ScrollbarThemeClient* scrollbar, const IntRect& rect, ScrollbarPart part) { // The buttons will be disabled if the thumb is as the appropriate extreme. GtkShadowType shadowType = GTK_SHADOW_OUT; GtkStateType stateType = GTK_STATE_INSENSITIVE; bool pressed = (part == scrollbar->pressedPart()); if ((BackButtonStartPart == part && scrollbar->currentPos()) || (BackButtonEndPart == part && scrollbar->currentPos()) || (ForwardButtonEndPart == part && scrollbar->currentPos() != scrollbar->maximum()) || (ForwardButtonStartPart == part && scrollbar->currentPos() != scrollbar->maximum())) { stateType = GTK_STATE_NORMAL; if (pressed) { stateType = GTK_STATE_ACTIVE; shadowType = GTK_SHADOW_IN; } else if (part == scrollbar->hoveredPart()) stateType = GTK_STATE_PRELIGHT; } // Themes determine how to draw the button (which button to draw) based on the allocation // of the widget. Where the target rect is in relation to the total widget allocation // determines the button. ScrollbarOrientation orientation = scrollbar->orientation(); int buttonSize = (orientation == VerticalScrollbar) ? rect.height() : rect.width(); int totalAllocation = buttonSize * 5; // One space for each button and one extra. int buttonOffset = 0; if (ForwardButtonStartPart == part) buttonOffset = buttonSize; else if (BackButtonEndPart == part) buttonOffset = 3 * buttonSize; else if (ForwardButtonEndPart == part) buttonOffset = 4 * buttonSize; // Now we want the allocation to be relative to the origin of the painted rect. GtkWidget* widget = getWidgetForScrollbar(scrollbar); GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); allocation.x = allocation.y = 0; allocation.width = rect.width(); allocation.height = rect.height(); if (orientation == VerticalScrollbar) { allocation.height = totalAllocation; allocation.y -= buttonOffset; } else { allocation.width = totalAllocation; allocation.x -= buttonOffset; } gtk_widget_set_allocation(widget, &allocation); const char* detail = orientation == VerticalScrollbar ? "vscrollbar" : "hscrollbar"; WidgetRenderingContext widgetContext(context, rect); IntRect buttonRect(IntPoint(), rect.size()); widgetContext.gtkPaintBox(buttonRect, widget, stateType, shadowType, detail); float arrowScaling; gtk_widget_style_get(widget, "arrow-scaling", &arrowScaling, NULL); IntSize arrowSize = rect.size(); arrowSize.scale(arrowScaling); IntRect arrowRect(IntPoint(buttonRect.x() + (buttonRect.width() - arrowSize.width()) / 2, buttonRect.y() + (buttonRect.height() - arrowSize.height()) / 2), arrowSize); if (pressed) { int arrowDisplacementX, arrowDisplacementY; gtk_widget_style_get(widget, "arrow-displacement-x", &arrowDisplacementX, "arrow-displacement-y", &arrowDisplacementY, NULL); arrowRect.move(arrowDisplacementX, arrowDisplacementY); } GtkArrowType arrowType = GTK_ARROW_DOWN; if (orientation == VerticalScrollbar) { if (part == BackButtonEndPart || part == BackButtonStartPart) arrowType = GTK_ARROW_UP; } else if (orientation == HorizontalScrollbar) { arrowType = GTK_ARROW_RIGHT; if (part == BackButtonEndPart || part == BackButtonStartPart) arrowType = GTK_ARROW_LEFT; } widgetContext.gtkPaintArrow(arrowRect, widget, stateType, shadowType, arrowType, detail); }
bool RenderThemeGtk::paintInnerSpinButton(RenderObject* renderObject, const PaintInfo& paintInfo, const IntRect& rect) { // We expand the painted area by 2 pixels on the top and bottom and 2 pixels on the right. This // is because GTK+ themes want to draw over the text box borders, but WebCore renders the inner // spin button inside the text box. IntRect expandedRect(rect); expandedRect.inflateY(2); expandedRect.setWidth(rect.width() + 2); WidgetRenderingContext widgetContext(paintInfo.context, expandedRect); GtkWidget* widget = gtkSpinButton(); gtk_widget_set_direction(widget, gtkTextDirection(renderObject->style().direction())); IntRect fullSpinButtonRect(IntPoint(), expandedRect.size()); widgetContext.gtkPaintBox(fullSpinButtonRect, widget, GTK_STATE_NORMAL, GTK_SHADOW_IN, "spinbutton"); bool upPressed = isSpinUpButtonPartPressed(renderObject); bool upHovered = isSpinUpButtonPartHovered(renderObject); bool controlActive = isEnabled(renderObject) && !isReadOnlyControl(renderObject); GtkShadowType shadowType = upPressed ? GTK_SHADOW_IN : GTK_SHADOW_OUT; GtkStateType stateType = GTK_STATE_INSENSITIVE; if (controlActive) { if (isPressed(renderObject) && upPressed) stateType = GTK_STATE_ACTIVE; else if (isHovered(renderObject) && upHovered) stateType = GTK_STATE_PRELIGHT; else stateType = GTK_STATE_NORMAL; } IntRect topRect(IntPoint(), expandedRect.size()); topRect.setHeight(expandedRect.height() / 2); widgetContext.gtkPaintBox(topRect, widget, stateType, shadowType, "spinbutton_up"); // The arrow size/position calculation here is based on the arbitrary gymnastics that happen // in gtkspinbutton.c. It isn't pretty there and it isn't pretty here. This manages to make // the button look native for many themes though. IntRect arrowRect; int arrowSize = (expandedRect.width() - 3) / 2; arrowSize -= (arrowSize % 2) - 1; // Force odd. arrowRect.setWidth(arrowSize); arrowRect.setHeight(arrowSize); arrowRect.move((expandedRect.width() - arrowRect.width()) / 2, (topRect.height() - arrowRect.height()) / 2 + 1); widgetContext.gtkPaintArrow(arrowRect, widget, stateType, shadowType, GTK_ARROW_UP, "spinbutton"); shadowType = isPressed(renderObject) && !upPressed ? GTK_SHADOW_IN : GTK_SHADOW_OUT; if (controlActive) { if (isPressed(renderObject) && !upPressed) stateType = GTK_STATE_ACTIVE; else if (isHovered(renderObject) && !upHovered) stateType = GTK_STATE_PRELIGHT; else stateType = GTK_STATE_NORMAL; } IntRect bottomRect(IntPoint(0, expandedRect.height() / 2), expandedRect.size()); bottomRect.setHeight(expandedRect.height() - bottomRect.y()); widgetContext.gtkPaintBox(bottomRect, widget, stateType, shadowType, "spinbutton_down"); arrowRect.setY(arrowRect.y() + bottomRect.y() - 1); widgetContext.gtkPaintArrow(arrowRect, widget, stateType, shadowType, GTK_ARROW_DOWN, "spinbutton"); return false; }