1 /* gtkscrollable.c
2  * Copyright (C) 2008 Tadej Borovšak <tadeboro@gmail.com>
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, see <http://www.gnu.org/licenses/>.
16  */
17 
18 /**
19  * SECTION:gtkscrollable
20  * @Short_Description: An interface for scrollable widgets
21  * @Title: GtkScrollable
22  *
23  * #GtkScrollable is an interface that is implemented by widgets with native
24  * scrolling ability.
25  *
26  * To implement this interface you should override the
27  * #GtkScrollable:hadjustment and #GtkScrollable:vadjustment properties.
28  *
29  * ## Creating a scrollable widget
30  *
31  * All scrollable widgets should do the following.
32  *
33  * - When a parent widget sets the scrollable child widget’s adjustments,
34  *   the widget should populate the adjustments’
35  *   #GtkAdjustment:lower, #GtkAdjustment:upper,
36  *   #GtkAdjustment:step-increment, #GtkAdjustment:page-increment and
37  *   #GtkAdjustment:page-size properties and connect to the
38  *   #GtkAdjustment::value-changed signal.
39  *
40  * - Because its preferred size is the size for a fully expanded widget,
41  *   the scrollable widget must be able to cope with underallocations.
42  *   This means that it must accept any value passed to its
43  *   #GtkWidgetClass.size_allocate() function.
44  *
45  * - When the parent allocates space to the scrollable child widget,
46  *   the widget should update the adjustments’ properties with new values.
47  *
48  * - When any of the adjustments emits the #GtkAdjustment::value-changed signal,
49  *   the scrollable widget should scroll its contents.
50  */
51 
52 #include "config.h"
53 
54 #include "gtkscrollable.h"
55 
56 #include "gtkadjustment.h"
57 #include "gtkprivate.h"
58 #include "gtktypebuiltins.h"
59 #include "gtkintl.h"
60 
G_DEFINE_INTERFACE(GtkScrollable,gtk_scrollable,G_TYPE_OBJECT)61 G_DEFINE_INTERFACE (GtkScrollable, gtk_scrollable, G_TYPE_OBJECT)
62 
63 static void
64 gtk_scrollable_default_init (GtkScrollableInterface *iface)
65 {
66   GParamSpec *pspec;
67 
68   /**
69    * GtkScrollable:hadjustment:
70    *
71    * Horizontal #GtkAdjustment of the scrollable widget. This adjustment is
72    * shared between the scrollable widget and its parent.
73    *
74    * Since: 3.0
75    */
76   pspec = g_param_spec_object ("hadjustment",
77                                P_("Horizontal adjustment"),
78                                P_("Horizontal adjustment that is shared "
79                                   "between the scrollable widget and its "
80                                   "controller"),
81                                GTK_TYPE_ADJUSTMENT,
82                                GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT);
83   g_object_interface_install_property (iface, pspec);
84 
85   /**
86    * GtkScrollable:vadjustment:
87    *
88    * Verical #GtkAdjustment of the scrollable widget. This adjustment is shared
89    * between the scrollable widget and its parent.
90    *
91    * Since: 3.0
92    */
93   pspec = g_param_spec_object ("vadjustment",
94                                P_("Vertical adjustment"),
95                                P_("Vertical adjustment that is shared "
96                                   "between the scrollable widget and its "
97                                   "controller"),
98                                GTK_TYPE_ADJUSTMENT,
99                                GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT);
100   g_object_interface_install_property (iface, pspec);
101 
102   /**
103    * GtkScrollable:hscroll-policy:
104    *
105    * Determines whether horizontal scrolling should start once the scrollable
106    * widget is allocated less than its minimum width or less than its natural width.
107    *
108    * Since: 3.0
109    */
110   pspec = g_param_spec_enum ("hscroll-policy",
111 			     P_("Horizontal Scrollable Policy"),
112 			     P_("How the size of the content should be determined"),
113 			     GTK_TYPE_SCROLLABLE_POLICY,
114 			     GTK_SCROLL_MINIMUM,
115 			     GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
116   g_object_interface_install_property (iface, pspec);
117 
118   /**
119    * GtkScrollable:vscroll-policy:
120    *
121    * Determines whether vertical scrolling should start once the scrollable
122    * widget is allocated less than its minimum height or less than its natural height.
123    *
124    * Since: 3.0
125    */
126   pspec = g_param_spec_enum ("vscroll-policy",
127 			     P_("Vertical Scrollable Policy"),
128 			     P_("How the size of the content should be determined"),
129 			     GTK_TYPE_SCROLLABLE_POLICY,
130 			     GTK_SCROLL_MINIMUM,
131 			     GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
132   g_object_interface_install_property (iface, pspec);
133 }
134 
135 /**
136  * gtk_scrollable_get_hadjustment:
137  * @scrollable: a #GtkScrollable
138  *
139  * Retrieves the #GtkAdjustment used for horizontal scrolling.
140  *
141  * Returns: (transfer none): horizontal #GtkAdjustment.
142  *
143  * Since: 3.0
144  **/
145 GtkAdjustment *
gtk_scrollable_get_hadjustment(GtkScrollable * scrollable)146 gtk_scrollable_get_hadjustment (GtkScrollable *scrollable)
147 {
148   GtkAdjustment *adj = NULL;
149 
150   g_return_val_if_fail (GTK_IS_SCROLLABLE (scrollable), NULL);
151 
152   g_object_get (scrollable, "hadjustment", &adj, NULL);
153 
154   /* Horrid hack; g_object_get() returns a new reference but
155    * that contradicts the memory management conventions
156    * for accessors.
157    */
158   if (adj)
159     g_object_unref (adj);
160 
161   return adj;
162 }
163 
164 /**
165  * gtk_scrollable_set_hadjustment:
166  * @scrollable: a #GtkScrollable
167  * @hadjustment: (allow-none): a #GtkAdjustment
168  *
169  * Sets the horizontal adjustment of the #GtkScrollable.
170  *
171  * Since: 3.0
172  **/
173 void
gtk_scrollable_set_hadjustment(GtkScrollable * scrollable,GtkAdjustment * hadjustment)174 gtk_scrollable_set_hadjustment (GtkScrollable *scrollable,
175                                 GtkAdjustment *hadjustment)
176 {
177   g_return_if_fail (GTK_IS_SCROLLABLE (scrollable));
178   g_return_if_fail (hadjustment == NULL || GTK_IS_ADJUSTMENT (hadjustment));
179 
180   g_object_set (scrollable, "hadjustment", hadjustment, NULL);
181 }
182 
183 /**
184  * gtk_scrollable_get_vadjustment:
185  * @scrollable: a #GtkScrollable
186  *
187  * Retrieves the #GtkAdjustment used for vertical scrolling.
188  *
189  * Returns: (transfer none): vertical #GtkAdjustment.
190  *
191  * Since: 3.0
192  **/
193 GtkAdjustment *
gtk_scrollable_get_vadjustment(GtkScrollable * scrollable)194 gtk_scrollable_get_vadjustment (GtkScrollable *scrollable)
195 {
196   GtkAdjustment *adj = NULL;
197 
198   g_return_val_if_fail (GTK_IS_SCROLLABLE (scrollable), NULL);
199 
200   g_object_get (scrollable, "vadjustment", &adj, NULL);
201 
202   /* Horrid hack; g_object_get() returns a new reference but
203    * that contradicts the memory management conventions
204    * for accessors.
205    */
206   if (adj)
207     g_object_unref (adj);
208 
209   return adj;
210 }
211 
212 /**
213  * gtk_scrollable_set_vadjustment:
214  * @scrollable: a #GtkScrollable
215  * @vadjustment: (allow-none): a #GtkAdjustment
216  *
217  * Sets the vertical adjustment of the #GtkScrollable.
218  *
219  * Since: 3.0
220  **/
221 void
gtk_scrollable_set_vadjustment(GtkScrollable * scrollable,GtkAdjustment * vadjustment)222 gtk_scrollable_set_vadjustment (GtkScrollable *scrollable,
223                                 GtkAdjustment *vadjustment)
224 {
225   g_return_if_fail (GTK_IS_SCROLLABLE (scrollable));
226   g_return_if_fail (vadjustment == NULL || GTK_IS_ADJUSTMENT (vadjustment));
227 
228   g_object_set (scrollable, "vadjustment", vadjustment, NULL);
229 }
230 
231 
232 /**
233  * gtk_scrollable_get_hscroll_policy:
234  * @scrollable: a #GtkScrollable
235  *
236  * Gets the horizontal #GtkScrollablePolicy.
237  *
238  * Returns: The horizontal #GtkScrollablePolicy.
239  *
240  * Since: 3.0
241  **/
242 GtkScrollablePolicy
gtk_scrollable_get_hscroll_policy(GtkScrollable * scrollable)243 gtk_scrollable_get_hscroll_policy (GtkScrollable *scrollable)
244 {
245   GtkScrollablePolicy policy;
246 
247   g_return_val_if_fail (GTK_IS_SCROLLABLE (scrollable), GTK_SCROLL_MINIMUM);
248 
249   g_object_get (scrollable, "hscroll-policy", &policy, NULL);
250 
251   return policy;
252 }
253 
254 /**
255  * gtk_scrollable_set_hscroll_policy:
256  * @scrollable: a #GtkScrollable
257  * @policy: the horizontal #GtkScrollablePolicy
258  *
259  * Sets the #GtkScrollablePolicy to determine whether
260  * horizontal scrolling should start below the minimum width or
261  * below the natural width.
262  *
263  * Since: 3.0
264  **/
265 void
gtk_scrollable_set_hscroll_policy(GtkScrollable * scrollable,GtkScrollablePolicy policy)266 gtk_scrollable_set_hscroll_policy (GtkScrollable       *scrollable,
267 				   GtkScrollablePolicy  policy)
268 {
269   g_return_if_fail (GTK_IS_SCROLLABLE (scrollable));
270 
271   g_object_set (scrollable, "hscroll-policy", policy, NULL);
272 }
273 
274 /**
275  * gtk_scrollable_get_vscroll_policy:
276  * @scrollable: a #GtkScrollable
277  *
278  * Gets the vertical #GtkScrollablePolicy.
279  *
280  * Returns: The vertical #GtkScrollablePolicy.
281  *
282  * Since: 3.0
283  **/
284 GtkScrollablePolicy
gtk_scrollable_get_vscroll_policy(GtkScrollable * scrollable)285 gtk_scrollable_get_vscroll_policy (GtkScrollable *scrollable)
286 {
287   GtkScrollablePolicy policy;
288 
289   g_return_val_if_fail (GTK_IS_SCROLLABLE (scrollable), GTK_SCROLL_MINIMUM);
290 
291   g_object_get (scrollable, "vscroll-policy", &policy, NULL);
292 
293   return policy;
294 }
295 
296 /**
297  * gtk_scrollable_set_vscroll_policy:
298  * @scrollable: a #GtkScrollable
299  * @policy: the vertical #GtkScrollablePolicy
300  *
301  * Sets the #GtkScrollablePolicy to determine whether
302  * vertical scrolling should start below the minimum height or
303  * below the natural height.
304  *
305  * Since: 3.0
306  **/
307 void
gtk_scrollable_set_vscroll_policy(GtkScrollable * scrollable,GtkScrollablePolicy policy)308 gtk_scrollable_set_vscroll_policy (GtkScrollable       *scrollable,
309 				   GtkScrollablePolicy  policy)
310 {
311   g_return_if_fail (GTK_IS_SCROLLABLE (scrollable));
312 
313   g_object_set (scrollable, "vscroll-policy", policy, NULL);
314 }
315 
316 /**
317  * gtk_scrollable_get_border:
318  * @scrollable: a #GtkScrollable
319  * @border: (out caller-allocates): return location for the results
320  *
321  * Returns the size of a non-scrolling border around the
322  * outside of the scrollable. An example for this would
323  * be treeview headers. GTK+ can use this information to
324  * display overlayed graphics, like the overshoot indication,
325  * at the right position.
326  *
327  * Returns: %TRUE if @border has been set
328  *
329  * Since: 3.16
330  */
331 gboolean
gtk_scrollable_get_border(GtkScrollable * scrollable,GtkBorder * border)332 gtk_scrollable_get_border (GtkScrollable *scrollable,
333                            GtkBorder     *border)
334 {
335   g_return_val_if_fail (GTK_IS_SCROLLABLE (scrollable), FALSE);
336   g_return_val_if_fail (border != NULL, FALSE);
337 
338   if (GTK_SCROLLABLE_GET_IFACE (scrollable)->get_border)
339     return GTK_SCROLLABLE_GET_IFACE (scrollable)->get_border (scrollable, border);
340 
341   return FALSE;
342 }
343