1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library 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 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 */
19
20 /*
21 * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
25 */
26
27 #ifdef HAVE_CONFIG_H
28 # include <config.h>
29 #endif
30
31 #include <gtk/gtkhscrollbar.h>
32 #include <gtk/gtkvscrollbar.h>
33 #include <gtk/gtksignal.h>
34 #include <gtk/gtkviewport.h>
35 #include "gtkscrollframe.h"
36
37
38 /* scrolled window policy and size requisition handling:
39 *
40 * gtk size requisition works as follows:
41 * a widget upon size-request reports the width and height that it finds
42 * to be best suited to display its contents, including children.
43 * the width and/or height reported from a widget upon size requisition
44 * may be overidden by the user by specifying a width and/or height
45 * other than 0 through gtk_widget_set_usize().
46 *
47 * a scrolled window needs (for imlementing all three policy types) to
48 * request its width and height based on two different rationales.
49 * 1) the user wants the scrolled window to just fit into the space
50 * that it gets allocated for a specifc dimension.
51 * 1.1) this does not apply if the user specified a concrete value
52 * value for that specific dimension by either specifying usize for the
53 * scrolled window or for its child.
54 * 2) the user wants the scrolled window to take as much space up as
55 * is desired by the child for a specifc dimension (i.e. POLICY_NEVER).
56 *
57 * also, kinda obvious:
58 * 3) a user would certainly not have choosen a scrolled window as a container
59 * for the child, if the resulting allocation takes up more space than the
60 * child would have allocated without the scrolled window.
61 *
62 * conclusions:
63 * A) from 1) follows: the scrolled window shouldn't request more space for a
64 * specifc dimension than is required at minimum.
65 * B) from 1.1) follows: the requisition may be overidden by usize of the scrolled
66 * window (done automatically) or by usize of the child (needs to be checked).
67 * C) from 2) follows: for POLICY_NEVER, the scrolled window simply reports the
68 * child's dimension.
69 * D) from 3) follows: the scrolled window child's minimum width and minimum height
70 * under A) at least correspond to the space taken up by its scrollbars.
71 */
72
73 /* Object argument IDs */
74 enum {
75 ARG_0,
76 ARG_HADJUSTMENT,
77 ARG_VADJUSTMENT,
78 ARG_HSCROLLBAR_POLICY,
79 ARG_VSCROLLBAR_POLICY,
80 ARG_FRAME_PLACEMENT,
81 ARG_SHADOW_TYPE,
82 ARG_SCROLLBAR_SPACING
83 };
84
85 /* Private part of the GtkScrollFrame structure */
86 typedef struct {
87 /* Horizontal and vertical scrollbars */
88 GtkWidget *hsb;
89 GtkWidget *vsb;
90
91 /* Space between scrollbars and frame */
92 guint sb_spacing;
93
94 /* Allocation for frame */
95 guint frame_x;
96 guint frame_y;
97 guint frame_w;
98 guint frame_h;
99
100 /* Scrollbar policy */
101 guint hsb_policy : 2;
102 guint vsb_policy : 2;
103
104 /* Whether scrollbars are visible */
105 guint hsb_visible : 1;
106 guint vsb_visible : 1;
107
108 /* Placement of frame wrt scrollbars */
109 guint frame_placement : 2;
110
111 /* Shadow type for frame */
112 guint shadow_type : 3;
113 } ScrollFramePrivate;
114
115
116 static void gtk_scroll_frame_class_init (GtkScrollFrameClass *class);
117 static void gtk_scroll_frame_init (GtkScrollFrame *sf);
118 static void gtk_scroll_frame_set_arg (GtkObject *object, GtkArg *arg, guint arg_id);
119 static void gtk_scroll_frame_get_arg (GtkObject *object, GtkArg *arg, guint arg_id);
120 static void gtk_scroll_frame_destroy (GtkObject *object);
121 static void gtk_scroll_frame_finalize (GtkObject *object);
122
123 static void gtk_scroll_frame_map (GtkWidget *widget);
124 static void gtk_scroll_frame_unmap (GtkWidget *widget);
125 static void gtk_scroll_frame_draw (GtkWidget *widget, GdkRectangle *area);
126 static void gtk_scroll_frame_size_request (GtkWidget *widget, GtkRequisition *requisition);
127 static void gtk_scroll_frame_size_allocate (GtkWidget *widget, GtkAllocation *allocation);
128 static gint gtk_scroll_frame_expose (GtkWidget *widget, GdkEventExpose *event);
129 static gint gtk_scroll_frame_button_press (GtkWidget *widget, GdkEventButton *event);
130
131 static void gtk_scroll_frame_add (GtkContainer *container, GtkWidget *widget);
132 static void gtk_scroll_frame_remove (GtkContainer *container, GtkWidget *widget);
133 static void gtk_scroll_frame_forall (GtkContainer *container, gboolean include_internals,
134 GtkCallback callback, gpointer callback_data);
135
136 static GtkBinClass *parent_class;
137
138
139 /**
140 * gtk_scroll_frame_get_type:
141 * @void:
142 *
143 * Registers the #GtkScrollFrame class if necessary, and returns the type ID
144 * associated to it.
145 *
146 * Return value: The type ID of the #GtkScrollFrame class.
147 **/
148 GtkType
gtk_scroll_frame_get_type(void)149 gtk_scroll_frame_get_type (void)
150 {
151 static GtkType scroll_frame_type = 0;
152
153 if (!scroll_frame_type) {
154 static const GtkTypeInfo scroll_frame_info = {
155 "GtkScrollFrame",
156 sizeof (GtkScrollFrame),
157 sizeof (GtkScrollFrameClass),
158 (GtkClassInitFunc) gtk_scroll_frame_class_init,
159 (GtkObjectInitFunc) gtk_scroll_frame_init,
160 NULL, /* reserved_1 */
161 NULL, /* reserved_2 */
162 (GtkClassInitFunc) NULL
163 };
164
165 scroll_frame_type = gtk_type_unique (GTK_TYPE_BIN, &scroll_frame_info);
166 }
167
168 return scroll_frame_type;
169 }
170
171 /* Class initialization function for the scroll frame widget */
172 static void
gtk_scroll_frame_class_init(GtkScrollFrameClass * class)173 gtk_scroll_frame_class_init (GtkScrollFrameClass *class)
174 {
175 GtkObjectClass *object_class;
176 GtkWidgetClass *widget_class;
177 GtkContainerClass *container_class;
178
179 object_class = (GtkObjectClass *) class;
180 widget_class = (GtkWidgetClass *) class;
181 container_class = (GtkContainerClass *) class;
182
183 parent_class = gtk_type_class (GTK_TYPE_BIN);
184
185 gtk_object_add_arg_type ("GtkScrollFrame::hadjustment",
186 GTK_TYPE_ADJUSTMENT,
187 GTK_ARG_READWRITE | GTK_ARG_CONSTRUCT,
188 ARG_HADJUSTMENT);
189 gtk_object_add_arg_type ("GtkScrollFrame::vadjustment",
190 GTK_TYPE_ADJUSTMENT,
191 GTK_ARG_READWRITE | GTK_ARG_CONSTRUCT,
192 ARG_VADJUSTMENT);
193 gtk_object_add_arg_type ("GtkScrollFrame::hscrollbar_policy",
194 GTK_TYPE_POLICY_TYPE,
195 GTK_ARG_READWRITE,
196 ARG_HSCROLLBAR_POLICY);
197 gtk_object_add_arg_type ("GtkScrollFrame::vscrollbar_policy",
198 GTK_TYPE_POLICY_TYPE,
199 GTK_ARG_READWRITE,
200 ARG_VSCROLLBAR_POLICY);
201 gtk_object_add_arg_type ("GtkScrollFrame::frame_placement",
202 GTK_TYPE_CORNER_TYPE,
203 GTK_ARG_READWRITE,
204 ARG_FRAME_PLACEMENT);
205 gtk_object_add_arg_type ("GtkScrollFrame::shadow_type",
206 GTK_TYPE_SHADOW_TYPE,
207 GTK_ARG_READWRITE,
208 ARG_SHADOW_TYPE);
209 gtk_object_add_arg_type ("GtkScrollFrame::scrollbar_spacing",
210 GTK_TYPE_UINT,
211 GTK_ARG_READWRITE,
212 ARG_SCROLLBAR_SPACING);
213
214 object_class->set_arg = gtk_scroll_frame_set_arg;
215 object_class->get_arg = gtk_scroll_frame_get_arg;
216 object_class->destroy = gtk_scroll_frame_destroy;
217 //object_class->finalize = gtk_scroll_frame_finalize;
218
219 widget_class->map = gtk_scroll_frame_map;
220 widget_class->unmap = gtk_scroll_frame_unmap;
221 //widget_class->draw = gtk_scroll_frame_draw;
222 widget_class->size_request = gtk_scroll_frame_size_request;
223 widget_class->size_allocate = gtk_scroll_frame_size_allocate;
224 widget_class->expose_event = gtk_scroll_frame_expose;
225 widget_class->button_press_event = gtk_scroll_frame_button_press;
226
227 container_class->add = gtk_scroll_frame_add;
228 container_class->remove = gtk_scroll_frame_remove;
229 container_class->forall = gtk_scroll_frame_forall;
230 }
231
232 /* Object initialization function for the scroll frame widget */
233 static void
gtk_scroll_frame_init(GtkScrollFrame * sf)234 gtk_scroll_frame_init (GtkScrollFrame *sf)
235 {
236 ScrollFramePrivate *priv;
237
238 priv = g_new0 (ScrollFramePrivate, 1);
239 sf->priv = priv;
240
241 GTK_WIDGET_SET_FLAGS (sf, GTK_NO_WINDOW);
242
243 gtk_container_set_resize_mode (GTK_CONTAINER (sf), GTK_RESIZE_QUEUE);
244
245 priv->sb_spacing = 3;
246 priv->hsb_policy = GTK_POLICY_ALWAYS;
247 priv->vsb_policy = GTK_POLICY_ALWAYS;
248 priv->frame_placement = GTK_CORNER_TOP_LEFT;
249 priv->shadow_type = GTK_SHADOW_NONE;
250 }
251
252 /* Set_arg handler for the scroll frame widget */
253 static void
gtk_scroll_frame_set_arg(GtkObject * object,GtkArg * arg,guint arg_id)254 gtk_scroll_frame_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
255 {
256 GtkScrollFrame *sf;
257 ScrollFramePrivate *priv;
258
259 sf = GTK_SCROLL_FRAME (object);
260 priv = sf->priv;
261
262 switch (arg_id) {
263 case ARG_HADJUSTMENT:
264 gtk_scroll_frame_set_hadjustment (sf, GTK_VALUE_POINTER (*arg));
265 break;
266
267 case ARG_VADJUSTMENT:
268 gtk_scroll_frame_set_vadjustment (sf, GTK_VALUE_POINTER (*arg));
269 break;
270
271 case ARG_HSCROLLBAR_POLICY:
272 gtk_scroll_frame_set_policy (sf, GTK_VALUE_ENUM (*arg), priv->vsb_policy);
273 break;
274
275 case ARG_VSCROLLBAR_POLICY:
276 gtk_scroll_frame_set_policy (sf, priv->hsb_policy, GTK_VALUE_ENUM (*arg));
277 break;
278
279 case ARG_FRAME_PLACEMENT:
280 gtk_scroll_frame_set_placement (sf, GTK_VALUE_ENUM (*arg));
281 break;
282
283 case ARG_SHADOW_TYPE:
284 gtk_scroll_frame_set_shadow_type (sf, GTK_VALUE_ENUM (*arg));
285 break;
286
287 case ARG_SCROLLBAR_SPACING:
288 gtk_scroll_frame_set_scrollbar_spacing (sf, GTK_VALUE_UINT (*arg));
289 break;
290
291 default:
292 break;
293 }
294 }
295
296 /* Get_arg handler for the scroll frame widget */
297 static void
gtk_scroll_frame_get_arg(GtkObject * object,GtkArg * arg,guint arg_id)298 gtk_scroll_frame_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
299 {
300 GtkScrollFrame *sf;
301 ScrollFramePrivate *priv;
302
303 sf = GTK_SCROLL_FRAME (object);
304 priv = sf->priv;
305
306 switch (arg_id) {
307 case ARG_HADJUSTMENT:
308 GTK_VALUE_POINTER (*arg) = gtk_scroll_frame_get_hadjustment (sf);
309 break;
310
311 case ARG_VADJUSTMENT:
312 GTK_VALUE_POINTER (*arg) = gtk_scroll_frame_get_vadjustment (sf);
313 break;
314
315 case ARG_HSCROLLBAR_POLICY:
316 GTK_VALUE_ENUM (*arg) = priv->hsb_policy;
317 break;
318
319 case ARG_VSCROLLBAR_POLICY:
320 GTK_VALUE_ENUM (*arg) = priv->vsb_policy;
321 break;
322
323 case ARG_FRAME_PLACEMENT:
324 GTK_VALUE_ENUM (*arg) = priv->frame_placement;
325 break;
326
327 case ARG_SHADOW_TYPE:
328 GTK_VALUE_ENUM (*arg) = priv->shadow_type;
329 break;
330
331 case ARG_SCROLLBAR_SPACING:
332 GTK_VALUE_UINT (*arg) = priv->sb_spacing;
333 break;
334
335 default:
336 arg->type = GTK_TYPE_INVALID;
337 break;
338 }
339 }
340
341 /* Destroy handler for the scroll frame widget */
342 static void
gtk_scroll_frame_destroy(GtkObject * object)343 gtk_scroll_frame_destroy (GtkObject *object)
344 {
345 GtkScrollFrame *sf;
346 ScrollFramePrivate *priv;
347
348 g_return_if_fail (object != NULL);
349 g_return_if_fail (GTK_IS_SCROLL_FRAME (object));
350
351 sf = GTK_SCROLL_FRAME (object);
352 priv = sf->priv;
353
354 gtk_widget_unparent (priv->hsb);
355 gtk_widget_unparent (priv->vsb);
356 gtk_widget_destroy (priv->hsb);
357 gtk_widget_destroy (priv->vsb);
358
359 if (GTK_OBJECT_CLASS (parent_class)->destroy)
360 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
361 }
362
363 /* Finalize handler for the scroll frame widget */
364 static void
gtk_scroll_frame_finalize(GtkObject * object)365 gtk_scroll_frame_finalize (GtkObject *object)
366 {
367 GtkScrollFrame *sf;
368 ScrollFramePrivate *priv;
369
370 sf = GTK_SCROLL_FRAME (object);
371 priv = sf->priv;
372
373 gtk_widget_unref (priv->hsb);
374 gtk_widget_unref (priv->vsb);
375
376 g_free (priv);
377
378 //if (GTK_OBJECT_CLASS (parent_class)->finalize)
379 // (* GTK_OBJECT_CLASS (parent_class)->finalize) (object);
380 }
381
382 /* Map handler for the scroll frame widget */
383 static void
gtk_scroll_frame_map(GtkWidget * widget)384 gtk_scroll_frame_map (GtkWidget *widget)
385 {
386 GtkScrollFrame *sf;
387 ScrollFramePrivate *priv;
388
389 g_return_if_fail (widget != NULL);
390 g_return_if_fail (GTK_IS_SCROLL_FRAME (widget));
391
392 sf = GTK_SCROLL_FRAME (widget);
393 priv = sf->priv;
394
395 /* chain parent class handler to map self and child */
396 if (GTK_WIDGET_CLASS (parent_class)->map)
397 (* GTK_WIDGET_CLASS (parent_class)->map) (widget);
398
399 if (GTK_WIDGET_VISIBLE (priv->hsb) && !GTK_WIDGET_MAPPED (priv->hsb))
400 gtk_widget_map (priv->hsb);
401
402 if (GTK_WIDGET_VISIBLE (priv->vsb) && !GTK_WIDGET_MAPPED (priv->vsb))
403 gtk_widget_map (priv->vsb);
404 }
405
406 /* Unmap handler for the scroll frame widget */
407 static void
gtk_scroll_frame_unmap(GtkWidget * widget)408 gtk_scroll_frame_unmap (GtkWidget *widget)
409 {
410 GtkScrollFrame *sf;
411 ScrollFramePrivate *priv;
412
413 g_return_if_fail (widget != NULL);
414 g_return_if_fail (GTK_IS_SCROLL_FRAME (widget));
415
416 sf = GTK_SCROLL_FRAME (widget);
417 priv = sf->priv;
418
419 /* chain parent class handler to unmap self and child */
420 if (GTK_WIDGET_CLASS (parent_class)->unmap)
421 (* GTK_WIDGET_CLASS (parent_class)->unmap) (widget);
422
423 if (GTK_WIDGET_MAPPED (priv->hsb))
424 gtk_widget_unmap (priv->hsb);
425
426 if (GTK_WIDGET_MAPPED (priv->vsb))
427 gtk_widget_unmap (priv->vsb);
428 }
429
430 /* Draws the shadow of a scroll frame widget */
431 static void
draw_shadow(GtkScrollFrame * sf,GdkRectangle * area)432 draw_shadow (GtkScrollFrame *sf, GdkRectangle *area)
433 {
434 ScrollFramePrivate *priv;
435
436 g_assert (area != NULL);
437
438 priv = sf->priv;
439
440 gtk_paint_shadow (GTK_WIDGET (sf)->style,
441 GTK_WIDGET (sf)->window,
442 GTK_STATE_NORMAL, priv->shadow_type,
443 area, GTK_WIDGET (sf),
444 "scroll_frame",
445 priv->frame_x, priv->frame_y,
446 priv->frame_w, priv->frame_h);
447 }
448
449 /* Draw handler for the scroll frame widget */
450 static void
gtk_scroll_frame_draw(GtkWidget * widget,GdkRectangle * area)451 gtk_scroll_frame_draw (GtkWidget *widget, GdkRectangle *area)
452 {
453 GtkScrollFrame *sf;
454 ScrollFramePrivate *priv;
455 GtkBin *bin;
456 GdkRectangle child_area;
457
458 g_return_if_fail (widget != NULL);
459 g_return_if_fail (GTK_IS_SCROLL_FRAME (widget));
460 g_return_if_fail (area != NULL);
461
462 sf = GTK_SCROLL_FRAME (widget);
463 priv = sf->priv;
464 bin = GTK_BIN (widget);
465
466 if (GTK_WIDGET_DRAWABLE (widget))
467 draw_shadow (sf, area);
468
469 if (bin->child && GTK_WIDGET_VISIBLE (bin->child)
470 && gtk_widget_intersect (bin->child, area, &child_area))
471 gtk_widget_draw (bin->child, &child_area);
472
473 if (GTK_WIDGET_VISIBLE (priv->hsb)
474 && gtk_widget_intersect (priv->hsb, area, &child_area))
475 gtk_widget_draw (priv->hsb, &child_area);
476
477 if (GTK_WIDGET_VISIBLE (priv->vsb)
478 && gtk_widget_intersect (priv->vsb, area, &child_area))
479 gtk_widget_draw (priv->vsb, &child_area);
480 }
481
482 /* Forall handler for the scroll frame widget */
483 static void
gtk_scroll_frame_forall(GtkContainer * container,gboolean include_internals,GtkCallback callback,gpointer callback_data)484 gtk_scroll_frame_forall (GtkContainer *container, gboolean include_internals,
485 GtkCallback callback, gpointer callback_data)
486 {
487 GtkScrollFrame *sf;
488 ScrollFramePrivate *priv;
489
490 g_return_if_fail (container != NULL);
491 g_return_if_fail (GTK_IS_SCROLL_FRAME (container));
492 g_return_if_fail (callback != NULL);
493
494 sf = GTK_SCROLL_FRAME (container);
495 priv = sf->priv;
496
497 if (GTK_CONTAINER_CLASS (parent_class)->forall)
498 (* GTK_CONTAINER_CLASS (parent_class)->forall) (
499 container, include_internals,
500 callback, callback_data);
501
502 if (include_internals) {
503 if (priv->vsb)
504 (* callback) (priv->vsb, callback_data);
505
506 if (priv->hsb)
507 (* callback) (priv->hsb, callback_data);
508 }
509 }
510
511 /* Size_request handler for the scroll frame widget */
512 static void
gtk_scroll_frame_size_request(GtkWidget * widget,GtkRequisition * requisition)513 gtk_scroll_frame_size_request (GtkWidget *widget, GtkRequisition *requisition)
514 {
515 GtkScrollFrame *sf;
516 ScrollFramePrivate *priv;
517 GtkBin *bin;
518 int extra_width;
519 int extra_height;
520 GtkRequisition hsb_requisition;
521 GtkRequisition vsb_requisition;
522 GtkRequisition child_requisition;
523
524 g_return_if_fail (widget != NULL);
525 g_return_if_fail (GTK_IS_SCROLL_FRAME (widget));
526 g_return_if_fail (requisition != NULL);
527
528 sf = GTK_SCROLL_FRAME (widget);
529 priv = sf->priv;
530 bin = GTK_BIN (widget);
531
532 extra_width = 0;
533 extra_height = 0;
534
535 requisition->width = GTK_CONTAINER (widget)->border_width * 2;
536 requisition->height = GTK_CONTAINER (widget)->border_width * 2;
537
538 if (priv->shadow_type != GTK_SHADOW_NONE) {
539 //requisition->width += 2 * widget->style->klass->xthickness;
540 //requisition->height += 2 * widget->style->klass->ythickness;
541 }
542
543 gtk_widget_size_request (priv->hsb, &hsb_requisition);
544 gtk_widget_size_request (priv->vsb, &vsb_requisition);
545
546 if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) {
547 static guint quark_aux_info;
548
549 if (!quark_aux_info)
550 quark_aux_info = g_quark_from_static_string ("gtk-aux-info");
551
552 gtk_widget_size_request (bin->child, &child_requisition);
553
554 if (priv->hsb_policy == GTK_POLICY_NEVER)
555 requisition->width += child_requisition.width;
556 else {
557 GtkWidgetAuxInfo *aux_info;
558
559 aux_info = gtk_object_get_data_by_id (GTK_OBJECT (bin->child),
560 quark_aux_info);
561 if (aux_info && aux_info->width > 0) {
562 requisition->width += aux_info->width;
563 extra_width = -1;
564 } else
565 requisition->width += vsb_requisition.width;
566 }
567
568 if (priv->vsb_policy == GTK_POLICY_NEVER)
569 requisition->height += child_requisition.height;
570 else {
571 GtkWidgetAuxInfo *aux_info;
572
573 aux_info = gtk_object_get_data_by_id (GTK_OBJECT (bin->child),
574 quark_aux_info);
575 if (aux_info && aux_info->height > 0) {
576 requisition->height += aux_info->height;
577 extra_height = -1;
578 } else
579 requisition->height += hsb_requisition.height;
580 }
581 }
582
583 if (priv->hsb_policy == GTK_POLICY_AUTOMATIC || GTK_WIDGET_VISIBLE (priv->hsb)) {
584 requisition->width = MAX (requisition->width, hsb_requisition.width);
585 if (!extra_height || GTK_WIDGET_VISIBLE (priv->hsb))
586 extra_height = priv->sb_spacing + hsb_requisition.height;
587 }
588
589 if (priv->vsb_policy == GTK_POLICY_AUTOMATIC || GTK_WIDGET_VISIBLE (priv->vsb)) {
590 requisition->height = MAX (requisition->height, vsb_requisition.height);
591 if (!extra_width || GTK_WIDGET_VISIBLE (priv->vsb))
592 extra_width = priv->sb_spacing + vsb_requisition.width;
593 }
594
595 requisition->width += MAX (0, extra_width);
596 requisition->height += MAX (0, extra_height);
597 }
598
599 /* Computes the relative allocation for the scroll frame widget */
600 static void
compute_relative_allocation(GtkWidget * widget,GtkAllocation * allocation)601 compute_relative_allocation (GtkWidget *widget, GtkAllocation *allocation)
602 {
603 GtkScrollFrame *sf;
604 ScrollFramePrivate *priv;
605
606 g_assert (widget != NULL);
607 g_assert (GTK_IS_SCROLL_FRAME (widget));
608 g_assert (allocation != NULL);
609
610 sf = GTK_SCROLL_FRAME (widget);
611 priv = sf->priv;
612
613 allocation->x = GTK_CONTAINER (widget)->border_width;
614 allocation->y = GTK_CONTAINER (widget)->border_width;
615 allocation->width = MAX (1, (int) widget->allocation.width - (int) allocation->x * 2);
616 allocation->height = MAX (1, (int) widget->allocation.height - (int) allocation->y * 2);
617
618 if (priv->vsb_visible) {
619 GtkRequisition vsb_requisition;
620
621 gtk_widget_get_child_requisition (priv->vsb, &vsb_requisition);
622
623 if (priv->frame_placement == GTK_CORNER_TOP_RIGHT
624 || priv->frame_placement == GTK_CORNER_BOTTOM_RIGHT)
625 allocation->x += vsb_requisition.width + priv->sb_spacing;
626
627 allocation->width = MAX (1,
628 ((int) allocation->width
629 - (int) (vsb_requisition.width + priv->sb_spacing)));
630 }
631
632 if (priv->hsb_visible) {
633 GtkRequisition hsb_requisition;
634
635 gtk_widget_get_child_requisition (priv->hsb, &hsb_requisition);
636
637 if (priv->frame_placement == GTK_CORNER_BOTTOM_LEFT
638 || priv->frame_placement == GTK_CORNER_BOTTOM_RIGHT)
639 allocation->y += hsb_requisition.height + priv->sb_spacing;
640
641 allocation->height = MAX (1,
642 ((int) allocation->height
643 - (int) (hsb_requisition.height + priv->sb_spacing)));
644 }
645 }
646
647 /* Size_allocate handler for the scroll frame widget */
648 static void
gtk_scroll_frame_size_allocate(GtkWidget * widget,GtkAllocation * allocation)649 gtk_scroll_frame_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
650 {
651 GtkScrollFrame *sf;
652 ScrollFramePrivate *priv;
653 GtkBin *bin;
654 GtkAllocation relative_allocation;
655 GtkAllocation child_allocation;
656 int xthickness, ythickness;
657
658 g_return_if_fail (widget != NULL);
659 g_return_if_fail (GTK_IS_SCROLL_FRAME (widget));
660 g_return_if_fail (allocation != NULL);
661
662 sf = GTK_SCROLL_FRAME (widget);
663 priv = sf->priv;
664 bin = GTK_BIN (widget);
665
666 widget->allocation = *allocation;
667
668 if (priv->hsb_policy == GTK_POLICY_ALWAYS)
669 priv->hsb_visible = TRUE;
670 else if (priv->hsb_policy == GTK_POLICY_NEVER)
671 priv->hsb_visible = FALSE;
672
673 if (priv->vsb_policy == GTK_POLICY_ALWAYS)
674 priv->vsb_visible = TRUE;
675 else if (priv->vsb_policy == GTK_POLICY_NEVER)
676 priv->vsb_visible = FALSE;
677
678 if (priv->shadow_type == GTK_SHADOW_NONE) {
679 xthickness = 0;
680 ythickness = 0;
681 } else {
682 //xthickness = widget->style->klass->xthickness;
683 //ythickness = widget->style->klass->ythickness;
684 }
685
686 if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) {
687 gboolean previous_hvis;
688 gboolean previous_vvis;
689 guint count = 0;
690
691 do {
692 compute_relative_allocation (widget, &relative_allocation);
693
694 priv->frame_x = relative_allocation.x + allocation->x;
695 priv->frame_y = relative_allocation.y + allocation->y;
696 priv->frame_w = relative_allocation.width;
697 priv->frame_h = relative_allocation.height;
698
699 child_allocation.x = priv->frame_x + xthickness;
700 child_allocation.y = priv->frame_y + ythickness;
701 child_allocation.width = MAX ((int) priv->frame_w - 2 * xthickness, 0);
702 child_allocation.height = MAX ((int) priv->frame_h - 2 * ythickness, 0);
703
704 previous_hvis = priv->hsb_visible;
705 previous_vvis = priv->vsb_visible;
706
707 gtk_widget_size_allocate (bin->child, &child_allocation);
708
709 /* If, after the first iteration, the hscrollbar and the
710 * vscrollbar flip visiblity, then we need both.
711 */
712 if (count
713 && previous_hvis != priv->hsb_visible
714 && previous_vvis != priv->vsb_visible) {
715 priv->hsb_visible = TRUE;
716 priv->vsb_visible = TRUE;
717
718 /* a new resize is already queued at this point,
719 * so we will immediatedly get reinvoked
720 */
721 return;
722 }
723
724 count++;
725 } while (previous_hvis != priv->hsb_visible
726 || previous_vvis != priv->vsb_visible);
727 } else
728 compute_relative_allocation (widget, &relative_allocation);
729
730 if (priv->hsb_visible) {
731 GtkRequisition hscrollbar_requisition;
732
733 gtk_widget_get_child_requisition (priv->hsb, &hscrollbar_requisition);
734
735 if (!GTK_WIDGET_VISIBLE (priv->hsb))
736 gtk_widget_show (priv->hsb);
737
738 child_allocation.x = relative_allocation.x;
739 if (priv->frame_placement == GTK_CORNER_TOP_LEFT
740 || priv->frame_placement == GTK_CORNER_TOP_RIGHT)
741 child_allocation.y = (relative_allocation.y
742 + relative_allocation.height
743 + priv->sb_spacing);
744 else
745 child_allocation.y = GTK_CONTAINER (sf)->border_width;
746
747 child_allocation.width = relative_allocation.width;
748 child_allocation.height = hscrollbar_requisition.height;
749 child_allocation.x += allocation->x;
750 child_allocation.y += allocation->y;
751
752 gtk_widget_size_allocate (priv->hsb, &child_allocation);
753 } else if (GTK_WIDGET_VISIBLE (priv->hsb))
754 gtk_widget_hide (priv->hsb);
755
756 if (priv->vsb_visible) {
757 GtkRequisition vscrollbar_requisition;
758
759 if (!GTK_WIDGET_VISIBLE (priv->vsb))
760 gtk_widget_show (priv->vsb);
761
762 gtk_widget_get_child_requisition (priv->vsb, &vscrollbar_requisition);
763
764 if (priv->frame_placement == GTK_CORNER_TOP_LEFT
765 || priv->frame_placement == GTK_CORNER_BOTTOM_LEFT)
766 child_allocation.x = (relative_allocation.x
767 + relative_allocation.width
768 + priv->sb_spacing);
769 else
770 child_allocation.x = GTK_CONTAINER (sf)->border_width;
771
772 child_allocation.y = relative_allocation.y;
773 child_allocation.width = vscrollbar_requisition.width;
774 child_allocation.height = relative_allocation.height;
775 child_allocation.x += allocation->x;
776 child_allocation.y += allocation->y;
777
778 gtk_widget_size_allocate (priv->vsb, &child_allocation);
779 } else if (GTK_WIDGET_VISIBLE (priv->vsb))
780 gtk_widget_hide (priv->vsb);
781 }
782
783 /* Button press handler for the scroll framw diget */
784 static gint
gtk_scroll_frame_button_press(GtkWidget * widget,GdkEventButton * event)785 gtk_scroll_frame_button_press (GtkWidget *widget, GdkEventButton *event)
786 {
787 g_return_val_if_fail (widget != NULL, FALSE);
788 g_return_val_if_fail (GTK_IS_SCROLL_FRAME (widget), FALSE);
789 g_return_val_if_fail (event != NULL, FALSE);
790
791 /* This is to handle mouse wheel scrolling */
792 if (event->button == 4 || event->button == 5) {
793 GtkAdjustment *adj;
794 gfloat new_value;
795
796 gtk_object_get (GTK_OBJECT (widget),
797 (event->state & GDK_CONTROL_MASK) ?
798 "hadjustment" : "vadjustment",
799 &adj,
800 NULL);
801
802 new_value = adj->value + ((event->button == 4) ?
803 -adj->page_increment / 2:
804 adj->page_increment / 2);
805 new_value = CLAMP (new_value, adj->lower, adj->upper - adj->page_size);
806 gtk_adjustment_set_value (adj, new_value);
807
808 return TRUE;
809 }
810
811 return FALSE;
812 }
813
814 /* Expose handler for the scroll frame widget */
815 static gint
gtk_scroll_frame_expose(GtkWidget * widget,GdkEventExpose * event)816 gtk_scroll_frame_expose (GtkWidget *widget, GdkEventExpose *event)
817 {
818 GtkScrollFrame *sf;
819
820 g_return_val_if_fail (widget != NULL, FALSE);
821 g_return_val_if_fail (GTK_IS_SCROLL_FRAME (widget), FALSE);
822 g_return_val_if_fail (event != NULL, FALSE);
823
824 sf = GTK_SCROLL_FRAME (widget);
825
826 if (GTK_WIDGET_DRAWABLE (widget))
827 draw_shadow (sf, &event->area);
828
829 if (GTK_WIDGET_CLASS (parent_class)->expose_event)
830 (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
831
832 return FALSE;
833 }
834
835 /* Add handler for the scroll frame widget */
836 static void
gtk_scroll_frame_add(GtkContainer * container,GtkWidget * child)837 gtk_scroll_frame_add (GtkContainer *container, GtkWidget *child)
838 {
839 GtkScrollFrame *sf;
840 ScrollFramePrivate *priv;
841 GtkBin *bin;
842
843 sf = GTK_SCROLL_FRAME (container);
844 priv = sf->priv;
845 bin = GTK_BIN (container);
846 g_return_if_fail (bin->child == NULL);
847
848 bin->child = child;
849 gtk_widget_set_parent (child, GTK_WIDGET (bin));
850
851 /* this is a temporary message */
852 if (!gtk_widget_set_scroll_adjustments (child,
853 gtk_range_get_adjustment (GTK_RANGE (priv->hsb)),
854 gtk_range_get_adjustment (GTK_RANGE (priv->vsb))))
855 g_warning ("gtk_scroll_frame_add(): cannot add non scrollable widget "
856 "use gtk_scroll_frame_add_with_viewport() instead");
857
858 if (GTK_WIDGET_REALIZED (child->parent))
859 gtk_widget_realize (child);
860
861 if (GTK_WIDGET_VISIBLE (child->parent) && GTK_WIDGET_VISIBLE (child)) {
862 if (GTK_WIDGET_MAPPED (child->parent))
863 gtk_widget_map (child);
864
865 gtk_widget_queue_resize (child);
866 }
867 }
868
869 /* Remove method for the scroll frame widget */
870 static void
gtk_scroll_frame_remove(GtkContainer * container,GtkWidget * child)871 gtk_scroll_frame_remove (GtkContainer *container, GtkWidget *child)
872 {
873 g_return_if_fail (container != NULL);
874 g_return_if_fail (GTK_IS_SCROLL_FRAME (container));
875 g_return_if_fail (child != NULL);
876 g_return_if_fail (GTK_BIN (container)->child == child);
877
878 gtk_widget_set_scroll_adjustments (child, NULL, NULL);
879
880 /* chain parent class handler to remove child */
881 if (GTK_CONTAINER_CLASS (parent_class)->remove)
882 (* GTK_CONTAINER_CLASS (parent_class)->remove) (container, child);
883 }
884
885 /**
886 * gtk_scroll_frame_new:
887 * @hadj: If non-NULL, the adjustment to use for horizontal scrolling.
888 * @vadj: If non-NULL, the adjustment to use for vertical scrolling.
889 *
890 * Creates a new scroll frame widget.
891 *
892 * Return value: The newly-created scroll frame widget.
893 **/
894 GtkWidget *
gtk_scroll_frame_new(GtkAdjustment * hadj,GtkAdjustment * vadj)895 gtk_scroll_frame_new (GtkAdjustment *hadj, GtkAdjustment *vadj)
896 {
897 if (hadj)
898 g_return_val_if_fail (GTK_IS_ADJUSTMENT (hadj), NULL);
899
900 if (vadj)
901 g_return_val_if_fail (GTK_IS_ADJUSTMENT (vadj), NULL);
902
903 return gtk_widget_new (GTK_TYPE_SCROLL_FRAME,
904 "hadjustment", hadj,
905 "vadjustment", vadj,
906 NULL);
907 }
908
909 /* Callback used when one of the scroll frame widget's adjustments changes */
910 static void
adjustment_changed(GtkAdjustment * adj,gpointer data)911 adjustment_changed (GtkAdjustment *adj, gpointer data)
912 {
913 GtkScrollFrame *sf;
914 ScrollFramePrivate *priv;
915
916 g_return_if_fail (adj != NULL);
917 g_return_if_fail (GTK_IS_ADJUSTMENT (adj));
918 g_return_if_fail (data != NULL);
919
920 sf = GTK_SCROLL_FRAME (data);
921 priv = sf->priv;
922
923 if (adj == gtk_range_get_adjustment (GTK_RANGE (priv->hsb))) {
924 if (priv->hsb_policy == GTK_POLICY_AUTOMATIC) {
925 gboolean visible;
926
927 visible = priv->hsb_visible;
928 priv->hsb_visible = (adj->upper - adj->lower > adj->page_size);
929 if (priv->hsb_visible != visible)
930 gtk_widget_queue_resize (GTK_WIDGET (sf));
931 }
932 } else if (adj == gtk_range_get_adjustment (GTK_RANGE (priv->vsb))) {
933 if (priv->vsb_policy == GTK_POLICY_AUTOMATIC) {
934 gboolean visible;
935
936 visible = priv->vsb_visible;
937 priv->vsb_visible = (adj->upper - adj->lower > adj->page_size);
938 if (priv->vsb_visible != visible)
939 gtk_widget_queue_resize (GTK_WIDGET (sf));
940 }
941 }
942 }
943
944 /**
945 * gtk_scroll_frame_set_hadjustment:
946 * @sf: A scroll frame widget.
947 * @adj: An adjustment.
948 *
949 * Sets the adjustment to be used for horizontal scrolling in a scroll frame
950 * widget.
951 **/
952 void
gtk_scroll_frame_set_hadjustment(GtkScrollFrame * sf,GtkAdjustment * adj)953 gtk_scroll_frame_set_hadjustment (GtkScrollFrame *sf, GtkAdjustment *adj)
954 {
955 ScrollFramePrivate *priv;
956
957 g_return_if_fail (sf != NULL);
958 g_return_if_fail (GTK_IS_SCROLL_FRAME (sf));
959
960 priv = sf->priv;
961
962 if (adj)
963 g_return_if_fail (GTK_IS_ADJUSTMENT (adj));
964 else
965 adj = GTK_ADJUSTMENT (gtk_object_new (GTK_TYPE_ADJUSTMENT, NULL));
966
967 if (!priv->hsb) {
968 gtk_widget_push_composite_child ();
969 priv->hsb = gtk_hscrollbar_new (adj);
970 gtk_widget_set_composite_name (priv->hsb, "hscrollbar");
971 gtk_widget_pop_composite_child ();
972
973 gtk_widget_set_parent (priv->hsb, GTK_WIDGET (sf));
974 gtk_widget_ref (priv->hsb);
975 gtk_widget_show (priv->hsb);
976 } else {
977 GtkAdjustment *old_adj;
978
979 old_adj = gtk_range_get_adjustment (GTK_RANGE (priv->hsb));
980 if (old_adj == adj)
981 return;
982
983 gtk_signal_disconnect_by_func (GTK_OBJECT (old_adj),
984 GTK_SIGNAL_FUNC (adjustment_changed),
985 sf);
986 gtk_range_set_adjustment (GTK_RANGE (priv->hsb), adj);
987 }
988
989 adj = gtk_range_get_adjustment (GTK_RANGE (priv->hsb));
990 gtk_signal_connect (GTK_OBJECT (adj),
991 "changed",
992 GTK_SIGNAL_FUNC (adjustment_changed),
993 sf);
994 adjustment_changed (adj, sf);
995
996 if (GTK_BIN (sf)->child)
997 gtk_widget_set_scroll_adjustments (
998 GTK_BIN (sf)->child,
999 gtk_range_get_adjustment (GTK_RANGE (priv->hsb)),
1000 gtk_range_get_adjustment (GTK_RANGE (priv->vsb)));
1001 }
1002
1003 /**
1004 * gtk_scroll_frame_set_vadjustment:
1005 * @sf: A scroll frame widget.
1006 * @adj: An adjustment.
1007 *
1008 * Sets the adjustment to be used for vertical scrolling in a scroll frame
1009 * widget.
1010 **/
1011 void
gtk_scroll_frame_set_vadjustment(GtkScrollFrame * sf,GtkAdjustment * adj)1012 gtk_scroll_frame_set_vadjustment (GtkScrollFrame *sf, GtkAdjustment *adj)
1013 {
1014 ScrollFramePrivate *priv;
1015
1016 g_return_if_fail (sf != NULL);
1017 g_return_if_fail (GTK_IS_SCROLL_FRAME (sf));
1018
1019 priv = sf->priv;
1020
1021 if (adj)
1022 g_return_if_fail (GTK_IS_ADJUSTMENT (adj));
1023 else
1024 adj = GTK_ADJUSTMENT (gtk_object_new (GTK_TYPE_ADJUSTMENT, NULL));
1025
1026 if (!priv->vsb) {
1027 gtk_widget_push_composite_child ();
1028 priv->vsb = gtk_vscrollbar_new (adj);
1029 gtk_widget_set_composite_name (priv->vsb, "vscrollbar");
1030 gtk_widget_pop_composite_child ();
1031
1032 gtk_widget_set_parent (priv->vsb, GTK_WIDGET (sf));
1033 gtk_widget_ref (priv->vsb);
1034 gtk_widget_show (priv->vsb);
1035 } else {
1036 GtkAdjustment *old_adj;
1037
1038 old_adj = gtk_range_get_adjustment (GTK_RANGE (priv->vsb));
1039 if (old_adj == adj)
1040 return;
1041
1042 gtk_signal_disconnect_by_func (GTK_OBJECT (old_adj),
1043 GTK_SIGNAL_FUNC (adjustment_changed),
1044 sf);
1045 gtk_range_set_adjustment (GTK_RANGE (priv->vsb), adj);
1046 }
1047
1048 adj = gtk_range_get_adjustment (GTK_RANGE (priv->vsb));
1049 gtk_signal_connect (GTK_OBJECT (adj),
1050 "changed",
1051 GTK_SIGNAL_FUNC (adjustment_changed),
1052 sf);
1053 adjustment_changed (adj, sf);
1054
1055 if (GTK_BIN (sf)->child)
1056 gtk_widget_set_scroll_adjustments (
1057 GTK_BIN (sf)->child,
1058 gtk_range_get_adjustment (GTK_RANGE (priv->hsb)),
1059 gtk_range_get_adjustment (GTK_RANGE (priv->vsb)));
1060 }
1061
1062 /**
1063 * gtk_scroll_frame_get_hadjustment:
1064 * @sf: A scroll frame widget.
1065 *
1066 * Queries the horizontal adjustment of a scroll frame widget.
1067 *
1068 * Return value: The horizontal adjustment of the scroll frame, or NULL if none.
1069 **/
1070 GtkAdjustment *
gtk_scroll_frame_get_hadjustment(GtkScrollFrame * sf)1071 gtk_scroll_frame_get_hadjustment (GtkScrollFrame *sf)
1072 {
1073 ScrollFramePrivate *priv;
1074
1075 g_return_val_if_fail (sf != NULL, NULL);
1076 g_return_val_if_fail (GTK_IS_SCROLL_FRAME (sf), NULL);
1077
1078 priv = sf->priv;
1079
1080 return priv->hsb ? gtk_range_get_adjustment (GTK_RANGE (priv->hsb)) : NULL;
1081 }
1082
1083 /**
1084 * gtk_scroll_frame_get_vadjustment:
1085 * @sf: A scroll frame widget.
1086 *
1087 * Queries the vertical adjustment of a scroll frame widget.
1088 *
1089 * Return value: The vertical adjustment of the scroll frame, or NULL if none.
1090 **/
1091 GtkAdjustment *
gtk_scroll_frame_get_vadjustment(GtkScrollFrame * sf)1092 gtk_scroll_frame_get_vadjustment (GtkScrollFrame *sf)
1093 {
1094 ScrollFramePrivate *priv;
1095
1096 g_return_val_if_fail (sf != NULL, NULL);
1097 g_return_val_if_fail (GTK_IS_SCROLL_FRAME (sf), NULL);
1098
1099 priv = sf->priv;
1100
1101 return priv->vsb ? gtk_range_get_adjustment (GTK_RANGE (priv->vsb)) : NULL;
1102 }
1103
1104 /**
1105 * gtk_scroll_frame_set_policy:
1106 * @sf: A scroll frame widget.
1107 * @hsb_policy: Policy for the horizontal scrollbar.
1108 * @vsb_policy: Policy for the vertical scrollbar.
1109 *
1110 * Sets the scrollbar policies of a scroll frame widget. These determine when
1111 * the scrollbars are to be shown or hidden.
1112 **/
1113 void
gtk_scroll_frame_set_policy(GtkScrollFrame * sf,GtkPolicyType hsb_policy,GtkPolicyType vsb_policy)1114 gtk_scroll_frame_set_policy (GtkScrollFrame *sf,
1115 GtkPolicyType hsb_policy,
1116 GtkPolicyType vsb_policy)
1117 {
1118 ScrollFramePrivate *priv;
1119
1120 g_return_if_fail (sf != NULL);
1121 g_return_if_fail (GTK_IS_SCROLL_FRAME (sf));
1122
1123 priv = sf->priv;
1124
1125 if (priv->hsb_policy == hsb_policy && priv->vsb_policy == vsb_policy)
1126 return;
1127
1128 priv->hsb_policy = hsb_policy;
1129 priv->vsb_policy = vsb_policy;
1130
1131 gtk_widget_queue_resize (GTK_WIDGET (sf));
1132 }
1133
1134 /**
1135 * gtk_scroll_frame_get_policy:
1136 * @sf: A scroll frame widget.
1137 * @hsb_policy: Return value for the horizontal scrollbar's policy.
1138 * @vsb_policy: Return value for the vertical scrollbar's policy.
1139 *
1140 * Queries the scrollbar policies of a scroll frame widget.
1141 **/
1142 void
gtk_scroll_frame_get_policy(GtkScrollFrame * sf,GtkPolicyType * hsb_policy,GtkPolicyType * vsb_policy)1143 gtk_scroll_frame_get_policy (GtkScrollFrame *sf,
1144 GtkPolicyType *hsb_policy,
1145 GtkPolicyType *vsb_policy)
1146 {
1147 ScrollFramePrivate *priv;
1148
1149 g_return_if_fail (sf != NULL);
1150 g_return_if_fail (GTK_IS_SCROLL_FRAME (sf));
1151
1152 priv = sf->priv;
1153
1154 if (hsb_policy)
1155 *hsb_policy = priv->hsb_policy;
1156
1157 if (vsb_policy)
1158 *vsb_policy = priv->vsb_policy;
1159 }
1160
1161 /**
1162 * gtk_scroll_frame_set_placement:
1163 * @sf: A scroll frame widget.
1164 * @frame_placement: Placement for the frame.
1165 *
1166 * Sets the placement of a scroll frame widget's frame with respect to its
1167 * scrollbars.
1168 **/
1169 void
gtk_scroll_frame_set_placement(GtkScrollFrame * sf,GtkCornerType frame_placement)1170 gtk_scroll_frame_set_placement (GtkScrollFrame *sf, GtkCornerType frame_placement)
1171 {
1172 ScrollFramePrivate *priv;
1173
1174 g_return_if_fail (sf != NULL);
1175 g_return_if_fail (GTK_IS_SCROLL_FRAME (sf));
1176
1177 priv = sf->priv;
1178
1179 if (priv->frame_placement == frame_placement)
1180 return;
1181
1182 priv->frame_placement = frame_placement;
1183 gtk_widget_queue_resize (GTK_WIDGET (sf));
1184 }
1185
1186 /**
1187 * gtk_scroll_frame_set_shadow_type:
1188 * @sf: A scroll frame widget.
1189 * @shadow_type: A shadow type.
1190 *
1191 * Sets the shadow type of a scroll frame widget. You can use this when you
1192 * insert a child that does not paint a frame on its own.
1193 **/
1194 void
gtk_scroll_frame_set_shadow_type(GtkScrollFrame * sf,GtkShadowType shadow_type)1195 gtk_scroll_frame_set_shadow_type (GtkScrollFrame *sf, GtkShadowType shadow_type)
1196 {
1197 ScrollFramePrivate *priv;
1198
1199 g_return_if_fail (sf != NULL);
1200 g_return_if_fail (GTK_IS_SCROLL_FRAME (sf));
1201 g_return_if_fail (shadow_type >= GTK_SHADOW_NONE && shadow_type <= GTK_SHADOW_ETCHED_OUT);
1202
1203 priv = sf->priv;
1204
1205 if (priv->shadow_type == shadow_type)
1206 return;
1207
1208 priv->shadow_type = shadow_type;
1209 gtk_widget_queue_resize (GTK_WIDGET (sf));
1210 }
1211
1212 /**
1213 * gtk_scroll_frame_get_shadow_type:
1214 * @sf: A scroll frame widget.
1215 *
1216 * Queries the shadow type of a scroll frame widget.
1217 *
1218 * Return value: Shadow type.
1219 **/
1220 GtkShadowType
gtk_scroll_frame_get_shadow_type(GtkScrollFrame * sf)1221 gtk_scroll_frame_get_shadow_type (GtkScrollFrame *sf)
1222 {
1223 ScrollFramePrivate *priv;
1224
1225 g_return_val_if_fail (sf != NULL, GTK_SHADOW_NONE);
1226 g_return_val_if_fail (GTK_IS_SCROLL_FRAME (sf), GTK_SHADOW_NONE);
1227
1228 priv = sf->priv;
1229
1230 return priv->shadow_type;
1231 }
1232
1233 /**
1234 * gtk_scroll_frame_set_scrollbar_spacing:
1235 * @sf: A scroll frame widget.
1236 * @spacing: Desired spacing in pixels.
1237 *
1238 * Sets the spacing between the frame and the scrollbars of a scroll frame
1239 * widget.
1240 **/
1241 void
gtk_scroll_frame_set_scrollbar_spacing(GtkScrollFrame * sf,guint spacing)1242 gtk_scroll_frame_set_scrollbar_spacing (GtkScrollFrame *sf, guint spacing)
1243 {
1244 ScrollFramePrivate *priv;
1245
1246 g_return_if_fail (sf != NULL);
1247 g_return_if_fail (GTK_IS_SCROLL_FRAME (sf));
1248
1249 priv = sf->priv;
1250
1251 if (priv->sb_spacing == spacing)
1252 return;
1253
1254 priv->sb_spacing = spacing;
1255 gtk_widget_queue_resize (GTK_WIDGET (sf));
1256 }
1257
1258 /**
1259 * gtk_scroll_frame_add_with_viewport:
1260 * @sf: A scroll frame widget.
1261 * @child: A widget.
1262 *
1263 * Creates a #GtkViewport and puts the specified child inside it, thus allowing
1264 * the viewport to be scrolled by the scroll frame widget. This is meant to be
1265 * used only when a child does not support the scrolling interface.
1266 **/
1267 void
gtk_scroll_frame_add_with_viewport(GtkScrollFrame * sf,GtkWidget * child)1268 gtk_scroll_frame_add_with_viewport (GtkScrollFrame *sf, GtkWidget *child)
1269 {
1270 ScrollFramePrivate *priv;
1271 GtkBin *bin;
1272 GtkWidget *viewport;
1273
1274 g_return_if_fail (sf != NULL);
1275 g_return_if_fail (GTK_IS_SCROLL_FRAME (sf));
1276 g_return_if_fail (child != NULL);
1277 g_return_if_fail (GTK_IS_WIDGET (child));
1278 g_return_if_fail (child->parent == NULL);
1279
1280 priv = sf->priv;
1281 bin = GTK_BIN (sf);
1282
1283 if (bin->child != NULL) {
1284 g_return_if_fail (GTK_IS_VIEWPORT (bin->child));
1285 g_return_if_fail (GTK_BIN (bin->child)->child == NULL);
1286
1287 viewport = bin->child;
1288 } else {
1289 viewport = gtk_viewport_new (gtk_scroll_frame_get_hadjustment (sf),
1290 gtk_scroll_frame_get_vadjustment (sf));
1291 gtk_container_add (GTK_CONTAINER (sf), viewport);
1292 }
1293
1294 gtk_widget_show (viewport);
1295 gtk_container_add (GTK_CONTAINER (viewport), child);
1296 }
1297