be4c1c401e619f7753a9ac5baa06eea9e892f198
[WebKit-https.git] / WebCore / platform / gtk / ScrollbarGtk.cpp
1 /*
2  *  Copyright (C) 2007 Holger Hans Peter Freyther zecke@selfish.org
3  *
4  *  This library is free software; you can redistribute it and/or
5  *  modify it under the terms of the GNU Lesser General Public
6  *  License as published by the Free Software Foundation; either
7  *  version 2 of the License, or (at your option) any later version.
8  *
9  *  This library is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  *  Lesser General Public License for more details.
13  *
14  *  You should have received a copy of the GNU Lesser General Public
15  *  License along with this library; if not, write to the Free Software
16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18
19 #include "config.h"
20 #include "ScrollbarGtk.h"
21
22 #include "IntRect.h"
23 #include "GraphicsContext.h"
24 #include "FrameView.h"
25 #include "NotImplemented.h"
26 #include "ScrollbarTheme.h"
27 #include "gtkdrawing.h"
28
29 #include <gtk/gtk.h>
30
31 using namespace WebCore;
32
33 PassRefPtr<Scrollbar> Scrollbar::createNativeScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, ScrollbarControlSize size)
34 {
35     return adoptRef(new ScrollbarGtk(client, orientation, size));
36 }
37
38 static gboolean gtkScrollEventCallback(GtkWidget* widget, GdkEventScroll* event, ScrollbarGtk*)
39 {
40     /* Scroll only if our parent rejects the scroll event. The rationale for
41      * this is that we want the main frame to scroll when we move the mouse
42      * wheel over a child scrollbar in most cases. */
43     return gtk_widget_event(gtk_widget_get_parent(widget), reinterpret_cast<GdkEvent*>(event));
44 }
45
46 ScrollbarGtk::ScrollbarGtk(ScrollbarClient* client, ScrollbarOrientation orientation,
47                            ScrollbarControlSize controlSize)
48     : Scrollbar(client, orientation, controlSize)
49     , m_adjustment(GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)))
50 {
51     GtkWidget* scrollBar = orientation == HorizontalScrollbar ?
52                            gtk_hscrollbar_new(m_adjustment):
53                            gtk_vscrollbar_new(m_adjustment);
54     gtk_widget_show(scrollBar);
55     g_signal_connect(scrollBar, "value-changed", G_CALLBACK(ScrollbarGtk::gtkValueChanged), this);
56     g_signal_connect(scrollBar, "scroll-event", G_CALLBACK(gtkScrollEventCallback), this);
57
58     setPlatformWidget(scrollBar);
59
60     /*
61      * assign a sane default width and height to the Scrollbar, otherwise
62      * we will end up with a 0 width scrollbar.
63      */
64     resize(ScrollbarTheme::nativeTheme()->scrollbarThickness(),
65            ScrollbarTheme::nativeTheme()->scrollbarThickness());
66 }
67
68 void ScrollbarGtk::frameRectsChanged()
69 {
70     if (!parent())
71         return;
72
73     // Translate our coordinates, we are a RenderLayout scrollbar because our
74     // ScrollView scrollbars are native.
75     IntPoint loc = parent()->contentsToWindow(frameRect().location());
76
77     // Don't allow the allocation size to be negative
78     IntSize sz = frameRect().size();
79     sz.clampNegativeToZero();
80
81     GtkAllocation allocation = { loc.x(), loc.y(), sz.width(), sz.height() };
82     gtk_widget_size_allocate(platformWidget(), &allocation);
83 }
84
85 void ScrollbarGtk::updateThumbPosition()
86 {
87     if (m_adjustment->value != m_currentPos) {
88         m_adjustment->value = m_currentPos;
89         gtk_adjustment_value_changed(m_adjustment);
90     }
91 }
92
93 void ScrollbarGtk::updateThumbProportion()
94 {
95     m_adjustment->step_increment = m_lineStep;
96     m_adjustment->page_increment = m_pageStep;
97     m_adjustment->page_size = m_visibleSize;
98     m_adjustment->upper = m_totalSize;
99     gtk_adjustment_changed(m_adjustment);
100 }
101
102 void ScrollbarGtk::setFrameRect(const IntRect& rect)
103 {
104     Widget::setFrameRect(rect);
105     frameRectsChanged();
106 }
107
108 void ScrollbarGtk::gtkValueChanged(GtkAdjustment*, ScrollbarGtk* that)
109 {
110     that->setValue(static_cast<int>(gtk_adjustment_get_value(that->m_adjustment)));
111 }
112
113 void ScrollbarGtk::setEnabled(bool shouldEnable)
114 {
115     if (enabled() == shouldEnable)
116         return;
117         
118     Scrollbar::setEnabled(shouldEnable);
119     if (platformWidget()) 
120         gtk_widget_set_sensitive(platformWidget(), shouldEnable);
121 }
122
123 /*
124  * Strategy to painting a Widget:
125  *  1.) do not paint if there is no GtkWidget set
126  *  2.) We assume that GTK_NO_WINDOW is set and that frameRectsChanged positioned
127  *      the widget correctly. ATM we do not honor the GraphicsContext translation.
128  */
129 void ScrollbarGtk::paint(GraphicsContext* context, const IntRect& rect)
130 {
131     if (!platformWidget())
132         return;
133
134     if (!context->gdkExposeEvent())
135         return;
136
137     GtkWidget* widget = platformWidget();
138     ASSERT(GTK_WIDGET_NO_WINDOW(widget));
139
140     GdkEvent* event = gdk_event_new(GDK_EXPOSE);
141     event->expose = *context->gdkExposeEvent();
142     event->expose.area = static_cast<GdkRectangle>(rect);
143
144     IntPoint loc = parent()->contentsToWindow(rect.location());
145     event->expose.area.x = loc.x();
146     event->expose.area.y = loc.y();
147
148     event->expose.region = gdk_region_rectangle(&event->expose.area);
149
150     /*
151      * This will be unref'ed by gdk_event_free.
152      */
153     g_object_ref(event->expose.window);
154
155     /*
156      * If we are going to paint do the translation and GtkAllocation manipulation.
157      */
158     if (!gdk_region_empty(event->expose.region))
159         gtk_widget_send_expose(widget, event);
160
161     gdk_event_free(event);
162 }