Home | History | Annotate | Download | only in gtk
      1 /*
      2  * Copyright (C) 2008 Apple Inc. All Rights Reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "ScrollbarThemeGtk.h"
     28 
     29 #ifdef GTK_API_VERSION_2
     30 
     31 #include "GtkVersioning.h"
     32 #include "PlatformMouseEvent.h"
     33 #include "RenderThemeGtk.h"
     34 #include "ScrollView.h"
     35 #include "Scrollbar.h"
     36 #include "WidgetRenderingContext.h"
     37 #include <gtk/gtk.h>
     38 
     39 namespace WebCore {
     40 
     41 static void gtkStyleSetCallback(GtkWidget* widget, GtkStyle* previous, ScrollbarThemeGtk* scrollbarTheme)
     42 {
     43     scrollbarTheme->updateThemeProperties();
     44 }
     45 
     46 ScrollbarThemeGtk::ScrollbarThemeGtk()
     47 {
     48     updateThemeProperties();
     49     g_signal_connect(static_cast<RenderThemeGtk*>(RenderTheme::defaultTheme().get())->gtkHScrollbar(),
     50          "style-set", G_CALLBACK(gtkStyleSetCallback), this);
     51 }
     52 
     53 void ScrollbarThemeGtk::updateThemeProperties()
     54 {
     55     GtkWidget* scrollbar = static_cast<RenderThemeGtk*>(RenderTheme::defaultTheme().get())->gtkHScrollbar();
     56     gtk_widget_style_get(scrollbar,
     57                          "slider_width", &m_thumbFatness,
     58                          "trough_border", &m_troughBorderWidth,
     59                          "stepper-size", &m_stepperSize,
     60                          "trough-under-steppers", &m_troughUnderSteppers,
     61                          "has-secondary-forward-stepper", &m_hasForwardButtonStartPart,
     62                          "has-secondary-backward-stepper", &m_hasBackButtonEndPart, NULL);
     63     m_minThumbLength = gtk_range_get_min_slider_size(GTK_RANGE(scrollbar));
     64     updateScrollbarsFrameThickness();
     65 }
     66 
     67 static GtkWidget* getWidgetForScrollbar(Scrollbar* scrollbar)
     68 {
     69     RenderThemeGtk* theme = static_cast<RenderThemeGtk*>(RenderTheme::defaultTheme().get());
     70     return scrollbar->orientation() == VerticalScrollbar ? theme->gtkVScrollbar() : theme->gtkHScrollbar();
     71 }
     72 
     73 void ScrollbarThemeGtk::paintTrackBackground(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect)
     74 {
     75     // Paint the track background. If the trough-under-steppers property is true, this
     76     // should be the full size of the scrollbar, but if is false, it should only be the
     77     // track rect.
     78     IntRect fullScrollbarRect(rect);
     79     if (m_troughUnderSteppers)
     80         fullScrollbarRect = IntRect(scrollbar->x(), scrollbar->y(), scrollbar->width(), scrollbar->height());
     81 
     82     WidgetRenderingContext widgetContext(context, fullScrollbarRect);
     83     IntRect paintRect(IntPoint(), fullScrollbarRect.size());
     84     widgetContext.gtkPaintBox(paintRect, getWidgetForScrollbar(scrollbar),
     85                               GTK_STATE_ACTIVE, GTK_SHADOW_IN, "trough");
     86 }
     87 
     88 void ScrollbarThemeGtk::paintScrollbarBackground(GraphicsContext* context, Scrollbar* scrollbar)
     89 {
     90     IntRect fullScrollbarRect = IntRect(scrollbar->x(), scrollbar->y(), scrollbar->width(), scrollbar->height());
     91 
     92     WidgetRenderingContext widgetContext(context, fullScrollbarRect);
     93     widgetContext.gtkPaintBox(fullScrollbarRect, getWidgetForScrollbar(scrollbar),
     94                               GTK_STATE_NORMAL, GTK_SHADOW_IN, "scrolled_window");
     95 }
     96 
     97 void ScrollbarThemeGtk::paintThumb(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect)
     98 {
     99     GtkWidget* widget = getWidgetForScrollbar(scrollbar);
    100     gboolean activateSlider;
    101     gtk_widget_style_get(widget, "activate-slider", &activateSlider, NULL);
    102 
    103     GtkStateType stateType = GTK_STATE_NORMAL;
    104     GtkShadowType shadowType = GTK_SHADOW_OUT;
    105     if (activateSlider && scrollbar->pressedPart() == ThumbPart) {
    106         stateType = GTK_STATE_ACTIVE;
    107         shadowType = GTK_SHADOW_IN;
    108     } else if (scrollbar->pressedPart() == ThumbPart || scrollbar->hoveredPart() == ThumbPart)
    109         stateType = GTK_STATE_PRELIGHT;
    110 
    111     // The adjustment controls the rendering of the scrollbar thumb. If it's not set
    112     // properly the theme may not draw the thumb borders properly.
    113     GtkAdjustment* adjustment = gtk_range_get_adjustment(GTK_RANGE(widget));
    114     gtk_adjustment_set_value(adjustment, scrollbar->currentPos());
    115     gtk_adjustment_set_lower(adjustment, 0);
    116     gtk_adjustment_set_upper(adjustment, scrollbar->maximum());
    117 
    118     GtkOrientation orientation = GTK_ORIENTATION_HORIZONTAL;
    119     if (scrollbar->orientation() == VerticalScrollbar) {
    120         gtk_adjustment_set_page_size(adjustment, rect.height());
    121         orientation = GTK_ORIENTATION_VERTICAL;
    122     } else
    123         gtk_adjustment_set_page_size(adjustment, rect.width());
    124 
    125     WidgetRenderingContext widgetContext(context, rect);
    126     IntRect sliderRect(IntPoint(), rect.size());
    127     widgetContext.gtkPaintSlider(sliderRect, widget, stateType, shadowType, "slider", orientation);
    128 }
    129 
    130 void ScrollbarThemeGtk::paintButton(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect, ScrollbarPart part)
    131 {
    132     // The buttons will be disabled if the thumb is as the appropriate extreme.
    133     GtkShadowType shadowType = GTK_SHADOW_OUT;
    134     GtkStateType stateType = GTK_STATE_INSENSITIVE;
    135     bool pressed = (part == scrollbar->pressedPart());
    136 
    137     if ((BackButtonStartPart == part && scrollbar->currentPos())
    138         || (BackButtonEndPart == part && scrollbar->currentPos())
    139         || (ForwardButtonEndPart == part && scrollbar->currentPos() != scrollbar->maximum())
    140         || (ForwardButtonStartPart == part && scrollbar->currentPos() != scrollbar->maximum())) {
    141         stateType = GTK_STATE_NORMAL;
    142         if (pressed) {
    143             stateType = GTK_STATE_ACTIVE;
    144             shadowType = GTK_SHADOW_IN;
    145         } else if (part == scrollbar->hoveredPart())
    146             stateType = GTK_STATE_PRELIGHT;
    147     }
    148 
    149     // Themes determine how to draw the button (which button to draw) based on the allocation
    150     // of the widget. Where the target rect is in relation to the total widget allocation
    151     // determines the button.
    152     ScrollbarOrientation orientation = scrollbar->orientation();
    153     int buttonSize = (orientation == VerticalScrollbar) ? rect.height() : rect.width();
    154     int totalAllocation = buttonSize * 5; // One space for each button and one extra.
    155     int buttonOffset = 0;
    156     if (ForwardButtonStartPart == part)
    157         buttonOffset = buttonSize;
    158     else if (BackButtonEndPart == part)
    159         buttonOffset = 3 * buttonSize;
    160     else if (ForwardButtonEndPart == part)
    161         buttonOffset = 4 * buttonSize;
    162 
    163     // Now we want the allocation to be relative to the origin of the painted rect.
    164     GtkWidget* widget = getWidgetForScrollbar(scrollbar);
    165     GtkAllocation allocation;
    166     gtk_widget_get_allocation(widget, &allocation);
    167     allocation.x = allocation.y = 0;
    168     allocation.width = rect.width();
    169     allocation.height = rect.height();
    170 
    171     if (orientation == VerticalScrollbar) {
    172         allocation.height = totalAllocation;
    173         allocation.y -= buttonOffset;
    174     } else {
    175         allocation.width = totalAllocation;
    176         allocation.x -= buttonOffset;
    177     }
    178     gtk_widget_set_allocation(widget, &allocation);
    179 
    180     const char* detail = orientation == VerticalScrollbar ? "vscrollbar" : "hscrollbar";
    181     WidgetRenderingContext widgetContext(context, rect);
    182 
    183     IntRect buttonRect(IntPoint(), rect.size());
    184     widgetContext.gtkPaintBox(buttonRect, widget, stateType, shadowType, detail);
    185 
    186     float arrowScaling;
    187     gtk_widget_style_get(widget, "arrow-scaling", &arrowScaling, NULL);
    188     IntSize arrowSize = rect.size();
    189     arrowSize.scale(arrowScaling);
    190     IntRect arrowRect(IntPoint(buttonRect.x() + (buttonRect.width() - arrowSize.width()) / 2,
    191                                buttonRect.y() + (buttonRect.height() - arrowSize.height()) / 2),
    192                       arrowSize);
    193     if (pressed) {
    194         int arrowDisplacementX, arrowDisplacementY;
    195         gtk_widget_style_get(widget,
    196                              "arrow-displacement-x", &arrowDisplacementX,
    197                              "arrow-displacement-y", &arrowDisplacementY,
    198                              NULL);
    199         arrowRect.move(arrowDisplacementX, arrowDisplacementY);
    200     }
    201 
    202     GtkArrowType arrowType = GTK_ARROW_DOWN;
    203     if (orientation == VerticalScrollbar) {
    204         if (part == BackButtonEndPart || part == BackButtonStartPart)
    205             arrowType = GTK_ARROW_UP;
    206     } else if (orientation == HorizontalScrollbar) {
    207         arrowType = GTK_ARROW_RIGHT;
    208         if (part == BackButtonEndPart || part == BackButtonStartPart)
    209             arrowType = GTK_ARROW_LEFT;
    210     }
    211     widgetContext.gtkPaintArrow(arrowRect, widget, stateType, shadowType, arrowType, detail);
    212 }
    213 
    214 } // namespace WebCore
    215 
    216 #endif // GTK_API_VERSION_2
    217