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