source: trunk/third/gtk/gtk/gtkscrolledwindow.c @ 14482

Revision 14482, 32.2 KB checked in by ghudson, 25 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r14481, which included commits to RCS files with non-trunk default branches.
Line 
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#include "gtkscrolledwindow.h"
28#include "gtksignal.h"
29
30
31/* scrolled window policy and size requisition handling:
32 *
33 * gtk size requisition works as follows:
34 *   a widget upon size-request reports the width and height that it finds
35 *   to be best suited to display its contents, including children.
36 *   the width and/or height reported from a widget upon size requisition
37 *   may be overidden by the user by specifying a width and/or height
38 *   other than 0 through gtk_widget_set_usize().
39 *
40 * a scrolled window needs (for imlementing all three policy types) to
41 * request its width and height based on two different rationales.
42 * 1)   the user wants the scrolled window to just fit into the space
43 *      that it gets allocated for a specifc dimension.
44 * 1.1) this does not apply if the user specified a concrete value
45 *      value for that specific dimension by either specifying usize for the
46 *      scrolled window or for its child.
47 * 2)   the user wants the scrolled window to take as much space up as
48 *      is desired by the child for a specifc dimension (i.e. POLICY_NEVER).
49 *
50 * also, kinda obvious:
51 * 3)   a user would certainly not have choosen a scrolled window as a container
52 *      for the child, if the resulting allocation takes up more space than the
53 *      child would have allocated without the scrolled window.
54 *
55 * conclusions:
56 * A) from 1) follows: the scrolled window shouldn't request more space for a
57 *    specifc dimension than is required at minimum.
58 * B) from 1.1) follows: the requisition may be overidden by usize of the scrolled
59 *    window (done automatically) or by usize of the child (needs to be checked).
60 * C) from 2) follows: for POLICY_NEVER, the scrolled window simply reports the
61 *    child's dimension.
62 * D) from 3) follows: the scrolled window child's minimum width and minimum height
63 *    under A) at least correspond to the space taken up by its scrollbars.
64 */
65
66#define SCROLLBAR_SPACING(w) (GTK_SCROLLED_WINDOW_CLASS (GTK_OBJECT (w)->klass)->scrollbar_spacing)
67
68#define DEFAULT_SCROLLBAR_SPACING  3
69
70enum {
71  ARG_0,
72  ARG_HADJUSTMENT,
73  ARG_VADJUSTMENT,
74  ARG_HSCROLLBAR_POLICY,
75  ARG_VSCROLLBAR_POLICY,
76  ARG_WINDOW_PLACEMENT
77};
78
79
80static void gtk_scrolled_window_class_init         (GtkScrolledWindowClass *klass);
81static void gtk_scrolled_window_init               (GtkScrolledWindow      *scrolled_window);
82static void gtk_scrolled_window_set_arg            (GtkObject              *object,
83                                                    GtkArg                 *arg,
84                                                    guint                   arg_id);
85static void gtk_scrolled_window_get_arg            (GtkObject              *object,
86                                                    GtkArg                 *arg,
87                                                    guint                   arg_id);
88static void gtk_scrolled_window_destroy            (GtkObject              *object);
89static void gtk_scrolled_window_finalize           (GtkObject              *object);
90static void gtk_scrolled_window_map                (GtkWidget              *widget);
91static void gtk_scrolled_window_unmap              (GtkWidget              *widget);
92static void gtk_scrolled_window_draw               (GtkWidget              *widget,
93                                                    GdkRectangle           *area);
94static void gtk_scrolled_window_size_request       (GtkWidget              *widget,
95                                                    GtkRequisition         *requisition);
96static void gtk_scrolled_window_size_allocate      (GtkWidget              *widget,
97                                                    GtkAllocation          *allocation);
98static void gtk_scrolled_window_add                (GtkContainer           *container,
99                                                    GtkWidget              *widget);
100static void gtk_scrolled_window_remove             (GtkContainer           *container,
101                                                    GtkWidget              *widget);
102static void gtk_scrolled_window_forall             (GtkContainer           *container,
103                                                    gboolean                include_internals,
104                                                    GtkCallback             callback,
105                                                    gpointer                callback_data);
106static void gtk_scrolled_window_relative_allocation(GtkWidget              *widget,
107                                                    GtkAllocation          *allocation);
108static void gtk_scrolled_window_adjustment_changed (GtkAdjustment          *adjustment,
109                                                    gpointer                data);
110
111
112static GtkContainerClass *parent_class = NULL;
113
114
115GtkType
116gtk_scrolled_window_get_type (void)
117{
118  static GtkType scrolled_window_type = 0;
119
120  if (!scrolled_window_type)
121    {
122      static const GtkTypeInfo scrolled_window_info =
123      {
124        "GtkScrolledWindow",
125        sizeof (GtkScrolledWindow),
126        sizeof (GtkScrolledWindowClass),
127        (GtkClassInitFunc) gtk_scrolled_window_class_init,
128        (GtkObjectInitFunc) gtk_scrolled_window_init,
129        /* reserved_1 */ NULL,
130        /* reserved_2 */ NULL,
131        (GtkClassInitFunc) NULL,
132      };
133
134      scrolled_window_type = gtk_type_unique (GTK_TYPE_BIN, &scrolled_window_info);
135    }
136
137  return scrolled_window_type;
138}
139
140static void
141gtk_scrolled_window_class_init (GtkScrolledWindowClass *class)
142{
143  GtkObjectClass *object_class;
144  GtkWidgetClass *widget_class;
145  GtkContainerClass *container_class;
146
147  object_class = (GtkObjectClass*) class;
148  widget_class = (GtkWidgetClass*) class;
149  container_class = (GtkContainerClass*) class;
150  parent_class = gtk_type_class (GTK_TYPE_BIN);
151
152  gtk_object_add_arg_type ("GtkScrolledWindow::hadjustment",
153                           GTK_TYPE_ADJUSTMENT,
154                           GTK_ARG_READWRITE | GTK_ARG_CONSTRUCT,
155                           ARG_HADJUSTMENT);
156  gtk_object_add_arg_type ("GtkScrolledWindow::vadjustment",
157                           GTK_TYPE_ADJUSTMENT,
158                           GTK_ARG_READWRITE | GTK_ARG_CONSTRUCT,
159                           ARG_VADJUSTMENT);
160  gtk_object_add_arg_type ("GtkScrolledWindow::hscrollbar_policy",
161                           GTK_TYPE_POLICY_TYPE,
162                           GTK_ARG_READWRITE,
163                           ARG_HSCROLLBAR_POLICY);
164  gtk_object_add_arg_type ("GtkScrolledWindow::vscrollbar_policy",
165                           GTK_TYPE_POLICY_TYPE,
166                           GTK_ARG_READWRITE,
167                           ARG_VSCROLLBAR_POLICY);
168  gtk_object_add_arg_type ("GtkScrolledWindow::window_placement",
169                           GTK_TYPE_CORNER_TYPE,
170                           GTK_ARG_READWRITE,
171                           ARG_WINDOW_PLACEMENT);
172
173  object_class->set_arg = gtk_scrolled_window_set_arg;
174  object_class->get_arg = gtk_scrolled_window_get_arg;
175  object_class->destroy = gtk_scrolled_window_destroy;
176  object_class->finalize = gtk_scrolled_window_finalize;
177
178  widget_class->map = gtk_scrolled_window_map;
179  widget_class->unmap = gtk_scrolled_window_unmap;
180  widget_class->draw = gtk_scrolled_window_draw;
181  widget_class->size_request = gtk_scrolled_window_size_request;
182  widget_class->size_allocate = gtk_scrolled_window_size_allocate;
183
184  container_class->add = gtk_scrolled_window_add;
185  container_class->remove = gtk_scrolled_window_remove;
186  container_class->forall = gtk_scrolled_window_forall;
187
188  class->scrollbar_spacing = DEFAULT_SCROLLBAR_SPACING;
189}
190
191static void
192gtk_scrolled_window_set_arg (GtkObject        *object,
193                             GtkArg           *arg,
194                             guint             arg_id)
195{
196  GtkScrolledWindow *scrolled_window;
197
198  scrolled_window = GTK_SCROLLED_WINDOW (object);
199
200  switch (arg_id)
201    {
202    case ARG_HADJUSTMENT:
203      gtk_scrolled_window_set_hadjustment (scrolled_window, GTK_VALUE_POINTER (*arg));
204      break;
205    case ARG_VADJUSTMENT:
206      gtk_scrolled_window_set_vadjustment (scrolled_window, GTK_VALUE_POINTER (*arg));
207      break;
208    case ARG_HSCROLLBAR_POLICY:
209      gtk_scrolled_window_set_policy (scrolled_window,
210                                      GTK_VALUE_ENUM (*arg),
211                                      scrolled_window->vscrollbar_policy);
212      break;
213    case ARG_VSCROLLBAR_POLICY:
214      gtk_scrolled_window_set_policy (scrolled_window,
215                                      scrolled_window->hscrollbar_policy,
216                                      GTK_VALUE_ENUM (*arg));
217      break;
218    case ARG_WINDOW_PLACEMENT:
219      gtk_scrolled_window_set_placement (scrolled_window,
220                                         GTK_VALUE_ENUM (*arg));
221      break;
222    default:
223      break;
224    }
225}
226
227static void
228gtk_scrolled_window_get_arg (GtkObject        *object,
229                             GtkArg           *arg,
230                             guint             arg_id)
231{
232  GtkScrolledWindow *scrolled_window;
233
234  scrolled_window = GTK_SCROLLED_WINDOW (object);
235
236  switch (arg_id)
237    {
238    case ARG_HADJUSTMENT:
239      GTK_VALUE_POINTER (*arg) = gtk_scrolled_window_get_hadjustment (scrolled_window);
240      break;
241    case ARG_VADJUSTMENT:
242      GTK_VALUE_POINTER (*arg) = gtk_scrolled_window_get_vadjustment (scrolled_window);
243      break;
244    case ARG_HSCROLLBAR_POLICY:
245      GTK_VALUE_ENUM (*arg) = scrolled_window->hscrollbar_policy;
246      break;
247    case ARG_VSCROLLBAR_POLICY:
248      GTK_VALUE_ENUM (*arg) = scrolled_window->vscrollbar_policy;
249      break;
250    case ARG_WINDOW_PLACEMENT:
251      GTK_VALUE_ENUM (*arg) = scrolled_window->window_placement;
252      break;
253    default:
254      arg->type = GTK_TYPE_INVALID;
255      break;
256    }
257}
258
259static void
260gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window)
261{
262  GTK_WIDGET_SET_FLAGS (scrolled_window, GTK_NO_WINDOW);
263
264  gtk_container_set_resize_mode (GTK_CONTAINER (scrolled_window), GTK_RESIZE_QUEUE);
265
266  scrolled_window->hscrollbar = NULL;
267  scrolled_window->vscrollbar = NULL;
268  scrolled_window->hscrollbar_policy = GTK_POLICY_ALWAYS;
269  scrolled_window->vscrollbar_policy = GTK_POLICY_ALWAYS;
270  scrolled_window->hscrollbar_visible = FALSE;
271  scrolled_window->vscrollbar_visible = FALSE;
272  scrolled_window->window_placement = GTK_CORNER_TOP_LEFT;
273}
274
275GtkWidget*
276gtk_scrolled_window_new (GtkAdjustment *hadjustment,
277                         GtkAdjustment *vadjustment)
278{
279  GtkWidget *scrolled_window;
280
281  if (hadjustment)
282    g_return_val_if_fail (GTK_IS_ADJUSTMENT (hadjustment), NULL);
283
284  if (vadjustment)
285    g_return_val_if_fail (GTK_IS_ADJUSTMENT (vadjustment), NULL);
286
287  scrolled_window = gtk_widget_new (GTK_TYPE_SCROLLED_WINDOW,
288                                    "hadjustment", hadjustment,
289                                    "vadjustment", vadjustment,
290                                    NULL);
291
292  return scrolled_window;
293}
294
295void
296gtk_scrolled_window_set_hadjustment (GtkScrolledWindow *scrolled_window,
297                                     GtkAdjustment     *hadjustment)
298{
299  GtkBin *bin;
300
301  g_return_if_fail (scrolled_window != NULL);
302  g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
303  if (hadjustment)
304    g_return_if_fail (GTK_IS_ADJUSTMENT (hadjustment));
305  else
306    hadjustment = (GtkAdjustment*) gtk_object_new (GTK_TYPE_ADJUSTMENT, NULL);
307
308  bin = GTK_BIN (scrolled_window);
309
310  if (!scrolled_window->hscrollbar)
311    {
312      gtk_widget_push_composite_child ();
313      scrolled_window->hscrollbar = gtk_hscrollbar_new (hadjustment);
314      gtk_widget_set_composite_name (scrolled_window->hscrollbar, "hscrollbar");
315      gtk_widget_pop_composite_child ();
316
317      gtk_widget_set_parent (scrolled_window->hscrollbar, GTK_WIDGET (scrolled_window));
318      gtk_widget_ref (scrolled_window->hscrollbar);
319      gtk_widget_show (scrolled_window->hscrollbar);
320    }
321  else
322    {
323      GtkAdjustment *old_adjustment;
324     
325      old_adjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
326      if (old_adjustment == hadjustment)
327        return;
328
329      gtk_signal_disconnect_by_func (GTK_OBJECT (old_adjustment),
330                                     GTK_SIGNAL_FUNC (gtk_scrolled_window_adjustment_changed),
331                                     scrolled_window);
332      gtk_range_set_adjustment (GTK_RANGE (scrolled_window->hscrollbar),
333                                hadjustment);
334    }
335  hadjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
336  gtk_signal_connect (GTK_OBJECT (hadjustment),
337                      "changed",
338                      GTK_SIGNAL_FUNC (gtk_scrolled_window_adjustment_changed),
339                      scrolled_window);
340  gtk_scrolled_window_adjustment_changed (hadjustment, scrolled_window);
341 
342  if (bin->child)
343    gtk_widget_set_scroll_adjustments (bin->child,
344                                       gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
345                                       gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)));
346}
347
348void
349gtk_scrolled_window_set_vadjustment (GtkScrolledWindow *scrolled_window,
350                                     GtkAdjustment     *vadjustment)
351{
352  GtkBin *bin;
353
354  g_return_if_fail (scrolled_window != NULL);
355  g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
356  if (vadjustment)
357    g_return_if_fail (GTK_IS_ADJUSTMENT (vadjustment));
358  else
359    vadjustment = (GtkAdjustment*) gtk_object_new (GTK_TYPE_ADJUSTMENT, NULL);
360
361  bin = GTK_BIN (scrolled_window);
362
363  if (!scrolled_window->vscrollbar)
364    {
365      gtk_widget_push_composite_child ();
366      scrolled_window->vscrollbar = gtk_vscrollbar_new (vadjustment);
367      gtk_widget_set_composite_name (scrolled_window->vscrollbar, "vscrollbar");
368      gtk_widget_pop_composite_child ();
369
370      gtk_widget_set_parent (scrolled_window->vscrollbar, GTK_WIDGET (scrolled_window));
371      gtk_widget_ref (scrolled_window->vscrollbar);
372      gtk_widget_show (scrolled_window->vscrollbar);
373    }
374  else
375    {
376      GtkAdjustment *old_adjustment;
377     
378      old_adjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
379      if (old_adjustment == vadjustment)
380        return;
381
382      gtk_signal_disconnect_by_func (GTK_OBJECT (old_adjustment),
383                                     GTK_SIGNAL_FUNC (gtk_scrolled_window_adjustment_changed),
384                                     scrolled_window);
385      gtk_range_set_adjustment (GTK_RANGE (scrolled_window->vscrollbar),
386                                vadjustment);
387    }
388  vadjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
389  gtk_signal_connect (GTK_OBJECT (vadjustment),
390                      "changed",
391                      GTK_SIGNAL_FUNC (gtk_scrolled_window_adjustment_changed),
392                      scrolled_window);
393  gtk_scrolled_window_adjustment_changed (vadjustment, scrolled_window);
394
395  if (bin->child)
396    gtk_widget_set_scroll_adjustments (bin->child,
397                                       gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
398                                       gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)));
399}
400
401GtkAdjustment*
402gtk_scrolled_window_get_hadjustment (GtkScrolledWindow *scrolled_window)
403{
404  g_return_val_if_fail (scrolled_window != NULL, NULL);
405  g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL);
406
407  return (scrolled_window->hscrollbar ?
408          gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)) :
409          NULL);
410}
411
412GtkAdjustment*
413gtk_scrolled_window_get_vadjustment (GtkScrolledWindow *scrolled_window)
414{
415  g_return_val_if_fail (scrolled_window != NULL, NULL);
416  g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL);
417
418  return (scrolled_window->vscrollbar ?
419          gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)) :
420          NULL);
421}
422
423void
424gtk_scrolled_window_set_policy (GtkScrolledWindow *scrolled_window,
425                                GtkPolicyType      hscrollbar_policy,
426                                GtkPolicyType      vscrollbar_policy)
427{
428  g_return_if_fail (scrolled_window != NULL);
429  g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
430
431  if ((scrolled_window->hscrollbar_policy != hscrollbar_policy) ||
432      (scrolled_window->vscrollbar_policy != vscrollbar_policy))
433    {
434      scrolled_window->hscrollbar_policy = hscrollbar_policy;
435      scrolled_window->vscrollbar_policy = vscrollbar_policy;
436
437      gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
438    }
439}
440
441void
442gtk_scrolled_window_set_placement (GtkScrolledWindow *scrolled_window,
443                                   GtkCornerType      window_placement)
444{
445  g_return_if_fail (scrolled_window != NULL);
446  g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
447
448  if (scrolled_window->window_placement != window_placement)
449    {
450      scrolled_window->window_placement = window_placement;
451
452      gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
453    }
454}
455
456static void
457gtk_scrolled_window_destroy (GtkObject *object)
458{
459  GtkScrolledWindow *scrolled_window;
460
461  g_return_if_fail (object != NULL);
462  g_return_if_fail (GTK_IS_SCROLLED_WINDOW (object));
463
464  scrolled_window = GTK_SCROLLED_WINDOW (object);
465
466  gtk_widget_unparent (scrolled_window->hscrollbar);
467  gtk_widget_unparent (scrolled_window->vscrollbar);
468  gtk_widget_destroy (scrolled_window->hscrollbar);
469  gtk_widget_destroy (scrolled_window->vscrollbar);
470
471  GTK_OBJECT_CLASS (parent_class)->destroy (object);
472}
473
474static void
475gtk_scrolled_window_finalize (GtkObject *object)
476{
477  GtkScrolledWindow *scrolled_window;
478
479  scrolled_window = GTK_SCROLLED_WINDOW (object);
480
481  gtk_widget_unref (scrolled_window->hscrollbar);
482  gtk_widget_unref (scrolled_window->vscrollbar);
483
484  GTK_OBJECT_CLASS (parent_class)->finalize (object);
485}
486
487static void
488gtk_scrolled_window_map (GtkWidget *widget)
489{
490  GtkScrolledWindow *scrolled_window;
491
492  g_return_if_fail (widget != NULL);
493  g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
494
495  scrolled_window = GTK_SCROLLED_WINDOW (widget);
496
497  /* chain parent class handler to map self and child */
498  GTK_WIDGET_CLASS (parent_class)->map (widget);
499 
500  if (GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar) &&
501      !GTK_WIDGET_MAPPED (scrolled_window->hscrollbar))
502    gtk_widget_map (scrolled_window->hscrollbar);
503 
504  if (GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar) &&
505      !GTK_WIDGET_MAPPED (scrolled_window->vscrollbar))
506    gtk_widget_map (scrolled_window->vscrollbar);
507}
508
509static void
510gtk_scrolled_window_unmap (GtkWidget *widget)
511{
512  GtkScrolledWindow *scrolled_window;
513
514  g_return_if_fail (widget != NULL);
515  g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
516
517  scrolled_window = GTK_SCROLLED_WINDOW (widget);
518
519  /* chain parent class handler to unmap self and child */
520  GTK_WIDGET_CLASS (parent_class)->unmap (widget);
521 
522  if (GTK_WIDGET_MAPPED (scrolled_window->hscrollbar))
523    gtk_widget_unmap (scrolled_window->hscrollbar);
524 
525  if (GTK_WIDGET_MAPPED (scrolled_window->vscrollbar))
526    gtk_widget_unmap (scrolled_window->vscrollbar);
527}
528
529static void
530gtk_scrolled_window_draw (GtkWidget    *widget,
531                          GdkRectangle *area)
532{
533  GtkScrolledWindow *scrolled_window;
534  GtkBin *bin;
535  GdkRectangle child_area;
536
537  g_return_if_fail (widget != NULL);
538  g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
539  g_return_if_fail (area != NULL);
540 
541  scrolled_window = GTK_SCROLLED_WINDOW (widget);
542  bin = GTK_BIN (widget);
543
544  if (bin->child && GTK_WIDGET_VISIBLE (bin->child) &&
545      gtk_widget_intersect (bin->child, area, &child_area))
546    gtk_widget_draw (bin->child, &child_area);
547 
548  if (GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar) &&
549      gtk_widget_intersect (scrolled_window->hscrollbar, area, &child_area))
550    gtk_widget_draw (scrolled_window->hscrollbar, &child_area);
551 
552  if (GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar) &&
553      gtk_widget_intersect (scrolled_window->vscrollbar, area, &child_area))
554    gtk_widget_draw (scrolled_window->vscrollbar, &child_area);
555}
556
557static void
558gtk_scrolled_window_forall (GtkContainer *container,
559                            gboolean      include_internals,
560                            GtkCallback   callback,
561                            gpointer      callback_data)
562{
563  g_return_if_fail (container != NULL);
564  g_return_if_fail (GTK_IS_SCROLLED_WINDOW (container));
565  g_return_if_fail (callback != NULL);
566
567  GTK_CONTAINER_CLASS (parent_class)->forall (container,
568                                              include_internals,
569                                              callback,
570                                              callback_data);
571  if (include_internals)
572    {
573      GtkScrolledWindow *scrolled_window;
574
575      scrolled_window = GTK_SCROLLED_WINDOW (container);
576     
577      if (scrolled_window->vscrollbar)
578        callback (scrolled_window->vscrollbar, callback_data);
579      if (scrolled_window->hscrollbar)
580        callback (scrolled_window->hscrollbar, callback_data);
581    }
582}
583
584static void
585gtk_scrolled_window_size_request (GtkWidget      *widget,
586                                  GtkRequisition *requisition)
587{
588  GtkScrolledWindow *scrolled_window;
589  GtkBin *bin;
590  gint extra_width;
591  gint extra_height;
592  GtkRequisition hscrollbar_requisition;
593  GtkRequisition vscrollbar_requisition;
594  GtkRequisition child_requisition;
595
596  g_return_if_fail (widget != NULL);
597  g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
598  g_return_if_fail (requisition != NULL);
599
600  scrolled_window = GTK_SCROLLED_WINDOW (widget);
601  bin = GTK_BIN (scrolled_window);
602
603  extra_width = 0;
604  extra_height = 0;
605  requisition->width = 0;
606  requisition->height = 0;
607 
608  gtk_widget_size_request (scrolled_window->hscrollbar,
609                           &hscrollbar_requisition);
610  gtk_widget_size_request (scrolled_window->vscrollbar,
611                           &vscrollbar_requisition);
612 
613  if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
614    {
615      static guint quark_aux_info = 0;
616
617      if (!quark_aux_info)
618        quark_aux_info = g_quark_from_static_string ("gtk-aux-info");
619
620      gtk_widget_size_request (bin->child, &child_requisition);
621
622      if (scrolled_window->hscrollbar_policy == GTK_POLICY_NEVER)
623        requisition->width += child_requisition.width;
624      else
625        {
626          GtkWidgetAuxInfo *aux_info;
627
628          aux_info = gtk_object_get_data_by_id (GTK_OBJECT (bin->child), quark_aux_info);
629          if (aux_info && aux_info->width > 0)
630            {
631              requisition->width += aux_info->width;
632              extra_width = -1;
633            }
634          else
635            requisition->width += vscrollbar_requisition.width;
636        }
637
638      if (scrolled_window->vscrollbar_policy == GTK_POLICY_NEVER)
639        requisition->height += child_requisition.height;
640      else
641        {
642          GtkWidgetAuxInfo *aux_info;
643
644          aux_info = gtk_object_get_data_by_id (GTK_OBJECT (bin->child), quark_aux_info);
645          if (aux_info && aux_info->height > 0)
646            {
647              requisition->height += aux_info->height;
648              extra_height = -1;
649            }
650          else
651            requisition->height += hscrollbar_requisition.height;
652        }
653    }
654
655  if (scrolled_window->hscrollbar_policy == GTK_POLICY_AUTOMATIC ||
656      scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
657    {
658      requisition->width = MAX (requisition->width, hscrollbar_requisition.width);
659      if (!extra_height || scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
660        extra_height = SCROLLBAR_SPACING (scrolled_window) + hscrollbar_requisition.height;
661    }
662
663  if (scrolled_window->vscrollbar_policy == GTK_POLICY_AUTOMATIC ||
664      scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
665    {
666      requisition->height = MAX (requisition->height, vscrollbar_requisition.height);
667      if (!extra_height || scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
668        extra_width = SCROLLBAR_SPACING (scrolled_window) + vscrollbar_requisition.width;
669    }
670
671  requisition->width += GTK_CONTAINER (widget)->border_width * 2 + MAX (0, extra_width);
672  requisition->height += GTK_CONTAINER (widget)->border_width * 2 + MAX (0, extra_height);
673}
674
675static void
676gtk_scrolled_window_relative_allocation (GtkWidget     *widget,
677                                         GtkAllocation *allocation)
678{
679  GtkScrolledWindow *scrolled_window;
680
681  g_return_if_fail (widget != NULL);
682  g_return_if_fail (allocation != NULL);
683
684  scrolled_window = GTK_SCROLLED_WINDOW (widget);
685
686  allocation->x = GTK_CONTAINER (widget)->border_width;
687  allocation->y = GTK_CONTAINER (widget)->border_width;
688  allocation->width = MAX (1, (gint)widget->allocation.width - allocation->x * 2);
689  allocation->height = MAX (1, (gint)widget->allocation.height - allocation->y * 2);
690
691  if (scrolled_window->vscrollbar_visible)
692    {
693      GtkRequisition vscrollbar_requisition;
694      gtk_widget_get_child_requisition (scrolled_window->vscrollbar,
695                                        &vscrollbar_requisition);
696 
697      if (scrolled_window->window_placement == GTK_CORNER_TOP_RIGHT ||
698          scrolled_window->window_placement == GTK_CORNER_BOTTOM_RIGHT)
699        allocation->x += (vscrollbar_requisition.width +
700                          SCROLLBAR_SPACING (scrolled_window));
701
702      allocation->width = MAX (1, (gint)allocation->width -
703                               ((gint)vscrollbar_requisition.width +
704                                (gint)SCROLLBAR_SPACING (scrolled_window)));
705    }
706  if (scrolled_window->hscrollbar_visible)
707    {
708      GtkRequisition hscrollbar_requisition;
709      gtk_widget_get_child_requisition (scrolled_window->hscrollbar,
710                                        &hscrollbar_requisition);
711 
712      if (scrolled_window->window_placement == GTK_CORNER_BOTTOM_LEFT ||
713          scrolled_window->window_placement == GTK_CORNER_BOTTOM_RIGHT)
714        allocation->y += (hscrollbar_requisition.height +
715                          SCROLLBAR_SPACING (scrolled_window));
716
717      allocation->height = MAX (1, (gint)allocation->height -
718                                ((gint)hscrollbar_requisition.height +
719                                 (gint)SCROLLBAR_SPACING (scrolled_window)));
720    }
721}
722
723static void
724gtk_scrolled_window_size_allocate (GtkWidget     *widget,
725                                   GtkAllocation *allocation)
726{
727  GtkScrolledWindow *scrolled_window;
728  GtkBin *bin;
729  GtkAllocation relative_allocation;
730  GtkAllocation child_allocation;
731 
732  g_return_if_fail (widget != NULL);
733  g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
734  g_return_if_fail (allocation != NULL);
735
736  scrolled_window = GTK_SCROLLED_WINDOW (widget);
737  bin = GTK_BIN (scrolled_window);
738
739  widget->allocation = *allocation;
740
741  if (scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
742    scrolled_window->hscrollbar_visible = TRUE;
743  else if (scrolled_window->hscrollbar_policy == GTK_POLICY_NEVER)
744    scrolled_window->hscrollbar_visible = FALSE;
745  if (scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
746    scrolled_window->vscrollbar_visible = TRUE;
747  else if (scrolled_window->vscrollbar_policy == GTK_POLICY_NEVER)
748    scrolled_window->vscrollbar_visible = FALSE;
749
750  if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
751    {
752      gboolean previous_hvis;
753      gboolean previous_vvis;
754      guint count = 0;
755     
756      do
757        {
758          gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
759         
760          child_allocation.x = relative_allocation.x + allocation->x;
761          child_allocation.y = relative_allocation.y + allocation->y;
762          child_allocation.width = relative_allocation.width;
763          child_allocation.height = relative_allocation.height;
764         
765          previous_hvis = scrolled_window->hscrollbar_visible;
766          previous_vvis = scrolled_window->vscrollbar_visible;
767         
768          gtk_widget_size_allocate (bin->child, &child_allocation);
769
770          /* If, after the first iteration, the hscrollbar and the
771           * vscrollbar flip visiblity, then we need both.
772           */
773          if (count &&
774              previous_hvis != scrolled_window->hscrollbar_visible &&
775              previous_vvis != scrolled_window->vscrollbar_visible)
776            {
777              scrolled_window->hscrollbar_visible = TRUE;
778              scrolled_window->vscrollbar_visible = TRUE;
779
780              /* a new resize is already queued at this point,
781               * so we will immediatedly get reinvoked
782               */
783              return;
784            }
785         
786          count++;
787        }
788      while (previous_hvis != scrolled_window->hscrollbar_visible ||
789             previous_vvis != scrolled_window->vscrollbar_visible);
790    }
791  else
792    gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
793 
794  if (scrolled_window->hscrollbar_visible)
795    {
796      GtkRequisition hscrollbar_requisition;
797      gtk_widget_get_child_requisition (scrolled_window->hscrollbar,
798                                        &hscrollbar_requisition);
799 
800      if (!GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar))
801        gtk_widget_show (scrolled_window->hscrollbar);
802
803      child_allocation.x = relative_allocation.x;
804      if (scrolled_window->window_placement == GTK_CORNER_TOP_LEFT ||
805          scrolled_window->window_placement == GTK_CORNER_TOP_RIGHT)
806        child_allocation.y = (relative_allocation.y +
807                              relative_allocation.height +
808                              SCROLLBAR_SPACING (scrolled_window));
809      else
810        child_allocation.y = GTK_CONTAINER (scrolled_window)->border_width;
811
812      child_allocation.width = relative_allocation.width;
813      child_allocation.height = hscrollbar_requisition.height;
814      child_allocation.x += allocation->x;
815      child_allocation.y += allocation->y;
816
817      gtk_widget_size_allocate (scrolled_window->hscrollbar, &child_allocation);
818    }
819  else if (GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar))
820    gtk_widget_hide (scrolled_window->hscrollbar);
821
822  if (scrolled_window->vscrollbar_visible)
823    {
824      GtkRequisition vscrollbar_requisition;
825      if (!GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar))
826        gtk_widget_show (scrolled_window->vscrollbar);
827
828      gtk_widget_get_child_requisition (scrolled_window->vscrollbar,
829                                        &vscrollbar_requisition);
830
831      if (scrolled_window->window_placement == GTK_CORNER_TOP_LEFT ||
832          scrolled_window->window_placement == GTK_CORNER_BOTTOM_LEFT)
833        child_allocation.x = (relative_allocation.x +
834                              relative_allocation.width +
835                              SCROLLBAR_SPACING (scrolled_window));
836      else
837        child_allocation.x = GTK_CONTAINER (scrolled_window)->border_width;
838
839      child_allocation.y = relative_allocation.y;
840      child_allocation.width = vscrollbar_requisition.width;
841      child_allocation.height = relative_allocation.height;
842      child_allocation.x += allocation->x;
843      child_allocation.y += allocation->y;
844
845      gtk_widget_size_allocate (scrolled_window->vscrollbar, &child_allocation);
846    }
847  else if (GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar))
848    gtk_widget_hide (scrolled_window->vscrollbar);
849}
850
851
852static void
853gtk_scrolled_window_adjustment_changed (GtkAdjustment *adjustment,
854                                        gpointer       data)
855{
856  GtkScrolledWindow *scrolled_win;
857
858  g_return_if_fail (adjustment != NULL);
859  g_return_if_fail (data != NULL);
860
861  scrolled_win = GTK_SCROLLED_WINDOW (data);
862
863  if (adjustment == gtk_range_get_adjustment (GTK_RANGE (scrolled_win->hscrollbar)))
864    {
865      if (scrolled_win->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
866        {
867          gboolean visible;
868         
869          visible = scrolled_win->hscrollbar_visible;
870          scrolled_win->hscrollbar_visible = (adjustment->upper - adjustment->lower >
871                                              adjustment->page_size);
872          if (scrolled_win->hscrollbar_visible != visible)
873            gtk_widget_queue_resize (GTK_WIDGET (scrolled_win));
874        }
875    }
876  else if (adjustment == gtk_range_get_adjustment (GTK_RANGE (scrolled_win->vscrollbar)))
877    {
878      if (scrolled_win->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
879        {
880          gboolean visible;
881
882          visible = scrolled_win->vscrollbar_visible;
883          scrolled_win->vscrollbar_visible = (adjustment->upper - adjustment->lower >
884                                              adjustment->page_size);
885          if (scrolled_win->vscrollbar_visible != visible)
886            gtk_widget_queue_resize (GTK_WIDGET (scrolled_win));
887        }
888    }
889}
890
891static void
892gtk_scrolled_window_add (GtkContainer *container,
893                         GtkWidget    *child)
894{
895  GtkScrolledWindow *scrolled_window;
896  GtkBin *bin;
897
898  bin = GTK_BIN (container);
899  g_return_if_fail (bin->child == NULL);
900
901  scrolled_window = GTK_SCROLLED_WINDOW (container);
902
903  bin->child = child;
904  gtk_widget_set_parent (child, GTK_WIDGET (bin));
905
906  /* this is a temporary message */
907  if (!gtk_widget_set_scroll_adjustments (child,
908                                          gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
909                                          gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar))))
910    g_warning ("gtk_scrolled_window_add(): cannot add non scrollable widget "
911               "use gtk_scrolled_window_add_with_viewport() instead");
912
913  if (GTK_WIDGET_REALIZED (child->parent))
914    gtk_widget_realize (child);
915
916  if (GTK_WIDGET_VISIBLE (child->parent) && GTK_WIDGET_VISIBLE (child))
917    {
918      if (GTK_WIDGET_MAPPED (child->parent))
919        gtk_widget_map (child);
920
921      gtk_widget_queue_resize (child);
922    }
923}
924
925static void
926gtk_scrolled_window_remove (GtkContainer *container,
927                            GtkWidget    *child)
928{
929  g_return_if_fail (container != NULL);
930  g_return_if_fail (GTK_IS_SCROLLED_WINDOW (container));
931  g_return_if_fail (child != NULL);
932  g_return_if_fail (GTK_BIN (container)->child == child);
933 
934  gtk_widget_set_scroll_adjustments (child, NULL, NULL);
935
936  /* chain parent class handler to remove child */
937  GTK_CONTAINER_CLASS (parent_class)->remove (container, child);
938}
939
940void
941gtk_scrolled_window_add_with_viewport (GtkScrolledWindow *scrolled_window,
942                                       GtkWidget         *child)
943{
944  GtkBin *bin;
945  GtkWidget *viewport;
946
947  g_return_if_fail (scrolled_window != NULL);
948  g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
949  g_return_if_fail (child != NULL);
950  g_return_if_fail (GTK_IS_WIDGET (child));
951  g_return_if_fail (child->parent == NULL);
952
953  bin = GTK_BIN (scrolled_window);
954
955  if (bin->child != NULL)
956    {
957      g_return_if_fail (GTK_IS_VIEWPORT (bin->child));
958      g_return_if_fail (GTK_BIN (bin->child)->child == NULL);
959
960      viewport = bin->child;
961    }
962  else
963    {
964      viewport =
965        gtk_viewport_new (gtk_scrolled_window_get_hadjustment (scrolled_window),
966                          gtk_scrolled_window_get_vadjustment (scrolled_window));
967      gtk_container_add (GTK_CONTAINER (scrolled_window), viewport);
968    }
969
970  gtk_widget_show (viewport);
971  gtk_container_add (GTK_CONTAINER (viewport), child);
972}
Note: See TracBrowser for help on using the repository browser.