~canonical-dx-team/ubuntu/maverick/gtk+2.0/menuproxy

« back to all changes in this revision

Viewing changes to gtk/gtkcontainer.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2007-05-04 12:24:25 UTC
  • mfrom: (1.1.21 upstream)
  • Revision ID: james.westby@ubuntu.com-20070504122425-0m8midgzrp40y8w2
Tags: 2.10.12-1ubuntu1
* Sync with Debian
* New upstream version:
  Fixed bugs:
  - 379414 file chooser warnings when changing path in the entry
  - 418585 GtkFileChooserDefault sizing code is not DPI independent
  - 419568 Crash in search if start with special letter
  - 435062 build dies with icon cache validation
  - 379399 Segfault to call gtk_print_operation_run twice.
  - 387889 cups backend has problems when there are too many printers
  - 418531 invalid read to gtkicontheme.c gtk_icon_theme_lookup_icon...
  - 423916 crash in color scheme code
  - 424042 Segmentation fault while quickly pressing Alt+arrows
  - 415260 Protect against negative indices when setting values in G...
  - 419171 XGetVisualInfo() may not set nxvisuals
  - 128852 Gdk cursors don't look good on win32
  - 344657 Ctrl-H doesn't toggle "Show Hidden Files" setting
  - 345345 PrintOperation::paginate is not emitted for class handler
  - 347567 GtkPrintOperation::end-print is not emitted if it's cance...
  - 369112 gtk_ui_manager_add_ui should accept unnamed separator
  - 392015 Selected menu item invisible on Windows Vista
  - 399253 MS-Windows Theme Bottom Tab placement rendering glitches
  - 399425 gtk_input_dialog_fill_axes() adds child to gtkscrolledwin...
  - 403251 [patch] little memory leak in GtkPrintJob
  - 403267 [patch] memory leak in GtkPageSetupUnixDialog
  - 403470 MS-Windows Theme tab placement other than on top leaks a ...
  - 404506 Windows system fonts that have multi-byte font names cann...
  - 405089 Incorrect window placement for GtkEventBox private window
  - 405515 Minor leak in gtkfilesystemmodel.c
  - 405539 gdk_pixbuf_save() for PNG saver can return FALSE without ...
  - 415681 gdk_window_clear_area includes an extra line and column o...
  - 418219 GtkRecentChooser should apply filter before sorting and c...
  - 418403 Scroll to printer after selecting it from settings
  - 421985 _gtk_print_operation_platform_backend_launch_preview
  - 421990 gtk_print_job_get_surface
  - 421993 gtk_print_operation_init
  - 423064 Conditional jump or move depends on uninitialised value(s...
  - 423722 Fix printing header in gtk-demo
  - 424168 gtk_print_operation_run on async preview
  - 425655 Don't install gtk+-unix-print-2.0.pc on non-UNIX platforms
  - 425786 GDK segfaults if XineramaQueryScreens fails
  - 428665 Lpr Backend gets stuck in infinite loop during gtk_enumer...
  - 429902 GtkPrintOperation leaks cairo contextes
  - 431997 First delay of GdkPixbufAnimationIter is wrong
  - 433242 Inconsistent scroll arrow position calculations
  - 433972 Placing gtk.Expander inside a gtk.TextView() changes gtk....
  - 434261 _gtk_toolbar_elide_underscores incorrectly handles some s...
  - 383354 ctrl-L should make 'Location' entry disappear
  - 418673 gtk_recent_manager_add_item
  - 429732 gtk_accel_group_finalize accesses invalid memory
  - 435028 WM_CLIENT_LEADER is wrong on the leader_window
  - 431067 Background of the header window is not updated
  - 338843 add recent files support inside the ui manager
  - 148535 add drop shadow to menus, tooltips, etc. under Windows XP
* debian/control.in:
  - Conflicts on ubuntulooks (<= 0.9.11-1)
* debian/patches/15_default-fallback-icon-theme.patch:
  - patch from Debian, fallback on gnome icon theme

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 Lesser General Public
 
6
 * License as published by the Free Software Foundation; either
 
7
 * version 2 of the License, or (at your option) any later version.
 
8
 *
 
9
 * This library is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
12
 * Lesser General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU Lesser General Public
 
15
 * License along with this library; if not, write to the
 
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-2000.  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 <config.h>
 
28
#include <stdarg.h>
 
29
#include <string.h>
 
30
#include <stdlib.h>
 
31
 
 
32
#include "gtkcontainer.h"
 
33
#include "gtkprivate.h"
 
34
#include "gtkmain.h"
 
35
#include "gtkmarshalers.h"
 
36
#include "gtkwindow.h"
 
37
#include "gtkintl.h"
 
38
#include "gtktoolbar.h"
 
39
#include <gobject/gobjectnotifyqueue.c>
 
40
#include <gobject/gvaluecollector.h>
 
41
#include "gtkalias.h"
 
42
 
 
43
 
 
44
enum {
 
45
  ADD,
 
46
  REMOVE,
 
47
  CHECK_RESIZE,
 
48
  SET_FOCUS_CHILD,
 
49
  LAST_SIGNAL
 
50
};
 
51
 
 
52
enum {
 
53
  PROP_0,
 
54
  PROP_BORDER_WIDTH,
 
55
  PROP_RESIZE_MODE,
 
56
  PROP_CHILD
 
57
};
 
58
 
 
59
#define PARAM_SPEC_PARAM_ID(pspec)              ((pspec)->param_id)
 
60
#define PARAM_SPEC_SET_PARAM_ID(pspec, id)      ((pspec)->param_id = (id))
 
61
 
 
62
 
 
63
/* --- prototypes --- */
 
64
static void     gtk_container_base_class_init      (GtkContainerClass *klass);
 
65
static void     gtk_container_base_class_finalize  (GtkContainerClass *klass);
 
66
static void     gtk_container_class_init           (GtkContainerClass *klass);
 
67
static void     gtk_container_init                 (GtkContainer      *container);
 
68
static void     gtk_container_destroy              (GtkObject         *object);
 
69
static void     gtk_container_set_property         (GObject         *object,
 
70
                                                    guint            prop_id,
 
71
                                                    const GValue    *value,
 
72
                                                    GParamSpec      *pspec);
 
73
static void     gtk_container_get_property         (GObject         *object,
 
74
                                                    guint            prop_id,
 
75
                                                    GValue          *value,
 
76
                                                    GParamSpec      *pspec);
 
77
static void     gtk_container_add_unimplemented    (GtkContainer      *container,
 
78
                                                    GtkWidget         *widget);
 
79
static void     gtk_container_remove_unimplemented (GtkContainer      *container,
 
80
                                                    GtkWidget         *widget);
 
81
static void     gtk_container_real_check_resize    (GtkContainer      *container);
 
82
static gboolean gtk_container_focus                (GtkWidget         *widget,
 
83
                                                    GtkDirectionType   direction);
 
84
static void     gtk_container_real_set_focus_child (GtkContainer      *container,
 
85
                                                    GtkWidget         *widget);
 
86
 
 
87
static gboolean gtk_container_focus_move           (GtkContainer      *container,
 
88
                                                    GList             *children,
 
89
                                                    GtkDirectionType   direction);
 
90
static void     gtk_container_children_callback    (GtkWidget         *widget,
 
91
                                                    gpointer           client_data);
 
92
static void     gtk_container_show_all             (GtkWidget         *widget);
 
93
static void     gtk_container_hide_all             (GtkWidget         *widget);
 
94
static gint     gtk_container_expose               (GtkWidget         *widget,
 
95
                                                    GdkEventExpose    *event);
 
96
static void     gtk_container_map                  (GtkWidget         *widget);
 
97
static void     gtk_container_unmap                (GtkWidget         *widget);
 
98
 
 
99
static gchar* gtk_container_child_default_composite_name (GtkContainer *container,
 
100
                                                          GtkWidget    *child);
 
101
 
 
102
 
 
103
/* --- variables --- */
 
104
static const gchar           vadjustment_key[] = "gtk-vadjustment";
 
105
static guint                 vadjustment_key_id = 0;
 
106
static const gchar           hadjustment_key[] = "gtk-hadjustment";
 
107
static guint                 hadjustment_key_id = 0;
 
108
static GSList               *container_resize_queue = NULL;
 
109
static guint                 container_signals[LAST_SIGNAL] = { 0 };
 
110
static GtkWidgetClass       *parent_class = NULL;
 
111
extern GParamSpecPool       *_gtk_widget_child_property_pool;
 
112
extern GObjectNotifyContext *_gtk_widget_child_property_notify_context;
 
113
 
 
114
 
 
115
/* --- functions --- */
 
116
GType
 
117
gtk_container_get_type (void)
 
118
{
 
119
  static GType container_type = 0;
 
120
 
 
121
  if (!container_type)
 
122
    {
 
123
      const GTypeInfo container_info =
 
124
      {
 
125
        sizeof (GtkContainerClass),
 
126
        (GBaseInitFunc) gtk_container_base_class_init,
 
127
        (GBaseFinalizeFunc) gtk_container_base_class_finalize,
 
128
        (GClassInitFunc) gtk_container_class_init,
 
129
        NULL        /* class_finalize */,
 
130
        NULL        /* class_data */,
 
131
        sizeof (GtkContainer),
 
132
        0           /* n_preallocs */,
 
133
        (GInstanceInitFunc) gtk_container_init,
 
134
        NULL,       /* value_table */
 
135
      };
 
136
 
 
137
      container_type =
 
138
        g_type_register_static (GTK_TYPE_WIDGET, I_("GtkContainer"), 
 
139
                                &container_info, G_TYPE_FLAG_ABSTRACT);
 
140
    }
 
141
 
 
142
  return container_type;
 
143
}
 
144
 
 
145
static void
 
146
gtk_container_base_class_init (GtkContainerClass *class)
 
147
{
 
148
  /* reset instance specifc class fields that don't get inherited */
 
149
  class->set_child_property = NULL;
 
150
  class->get_child_property = NULL;
 
151
}
 
152
 
 
153
static void
 
154
gtk_container_base_class_finalize (GtkContainerClass *class)
 
155
{
 
156
  GList *list, *node;
 
157
 
 
158
  list = g_param_spec_pool_list_owned (_gtk_widget_child_property_pool, G_OBJECT_CLASS_TYPE (class));
 
159
  for (node = list; node; node = node->next)
 
160
    {
 
161
      GParamSpec *pspec = node->data;
 
162
 
 
163
      g_param_spec_pool_remove (_gtk_widget_child_property_pool, pspec);
 
164
      PARAM_SPEC_SET_PARAM_ID (pspec, 0);
 
165
      g_param_spec_unref (pspec);
 
166
    }
 
167
  g_list_free (list);
 
168
}
 
169
 
 
170
static void
 
171
gtk_container_class_init (GtkContainerClass *class)
 
172
{
 
173
  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
 
174
  GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
 
175
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
 
176
 
 
177
  parent_class = g_type_class_peek_parent (class);
 
178
 
 
179
  vadjustment_key_id = g_quark_from_static_string (vadjustment_key);
 
180
  hadjustment_key_id = g_quark_from_static_string (hadjustment_key);
 
181
  
 
182
  gobject_class->set_property = gtk_container_set_property;
 
183
  gobject_class->get_property = gtk_container_get_property;
 
184
 
 
185
  object_class->destroy = gtk_container_destroy;
 
186
 
 
187
  widget_class->show_all = gtk_container_show_all;
 
188
  widget_class->hide_all = gtk_container_hide_all;
 
189
  widget_class->expose_event = gtk_container_expose;
 
190
  widget_class->map = gtk_container_map;
 
191
  widget_class->unmap = gtk_container_unmap;
 
192
  widget_class->focus = gtk_container_focus;
 
193
  
 
194
  class->add = gtk_container_add_unimplemented;
 
195
  class->remove = gtk_container_remove_unimplemented;
 
196
  class->check_resize = gtk_container_real_check_resize;
 
197
  class->forall = NULL;
 
198
  class->set_focus_child = gtk_container_real_set_focus_child;
 
199
  class->child_type = NULL;
 
200
  class->composite_name = gtk_container_child_default_composite_name;
 
201
 
 
202
  g_object_class_install_property (gobject_class,
 
203
                                   PROP_RESIZE_MODE,
 
204
                                   g_param_spec_enum ("resize-mode",
 
205
                                                      P_("Resize mode"),
 
206
                                                      P_("Specify how resize events are handled"),
 
207
                                                      GTK_TYPE_RESIZE_MODE,
 
208
                                                      GTK_RESIZE_PARENT,
 
209
                                                      GTK_PARAM_READWRITE));
 
210
  g_object_class_install_property (gobject_class,
 
211
                                   PROP_BORDER_WIDTH,
 
212
                                   g_param_spec_uint ("border-width",
 
213
                                                      P_("Border width"),
 
214
                                                      P_("The width of the empty border outside the containers children"),
 
215
                                                      0,
 
216
                                                      G_MAXINT,
 
217
                                                      0,
 
218
                                                      GTK_PARAM_READWRITE));
 
219
  g_object_class_install_property (gobject_class,
 
220
                                   PROP_CHILD,
 
221
                                   g_param_spec_object ("child",
 
222
                                                      P_("Child"),
 
223
                                                      P_("Can be used to add a new child to the container"),
 
224
                                                      GTK_TYPE_WIDGET,
 
225
                                                      GTK_PARAM_WRITABLE));
 
226
  container_signals[ADD] =
 
227
    g_signal_new (I_("add"),
 
228
                  G_OBJECT_CLASS_TYPE (object_class),
 
229
                  G_SIGNAL_RUN_FIRST,
 
230
                  G_STRUCT_OFFSET (GtkContainerClass, add),
 
231
                  NULL, NULL,
 
232
                  _gtk_marshal_VOID__OBJECT,
 
233
                  G_TYPE_NONE, 1,
 
234
                  GTK_TYPE_WIDGET);
 
235
  container_signals[REMOVE] =
 
236
    g_signal_new (I_("remove"),
 
237
                  G_OBJECT_CLASS_TYPE (object_class),
 
238
                  G_SIGNAL_RUN_FIRST,
 
239
                  G_STRUCT_OFFSET (GtkContainerClass, remove),
 
240
                  NULL, NULL,
 
241
                  _gtk_marshal_VOID__OBJECT,
 
242
                  G_TYPE_NONE, 1,
 
243
                  GTK_TYPE_WIDGET);
 
244
  container_signals[CHECK_RESIZE] =
 
245
    g_signal_new (I_("check_resize"),
 
246
                  G_OBJECT_CLASS_TYPE (object_class),
 
247
                  G_SIGNAL_RUN_LAST,
 
248
                  G_STRUCT_OFFSET (GtkContainerClass, check_resize),
 
249
                  NULL, NULL,
 
250
                  _gtk_marshal_VOID__VOID,
 
251
                  G_TYPE_NONE, 0);
 
252
  container_signals[SET_FOCUS_CHILD] =
 
253
    g_signal_new (I_("set-focus-child"),
 
254
                  G_OBJECT_CLASS_TYPE (object_class),
 
255
                  G_SIGNAL_RUN_FIRST,
 
256
                  G_STRUCT_OFFSET (GtkContainerClass, set_focus_child),
 
257
                  NULL, NULL,
 
258
                  _gtk_marshal_VOID__OBJECT,
 
259
                  G_TYPE_NONE, 1,
 
260
                  GTK_TYPE_WIDGET);
 
261
}
 
262
 
 
263
/**
 
264
 * gtk_container_child_type: 
 
265
 * @container: a #GtkContainer.
 
266
 *
 
267
 * Returns the type of the children supported by the container.
 
268
 *
 
269
 * Note that this may return %G_TYPE_NONE to indicate that no more
 
270
 * children can be added, e.g. for a #GtkPaned which already has two 
 
271
 * children.
 
272
 *
 
273
 * Return value: a #GType.
 
274
 **/
 
275
GType
 
276
gtk_container_child_type (GtkContainer *container)
 
277
{
 
278
  GType slot;
 
279
  GtkContainerClass *class;
 
280
 
 
281
  g_return_val_if_fail (GTK_IS_CONTAINER (container), 0);
 
282
 
 
283
  class = GTK_CONTAINER_GET_CLASS (container);
 
284
  if (class->child_type)
 
285
    slot = class->child_type (container);
 
286
  else
 
287
    slot = G_TYPE_NONE;
 
288
 
 
289
  return slot;
 
290
}
 
291
 
 
292
/* --- GtkContainer child property mechanism --- */
 
293
static inline void
 
294
container_get_child_property (GtkContainer *container,
 
295
                              GtkWidget    *child,
 
296
                              GParamSpec   *pspec,
 
297
                              GValue       *value)
 
298
{
 
299
  GtkContainerClass *class = g_type_class_peek (pspec->owner_type);
 
300
  
 
301
  class->get_child_property (container, child, PARAM_SPEC_PARAM_ID (pspec), value, pspec);
 
302
}
 
303
 
 
304
static inline void
 
305
container_set_child_property (GtkContainer       *container,
 
306
                              GtkWidget          *child,
 
307
                              GParamSpec         *pspec,
 
308
                              const GValue       *value,
 
309
                              GObjectNotifyQueue *nqueue)
 
310
{
 
311
  GValue tmp_value = { 0, };
 
312
  GtkContainerClass *class = g_type_class_peek (pspec->owner_type);
 
313
 
 
314
  /* provide a copy to work from, convert (if necessary) and validate */
 
315
  g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
 
316
  if (!g_value_transform (value, &tmp_value))
 
317
    g_warning ("unable to set child property `%s' of type `%s' from value of type `%s'",
 
318
               pspec->name,
 
319
               g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
 
320
               G_VALUE_TYPE_NAME (value));
 
321
  else if (g_param_value_validate (pspec, &tmp_value) && !(pspec->flags & G_PARAM_LAX_VALIDATION))
 
322
    {
 
323
      gchar *contents = g_strdup_value_contents (value);
 
324
 
 
325
      g_warning ("value \"%s\" of type `%s' is invalid for property `%s' of type `%s'",
 
326
                 contents,
 
327
                 G_VALUE_TYPE_NAME (value),
 
328
                 pspec->name,
 
329
                 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
 
330
      g_free (contents);
 
331
    }
 
332
  else
 
333
    {
 
334
      class->set_child_property (container, child, PARAM_SPEC_PARAM_ID (pspec), &tmp_value, pspec);
 
335
      g_object_notify_queue_add (G_OBJECT (child), nqueue, pspec);
 
336
    }
 
337
  g_value_unset (&tmp_value);
 
338
}
 
339
 
 
340
/**
 
341
 * gtk_container_child_get_valist:
 
342
 * @container: a #GtkContainer
 
343
 * @child: a widget which is a child of @container
 
344
 * @first_property_name: the name of the first property to get
 
345
 * @var_args: a %NULL-terminated list of property names and #GValue*, 
 
346
 *           starting with @first_prop_name.
 
347
 * 
 
348
 * Gets the values of one or more child properties for @child and @container.
 
349
 **/
 
350
void
 
351
gtk_container_child_get_valist (GtkContainer *container,
 
352
                                GtkWidget    *child,
 
353
                                const gchar  *first_property_name,
 
354
                                va_list       var_args)
 
355
{
 
356
  const gchar *name;
 
357
 
 
358
  g_return_if_fail (GTK_IS_CONTAINER (container));
 
359
  g_return_if_fail (GTK_IS_WIDGET (child));
 
360
  g_return_if_fail (child->parent == GTK_WIDGET (container));
 
361
 
 
362
  g_object_ref (container);
 
363
  g_object_ref (child);
 
364
 
 
365
  name = first_property_name;
 
366
  while (name)
 
367
    {
 
368
      GValue value = { 0, };
 
369
      GParamSpec *pspec;
 
370
      gchar *error;
 
371
 
 
372
      pspec = g_param_spec_pool_lookup (_gtk_widget_child_property_pool,
 
373
                                        name,
 
374
                                        G_OBJECT_TYPE (container),
 
375
                                        TRUE);
 
376
      if (!pspec)
 
377
        {
 
378
          g_warning ("%s: container class `%s' has no child property named `%s'",
 
379
                     G_STRLOC,
 
380
                     G_OBJECT_TYPE_NAME (container),
 
381
                     name);
 
382
          break;
 
383
        }
 
384
      if (!(pspec->flags & G_PARAM_READABLE))
 
385
        {
 
386
          g_warning ("%s: child property `%s' of container class `%s' is not readable",
 
387
                     G_STRLOC,
 
388
                     pspec->name,
 
389
                     G_OBJECT_TYPE_NAME (container));
 
390
          break;
 
391
        }
 
392
      g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
 
393
      container_get_child_property (container, child, pspec, &value);
 
394
      G_VALUE_LCOPY (&value, var_args, 0, &error);
 
395
      if (error)
 
396
        {
 
397
          g_warning ("%s: %s", G_STRLOC, error);
 
398
          g_free (error);
 
399
          g_value_unset (&value);
 
400
          break;
 
401
        }
 
402
      g_value_unset (&value);
 
403
      name = va_arg (var_args, gchar*);
 
404
    }
 
405
 
 
406
  g_object_unref (child);
 
407
  g_object_unref (container);
 
408
}
 
409
 
 
410
/**
 
411
 * gtk_container_child_get_property:
 
412
 * @container: a #GtkContainer
 
413
 * @child: a widget which is a child of @container
 
414
 * @property_name: the name of the property to get
 
415
 * @value: a location to return the value
 
416
 * 
 
417
 * Gets the value of a child property for @child and @container.
 
418
 **/
 
419
void
 
420
gtk_container_child_get_property (GtkContainer *container,
 
421
                                  GtkWidget    *child,
 
422
                                  const gchar  *property_name,
 
423
                                  GValue       *value)
 
424
{
 
425
  GParamSpec *pspec;
 
426
 
 
427
  g_return_if_fail (GTK_IS_CONTAINER (container));
 
428
  g_return_if_fail (GTK_IS_WIDGET (child));
 
429
  g_return_if_fail (child->parent == GTK_WIDGET (container));
 
430
  g_return_if_fail (property_name != NULL);
 
431
  g_return_if_fail (G_IS_VALUE (value));
 
432
  
 
433
  g_object_ref (container);
 
434
  g_object_ref (child);
 
435
  pspec = g_param_spec_pool_lookup (_gtk_widget_child_property_pool, property_name,
 
436
                                    G_OBJECT_TYPE (container), TRUE);
 
437
  if (!pspec)
 
438
    g_warning ("%s: container class `%s' has no child property named `%s'",
 
439
               G_STRLOC,
 
440
               G_OBJECT_TYPE_NAME (container),
 
441
               property_name);
 
442
  else if (!(pspec->flags & G_PARAM_READABLE))
 
443
    g_warning ("%s: child property `%s' of container class `%s' is not readable",
 
444
               G_STRLOC,
 
445
               pspec->name,
 
446
               G_OBJECT_TYPE_NAME (container));
 
447
  else
 
448
    {
 
449
      GValue *prop_value, tmp_value = { 0, };
 
450
 
 
451
      /* auto-conversion of the callers value type
 
452
       */
 
453
      if (G_VALUE_TYPE (value) == G_PARAM_SPEC_VALUE_TYPE (pspec))
 
454
        {
 
455
          g_value_reset (value);
 
456
          prop_value = value;
 
457
        }
 
458
      else if (!g_value_type_transformable (G_PARAM_SPEC_VALUE_TYPE (pspec), G_VALUE_TYPE (value)))
 
459
        {
 
460
          g_warning ("can't retrieve child property `%s' of type `%s' as value of type `%s'",
 
461
                     pspec->name,
 
462
                     g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
 
463
                     G_VALUE_TYPE_NAME (value));
 
464
          g_object_unref (child);
 
465
          g_object_unref (container);
 
466
          return;
 
467
        }
 
468
      else
 
469
        {
 
470
          g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
 
471
          prop_value = &tmp_value;
 
472
        }
 
473
      container_get_child_property (container, child, pspec, prop_value);
 
474
      if (prop_value != value)
 
475
        {
 
476
          g_value_transform (prop_value, value);
 
477
          g_value_unset (&tmp_value);
 
478
        }
 
479
    }
 
480
  g_object_unref (child);
 
481
  g_object_unref (container);
 
482
}
 
483
 
 
484
/**
 
485
 * gtk_container_child_set_valist:
 
486
 * @container: a #GtkContainer
 
487
 * @child: a widget which is a child of @container
 
488
 * @first_property_name: the name of the first property to set
 
489
 * @var_args: a %NULL-terminated list of property names and values, starting
 
490
 *           with @first_prop_name.
 
491
 * 
 
492
 * Sets one or more child properties for @child and @container.
 
493
 **/
 
494
void
 
495
gtk_container_child_set_valist (GtkContainer *container,
 
496
                                GtkWidget    *child,
 
497
                                const gchar  *first_property_name,
 
498
                                va_list       var_args)
 
499
{
 
500
  GObjectNotifyQueue *nqueue;
 
501
  const gchar *name;
 
502
 
 
503
  g_return_if_fail (GTK_IS_CONTAINER (container));
 
504
  g_return_if_fail (GTK_IS_WIDGET (child));
 
505
  g_return_if_fail (child->parent == GTK_WIDGET (container));
 
506
 
 
507
  g_object_ref (container);
 
508
  g_object_ref (child);
 
509
 
 
510
  nqueue = g_object_notify_queue_freeze (G_OBJECT (child), _gtk_widget_child_property_notify_context);
 
511
  name = first_property_name;
 
512
  while (name)
 
513
    {
 
514
      GValue value = { 0, };
 
515
      gchar *error = NULL;
 
516
      GParamSpec *pspec = g_param_spec_pool_lookup (_gtk_widget_child_property_pool,
 
517
                                                    name,
 
518
                                                    G_OBJECT_TYPE (container),
 
519
                                                    TRUE);
 
520
      if (!pspec)
 
521
        {
 
522
          g_warning ("%s: container class `%s' has no child property named `%s'",
 
523
                     G_STRLOC,
 
524
                     G_OBJECT_TYPE_NAME (container),
 
525
                     name);
 
526
          break;
 
527
        }
 
528
      if (!(pspec->flags & G_PARAM_WRITABLE))
 
529
        {
 
530
          g_warning ("%s: child property `%s' of container class `%s' is not writable",
 
531
                     G_STRLOC,
 
532
                     pspec->name,
 
533
                     G_OBJECT_TYPE_NAME (container));
 
534
          break;
 
535
        }
 
536
      g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
 
537
      G_VALUE_COLLECT (&value, var_args, 0, &error);
 
538
      if (error)
 
539
        {
 
540
          g_warning ("%s: %s", G_STRLOC, error);
 
541
          g_free (error);
 
542
 
 
543
          /* we purposely leak the value here, it might not be
 
544
           * in a sane state if an error condition occoured
 
545
           */
 
546
          break;
 
547
        }
 
548
      container_set_child_property (container, child, pspec, &value, nqueue);
 
549
      g_value_unset (&value);
 
550
      name = va_arg (var_args, gchar*);
 
551
    }
 
552
  g_object_notify_queue_thaw (G_OBJECT (child), nqueue);
 
553
 
 
554
  g_object_unref (container);
 
555
  g_object_unref (child);
 
556
}
 
557
 
 
558
/**
 
559
 * gtk_container_child_set_property:
 
560
 * @container: a #GtkContainer
 
561
 * @child: a widget which is a child of @container
 
562
 * @property_name: the name of the property to set
 
563
 * @value: the value to set the property to
 
564
 * 
 
565
 * Sets a child property for @child and @container.
 
566
 **/
 
567
void
 
568
gtk_container_child_set_property (GtkContainer *container,
 
569
                                  GtkWidget    *child,
 
570
                                  const gchar  *property_name,
 
571
                                  const GValue *value)
 
572
{
 
573
  GObjectNotifyQueue *nqueue;
 
574
  GParamSpec *pspec;
 
575
 
 
576
  g_return_if_fail (GTK_IS_CONTAINER (container));
 
577
  g_return_if_fail (GTK_IS_WIDGET (child));
 
578
  g_return_if_fail (child->parent == GTK_WIDGET (container));
 
579
  g_return_if_fail (property_name != NULL);
 
580
  g_return_if_fail (G_IS_VALUE (value));
 
581
  
 
582
  g_object_ref (container);
 
583
  g_object_ref (child);
 
584
 
 
585
  nqueue = g_object_notify_queue_freeze (G_OBJECT (child), _gtk_widget_child_property_notify_context);
 
586
  pspec = g_param_spec_pool_lookup (_gtk_widget_child_property_pool, property_name,
 
587
                                    G_OBJECT_TYPE (container), TRUE);
 
588
  if (!pspec)
 
589
    g_warning ("%s: container class `%s' has no child property named `%s'",
 
590
               G_STRLOC,
 
591
               G_OBJECT_TYPE_NAME (container),
 
592
               property_name);
 
593
  else if (!(pspec->flags & G_PARAM_WRITABLE))
 
594
    g_warning ("%s: child property `%s' of container class `%s' is not writable",
 
595
               G_STRLOC,
 
596
               pspec->name,
 
597
               G_OBJECT_TYPE_NAME (container));
 
598
  else
 
599
    {
 
600
      container_set_child_property (container, child, pspec, value, nqueue);
 
601
    }
 
602
  g_object_notify_queue_thaw (G_OBJECT (child), nqueue);
 
603
  g_object_unref (container);
 
604
  g_object_unref (child);
 
605
}
 
606
 
 
607
/**
 
608
 * gtk_container_add_with_properties:
 
609
 * @container: a #GtkContainer 
 
610
 * @widget: a widget to be placed inside @container 
 
611
 * @first_prop_name: the name of the first child property to set 
 
612
 * @Varargs: a %NULL-terminated list of property names and values, starting
 
613
 *           with @first_prop_name.
 
614
 * 
 
615
 * Adds @widget to @container, setting child properties at the same time.
 
616
 * See gtk_container_add() and gtk_container_child_set() for more details.
 
617
 **/
 
618
void
 
619
gtk_container_add_with_properties (GtkContainer *container,
 
620
                                   GtkWidget    *widget,
 
621
                                   const gchar  *first_prop_name,
 
622
                                   ...)
 
623
{
 
624
  g_return_if_fail (GTK_IS_CONTAINER (container));
 
625
  g_return_if_fail (GTK_IS_WIDGET (widget));
 
626
  g_return_if_fail (widget->parent == NULL);
 
627
 
 
628
  g_object_ref (container);
 
629
  g_object_ref (widget);
 
630
  gtk_widget_freeze_child_notify (widget);
 
631
 
 
632
  g_signal_emit (container, container_signals[ADD], 0, widget);
 
633
  if (widget->parent)
 
634
    {
 
635
      va_list var_args;
 
636
 
 
637
      va_start (var_args, first_prop_name);
 
638
      gtk_container_child_set_valist (container, widget, first_prop_name, var_args);
 
639
      va_end (var_args);
 
640
    }
 
641
 
 
642
  gtk_widget_thaw_child_notify (widget);
 
643
  g_object_unref (widget);
 
644
  g_object_unref (container);
 
645
}
 
646
 
 
647
/**
 
648
 * gtk_container_child_set:
 
649
 * @container: a #GtkContainer
 
650
 * @child: a widget which is a child of @container
 
651
 * @first_prop_name: the name of the first property to set
 
652
 * @Varargs: a %NULL-terminated list of property names and values, starting
 
653
 *           with @first_prop_name.
 
654
 * 
 
655
 * Sets one or more child properties for @child and @container.
 
656
 **/
 
657
void
 
658
gtk_container_child_set (GtkContainer      *container,
 
659
                         GtkWidget         *child,
 
660
                         const gchar       *first_prop_name,
 
661
                         ...)
 
662
{
 
663
  va_list var_args;
 
664
  
 
665
  g_return_if_fail (GTK_IS_CONTAINER (container));
 
666
  g_return_if_fail (GTK_IS_WIDGET (child));
 
667
  g_return_if_fail (child->parent == GTK_WIDGET (container));
 
668
 
 
669
  va_start (var_args, first_prop_name);
 
670
  gtk_container_child_set_valist (container, child, first_prop_name, var_args);
 
671
  va_end (var_args);
 
672
}
 
673
 
 
674
/**
 
675
 * gtk_container_child_get:
 
676
 * @container: a #GtkContainer
 
677
 * @child: a widget which is a child of @container
 
678
 * @first_prop_name: the name of the first property to get
 
679
 * @Varargs: a %NULL-terminated list of property names and #GValue*, 
 
680
 *           starting with @first_prop_name.
 
681
 * 
 
682
 * Gets the values of one or more child properties for @child and @container.
 
683
 **/
 
684
void
 
685
gtk_container_child_get (GtkContainer      *container,
 
686
                         GtkWidget         *child,
 
687
                         const gchar       *first_prop_name,
 
688
                         ...)
 
689
{
 
690
  va_list var_args;
 
691
  
 
692
  g_return_if_fail (GTK_IS_CONTAINER (container));
 
693
  g_return_if_fail (GTK_IS_WIDGET (child));
 
694
  g_return_if_fail (child->parent == GTK_WIDGET (container));
 
695
 
 
696
  va_start (var_args, first_prop_name);
 
697
  gtk_container_child_get_valist (container, child, first_prop_name, var_args);
 
698
  va_end (var_args);
 
699
}
 
700
 
 
701
/**
 
702
 * gtk_container_class_install_child_property:
 
703
 * @cclass: a #GtkContainerClass
 
704
 * @property_id: the id for the property
 
705
 * @pspec: the #GParamSpec for the property
 
706
 * 
 
707
 * Installs a child property on a container class. 
 
708
 **/
 
709
void
 
710
gtk_container_class_install_child_property (GtkContainerClass *cclass,
 
711
                                            guint              property_id,
 
712
                                            GParamSpec        *pspec)
 
713
{
 
714
  g_return_if_fail (GTK_IS_CONTAINER_CLASS (cclass));
 
715
  g_return_if_fail (G_IS_PARAM_SPEC (pspec));
 
716
  if (pspec->flags & G_PARAM_WRITABLE)
 
717
    g_return_if_fail (cclass->set_child_property != NULL);
 
718
  if (pspec->flags & G_PARAM_READABLE)
 
719
    g_return_if_fail (cclass->get_child_property != NULL);
 
720
  g_return_if_fail (property_id > 0);
 
721
  g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0);  /* paranoid */
 
722
  if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY))
 
723
    g_return_if_fail ((pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) == 0);
 
724
 
 
725
  if (g_param_spec_pool_lookup (_gtk_widget_child_property_pool, pspec->name, G_OBJECT_CLASS_TYPE (cclass), FALSE))
 
726
    {
 
727
      g_warning (G_STRLOC ": class `%s' already contains a child property named `%s'",
 
728
                 G_OBJECT_CLASS_NAME (cclass),
 
729
                 pspec->name);
 
730
      return;
 
731
    }
 
732
  g_param_spec_ref (pspec);
 
733
  g_param_spec_sink (pspec);
 
734
  PARAM_SPEC_SET_PARAM_ID (pspec, property_id);
 
735
  g_param_spec_pool_insert (_gtk_widget_child_property_pool, pspec, G_OBJECT_CLASS_TYPE (cclass));
 
736
}
 
737
 
 
738
/**
 
739
 * gtk_container_class_find_child_property:
 
740
 * @cclass: a #GtkContainerClass
 
741
 * @property_name: the name of the child property to find
 
742
 * @returns: the #GParamSpec of the child property or %NULL if @class has no
 
743
 *   child property with that name.
 
744
 *
 
745
 * Finds a child property of a container class by name.
 
746
 */
 
747
GParamSpec*
 
748
gtk_container_class_find_child_property (GObjectClass *cclass,
 
749
                                         const gchar  *property_name)
 
750
{
 
751
  g_return_val_if_fail (GTK_IS_CONTAINER_CLASS (cclass), NULL);
 
752
  g_return_val_if_fail (property_name != NULL, NULL);
 
753
 
 
754
  return g_param_spec_pool_lookup (_gtk_widget_child_property_pool,
 
755
                                   property_name,
 
756
                                   G_OBJECT_CLASS_TYPE (cclass),
 
757
                                   TRUE);
 
758
}
 
759
 
 
760
/**
 
761
 * gtk_container_class_list_child_properties:
 
762
 * @cclass: a #GtkContainerClass
 
763
 * @n_properties: location to return the number of child properties found
 
764
 * @returns: a newly allocated array of #GParamSpec*. The array must be 
 
765
 *           freed with g_free().
 
766
 *
 
767
 * Returns all child properties of a container class.
 
768
 */
 
769
GParamSpec**
 
770
gtk_container_class_list_child_properties (GObjectClass *cclass,
 
771
                                           guint        *n_properties)
 
772
{
 
773
  GParamSpec **pspecs;
 
774
  guint n;
 
775
 
 
776
  g_return_val_if_fail (GTK_IS_CONTAINER_CLASS (cclass), NULL);
 
777
 
 
778
  pspecs = g_param_spec_pool_list (_gtk_widget_child_property_pool,
 
779
                                   G_OBJECT_CLASS_TYPE (cclass),
 
780
                                   &n);
 
781
  if (n_properties)
 
782
    *n_properties = n;
 
783
 
 
784
  return pspecs;
 
785
}
 
786
 
 
787
static void
 
788
gtk_container_add_unimplemented (GtkContainer     *container,
 
789
                                 GtkWidget        *widget)
 
790
{
 
791
  g_warning ("GtkContainerClass::add not implemented for `%s'", g_type_name (G_TYPE_FROM_INSTANCE (container)));
 
792
}
 
793
 
 
794
static void
 
795
gtk_container_remove_unimplemented (GtkContainer     *container,
 
796
                                    GtkWidget        *widget)
 
797
{
 
798
  g_warning ("GtkContainerClass::remove not implemented for `%s'", g_type_name (G_TYPE_FROM_INSTANCE (container)));
 
799
}
 
800
 
 
801
static void
 
802
gtk_container_init (GtkContainer *container)
 
803
{
 
804
  container->focus_child = NULL;
 
805
  container->border_width = 0;
 
806
  container->need_resize = FALSE;
 
807
  container->resize_mode = GTK_RESIZE_PARENT;
 
808
  container->reallocate_redraws = FALSE;
 
809
}
 
810
 
 
811
static void
 
812
gtk_container_destroy (GtkObject *object)
 
813
{
 
814
  GtkContainer *container = GTK_CONTAINER (object);
 
815
  
 
816
  if (GTK_CONTAINER_RESIZE_PENDING (container))
 
817
    _gtk_container_dequeue_resize_handler (container);
 
818
 
 
819
  /* do this before walking child widgets, to avoid
 
820
   * removing children from focus chain one by one.
 
821
   */
 
822
  if (container->has_focus_chain)
 
823
    gtk_container_unset_focus_chain (container);
 
824
  
 
825
  gtk_container_foreach (container, (GtkCallback) gtk_widget_destroy, NULL);
 
826
  
 
827
  if (GTK_OBJECT_CLASS (parent_class)->destroy)
 
828
    (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
 
829
}
 
830
 
 
831
static void
 
832
gtk_container_set_property (GObject         *object,
 
833
                            guint            prop_id,
 
834
                            const GValue    *value,
 
835
                            GParamSpec      *pspec)
 
836
{
 
837
  GtkContainer *container = GTK_CONTAINER (object);
 
838
 
 
839
  switch (prop_id)
 
840
    {
 
841
    case PROP_BORDER_WIDTH:
 
842
      gtk_container_set_border_width (container, g_value_get_uint (value));
 
843
      break;
 
844
    case PROP_RESIZE_MODE:
 
845
      gtk_container_set_resize_mode (container, g_value_get_enum (value));
 
846
      break;
 
847
    case PROP_CHILD:
 
848
      gtk_container_add (container, GTK_WIDGET (g_value_get_object (value)));
 
849
      break;
 
850
    default:
 
851
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
852
      break;
 
853
    }
 
854
}
 
855
 
 
856
static void
 
857
gtk_container_get_property (GObject         *object,
 
858
                            guint            prop_id,
 
859
                            GValue          *value,
 
860
                            GParamSpec      *pspec)
 
861
{
 
862
  GtkContainer *container = GTK_CONTAINER (object);
 
863
  
 
864
  switch (prop_id)
 
865
    {
 
866
    case PROP_BORDER_WIDTH:
 
867
      g_value_set_uint (value, container->border_width);
 
868
      break;
 
869
    case PROP_RESIZE_MODE:
 
870
      g_value_set_enum (value, container->resize_mode);
 
871
      break;
 
872
    default:
 
873
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
874
      break;
 
875
    }
 
876
}
 
877
 
 
878
/**
 
879
 * gtk_container_set_border_width:
 
880
 * @container: a #GtkContainer
 
881
 * @border_width: amount of blank space to leave <emphasis>outside</emphasis> the container.
 
882
 *   Valid values are in the range 0-65535 pixels.
 
883
 *
 
884
 * Sets the border width of the container.
 
885
 *
 
886
 * The border width of a container is the amount of space to leave
 
887
 * around the outside of the container. The only exception to this is
 
888
 * #GtkWindow; because toplevel windows can't leave space outside,
 
889
 * they leave the space inside. The border is added on all sides of
 
890
 * the container. To add space to only one side, one approach is to
 
891
 * create a #GtkAlignment widget, call gtk_widget_set_usize() to give
 
892
 * it a size, and place it on the side of the container as a spacer.
 
893
 **/
 
894
void
 
895
gtk_container_set_border_width (GtkContainer *container,
 
896
                                guint         border_width)
 
897
{
 
898
  g_return_if_fail (GTK_IS_CONTAINER (container));
 
899
 
 
900
  if (container->border_width != border_width)
 
901
    {
 
902
      container->border_width = border_width;
 
903
      g_object_notify (G_OBJECT (container), "border-width");
 
904
      
 
905
      if (GTK_WIDGET_REALIZED (container))
 
906
        gtk_widget_queue_resize (GTK_WIDGET (container));
 
907
    }
 
908
}
 
909
 
 
910
/**
 
911
 * gtk_container_get_border_width:
 
912
 * @container: a #GtkContainer
 
913
 * 
 
914
 * Retrieves the border width of the container. See
 
915
 * gtk_container_set_border_width().
 
916
 *
 
917
 * Return value: the current border width
 
918
 **/
 
919
guint
 
920
gtk_container_get_border_width (GtkContainer *container)
 
921
{
 
922
  g_return_val_if_fail (GTK_IS_CONTAINER (container), 0);
 
923
 
 
924
  return container->border_width;
 
925
}
 
926
 
 
927
/**
 
928
 * gtk_container_add:
 
929
 * @container: a #GtkContainer
 
930
 * @widget: a widget to be placed inside @container
 
931
 * 
 
932
 * Adds @widget to @container. Typically used for simple containers
 
933
 * such as #GtkWindow, #GtkFrame, or #GtkButton; for more complicated
 
934
 * layout containers such as #GtkBox or #GtkTable, this function will
 
935
 * pick default packing parameters that may not be correct.  So
 
936
 * consider functions such as gtk_box_pack_start() and
 
937
 * gtk_table_attach() as an alternative to gtk_container_add() in
 
938
 * those cases. A widget may be added to only one container at a time;
 
939
 * you can't place the same widget inside two different containers.
 
940
 **/
 
941
void
 
942
gtk_container_add (GtkContainer *container,
 
943
                   GtkWidget    *widget)
 
944
{
 
945
  g_return_if_fail (GTK_IS_CONTAINER (container));
 
946
  g_return_if_fail (GTK_IS_WIDGET (widget));
 
947
 
 
948
  if (widget->parent != NULL)
 
949
    {
 
950
      g_warning ("Attempting to add a widget with type %s to a container of "
 
951
                 "type %s, but the widget is already inside a container of type %s, "
 
952
                 "the GTK+ FAQ at http://www.gtk.org/faq/ explains how to reparent a widget.",
 
953
                 g_type_name (G_OBJECT_TYPE (widget)),
 
954
                 g_type_name (G_OBJECT_TYPE (container)),
 
955
                 g_type_name (G_OBJECT_TYPE (widget->parent)));
 
956
      return;
 
957
    }
 
958
 
 
959
  g_signal_emit (container, container_signals[ADD], 0, widget);
 
960
}
 
961
 
 
962
/**
 
963
 * gtk_container_remove:
 
964
 * @container: a #GtkContainer
 
965
 * @widget: a current child of @container
 
966
 * 
 
967
 * Removes @widget from @container. @widget must be inside @container.
 
968
 * Note that @container will own a reference to @widget, and that this
 
969
 * may be the last reference held; so removing a widget from its
 
970
 * container can destroy that widget. If you want to use @widget
 
971
 * again, you need to add a reference to it while it's not inside
 
972
 * a container, using g_object_ref(). If you don't want to use @widget
 
973
 * again it's usually more efficient to simply destroy it directly
 
974
 * using gtk_widget_destroy() since this will remove it from the
 
975
 * container and help break any circular reference count cycles.
 
976
 **/
 
977
void
 
978
gtk_container_remove (GtkContainer *container,
 
979
                      GtkWidget    *widget)
 
980
{
 
981
  g_return_if_fail (GTK_IS_CONTAINER (container));
 
982
  g_return_if_fail (GTK_IS_WIDGET (widget));
 
983
 
 
984
  /* When using the deprecated API of the toolbar, it is possible
 
985
   * to legitimately call this function with a widget that is not
 
986
   * a direct child of the container.
 
987
   */
 
988
  g_return_if_fail (GTK_IS_TOOLBAR (container) ||
 
989
                    widget->parent == GTK_WIDGET (container));
 
990
  
 
991
  g_signal_emit (container, container_signals[REMOVE], 0, widget);
 
992
}
 
993
 
 
994
void
 
995
_gtk_container_dequeue_resize_handler (GtkContainer *container)
 
996
{
 
997
  g_return_if_fail (GTK_IS_CONTAINER (container));
 
998
  g_return_if_fail (GTK_CONTAINER_RESIZE_PENDING (container));
 
999
 
 
1000
  container_resize_queue = g_slist_remove (container_resize_queue, container);
 
1001
  GTK_PRIVATE_UNSET_FLAG (container, GTK_RESIZE_PENDING);
 
1002
}
 
1003
 
 
1004
/**
 
1005
 * gtk_container_set_resize_mode:
 
1006
 * @container: a #GtkContainer.
 
1007
 * @resize_mode: the new resize mode.
 
1008
 * 
 
1009
 * Sets the resize mode for the container.
 
1010
 *
 
1011
 * The resize mode of a container determines whether a resize request 
 
1012
 * will be passed to the container's parent, queued for later execution
 
1013
 * or executed immediately.
 
1014
 **/
 
1015
void
 
1016
gtk_container_set_resize_mode (GtkContainer  *container,
 
1017
                               GtkResizeMode  resize_mode)
 
1018
{
 
1019
  g_return_if_fail (GTK_IS_CONTAINER (container));
 
1020
  g_return_if_fail (resize_mode <= GTK_RESIZE_IMMEDIATE);
 
1021
  
 
1022
  if (GTK_WIDGET_TOPLEVEL (container) &&
 
1023
      resize_mode == GTK_RESIZE_PARENT)
 
1024
    {
 
1025
      resize_mode = GTK_RESIZE_QUEUE;
 
1026
    }
 
1027
  
 
1028
  if (container->resize_mode != resize_mode)
 
1029
    {
 
1030
      container->resize_mode = resize_mode;
 
1031
      
 
1032
      gtk_widget_queue_resize (GTK_WIDGET (container));
 
1033
      g_object_notify (G_OBJECT (container), "resize-mode");
 
1034
    }
 
1035
}
 
1036
 
 
1037
/**
 
1038
 * gtk_container_get_resize_mode:
 
1039
 * @container: a #GtkContainer
 
1040
 * 
 
1041
 * Returns the resize mode for the container. See
 
1042
 * gtk_container_set_resize_mode ().
 
1043
 *
 
1044
 * Return value: the current resize mode
 
1045
 **/
 
1046
GtkResizeMode
 
1047
gtk_container_get_resize_mode (GtkContainer *container)
 
1048
{
 
1049
  g_return_val_if_fail (GTK_IS_CONTAINER (container), GTK_RESIZE_PARENT);
 
1050
 
 
1051
  return container->resize_mode;
 
1052
}
 
1053
 
 
1054
/**
 
1055
 * gtk_container_set_reallocate_redraws:
 
1056
 * @container: a #GtkContainer.
 
1057
 * @needs_redraws: the new value for the container's @reallocate_redraws flag.
 
1058
 *
 
1059
 * Sets the @reallocate_redraws flag of the container to the given value.
 
1060
 * 
 
1061
 * Containers requesting reallocation redraws get automatically
 
1062
 * redrawn if any of their children changed allocation. 
 
1063
 **/ 
 
1064
void
 
1065
gtk_container_set_reallocate_redraws (GtkContainer *container,
 
1066
                                      gboolean      needs_redraws)
 
1067
{
 
1068
  g_return_if_fail (GTK_IS_CONTAINER (container));
 
1069
 
 
1070
  container->reallocate_redraws = needs_redraws ? TRUE : FALSE;
 
1071
}
 
1072
 
 
1073
static GtkContainer*
 
1074
gtk_container_get_resize_container (GtkContainer *container)
 
1075
{
 
1076
  GtkWidget *widget = GTK_WIDGET (container);
 
1077
 
 
1078
  while (widget->parent)
 
1079
    {
 
1080
      widget = widget->parent;
 
1081
      if (GTK_IS_RESIZE_CONTAINER (widget))
 
1082
        break;
 
1083
    }
 
1084
 
 
1085
  return GTK_IS_RESIZE_CONTAINER (widget) ? (GtkContainer*) widget : NULL;
 
1086
}
 
1087
 
 
1088
static gboolean
 
1089
gtk_container_idle_sizer (gpointer data)
 
1090
{
 
1091
  GDK_THREADS_ENTER ();
 
1092
 
 
1093
  /* we may be invoked with a container_resize_queue of NULL, because
 
1094
   * queue_resize could have been adding an extra idle function while
 
1095
   * the queue still got processed. we better just ignore such case
 
1096
   * than trying to explicitely work around them with some extra flags,
 
1097
   * since it doesn't cause any actual harm.
 
1098
   */
 
1099
  while (container_resize_queue)
 
1100
    {
 
1101
      GSList *slist;
 
1102
      GtkWidget *widget;
 
1103
 
 
1104
      slist = container_resize_queue;
 
1105
      container_resize_queue = slist->next;
 
1106
      widget = slist->data;
 
1107
      g_slist_free_1 (slist);
 
1108
 
 
1109
      GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_PENDING);
 
1110
      gtk_container_check_resize (GTK_CONTAINER (widget));
 
1111
    }
 
1112
 
 
1113
  gdk_window_process_all_updates ();
 
1114
 
 
1115
  GDK_THREADS_LEAVE ();
 
1116
 
 
1117
  return FALSE;
 
1118
}
 
1119
 
 
1120
void
 
1121
_gtk_container_queue_resize (GtkContainer *container)
 
1122
{
 
1123
  GtkContainer *resize_container;
 
1124
  GtkWidget *widget;
 
1125
  
 
1126
  g_return_if_fail (GTK_IS_CONTAINER (container));
 
1127
 
 
1128
  widget = GTK_WIDGET (container);
 
1129
  resize_container = gtk_container_get_resize_container (container);
 
1130
  
 
1131
  while (TRUE)
 
1132
    {
 
1133
      GTK_PRIVATE_SET_FLAG (widget, GTK_ALLOC_NEEDED);
 
1134
      GTK_PRIVATE_SET_FLAG (widget, GTK_REQUEST_NEEDED);
 
1135
      if ((resize_container && widget == GTK_WIDGET (resize_container)) ||
 
1136
          !widget->parent)
 
1137
        break;
 
1138
      
 
1139
      widget = widget->parent;
 
1140
    }
 
1141
      
 
1142
  if (resize_container)
 
1143
    {
 
1144
      if (GTK_WIDGET_VISIBLE (resize_container) &&
 
1145
          (GTK_WIDGET_TOPLEVEL (resize_container) || GTK_WIDGET_REALIZED (resize_container)))
 
1146
        {
 
1147
          switch (resize_container->resize_mode)
 
1148
            {
 
1149
            case GTK_RESIZE_QUEUE:
 
1150
              if (!GTK_CONTAINER_RESIZE_PENDING (resize_container))
 
1151
                {
 
1152
                  GTK_PRIVATE_SET_FLAG (resize_container, GTK_RESIZE_PENDING);
 
1153
                  if (container_resize_queue == NULL)
 
1154
                    g_idle_add_full (GTK_PRIORITY_RESIZE,
 
1155
                                     gtk_container_idle_sizer,
 
1156
                                     NULL, NULL);
 
1157
                  container_resize_queue = g_slist_prepend (container_resize_queue, resize_container);
 
1158
                }
 
1159
              break;
 
1160
 
 
1161
            case GTK_RESIZE_IMMEDIATE:
 
1162
              gtk_container_check_resize (resize_container);
 
1163
              break;
 
1164
 
 
1165
            case GTK_RESIZE_PARENT:
 
1166
              g_assert_not_reached ();
 
1167
              break;
 
1168
            }
 
1169
        }
 
1170
      else
 
1171
        {
 
1172
          /* we need to let hidden resize containers know that something
 
1173
           * changed while they where hidden (currently only evaluated by
 
1174
           * toplevels).
 
1175
           */
 
1176
          resize_container->need_resize = TRUE;
 
1177
        }
 
1178
    }
 
1179
}
 
1180
 
 
1181
void
 
1182
gtk_container_check_resize (GtkContainer *container)
 
1183
{
 
1184
  g_return_if_fail (GTK_IS_CONTAINER (container));
 
1185
  
 
1186
  g_signal_emit (container, container_signals[CHECK_RESIZE], 0);
 
1187
}
 
1188
 
 
1189
static void
 
1190
gtk_container_real_check_resize (GtkContainer *container)
 
1191
{
 
1192
  GtkWidget *widget = GTK_WIDGET (container);
 
1193
  GtkRequisition requisition;
 
1194
  
 
1195
  gtk_widget_size_request (widget, &requisition);
 
1196
  
 
1197
  if (requisition.width > widget->allocation.width ||
 
1198
      requisition.height > widget->allocation.height)
 
1199
    {
 
1200
      if (GTK_IS_RESIZE_CONTAINER (container))
 
1201
        gtk_widget_size_allocate (GTK_WIDGET (container),
 
1202
                                  &GTK_WIDGET (container)->allocation);
 
1203
      else
 
1204
        gtk_widget_queue_resize (widget);
 
1205
    }
 
1206
  else
 
1207
    {
 
1208
      gtk_container_resize_children (container);
 
1209
    }
 
1210
}
 
1211
 
 
1212
/* The container hasn't changed size but one of its children
 
1213
 *  queued a resize request. Which means that the allocation
 
1214
 *  is not sufficient for the requisition of some child.
 
1215
 *  We've already performed a size request at this point,
 
1216
 *  so we simply need to reallocate and let the allocation
 
1217
 *  trickle down via GTK_WIDGET_ALLOC_NEEDED flags. 
 
1218
 */
 
1219
void
 
1220
gtk_container_resize_children (GtkContainer *container)
 
1221
{
 
1222
  GtkWidget *widget;
 
1223
  
 
1224
  /* resizing invariants:
 
1225
   * toplevels have *always* resize_mode != GTK_RESIZE_PARENT set.
 
1226
   * containers that have an idle sizer pending must be flagged with
 
1227
   * RESIZE_PENDING.
 
1228
   */
 
1229
  g_return_if_fail (GTK_IS_CONTAINER (container));
 
1230
 
 
1231
  widget = GTK_WIDGET (container);
 
1232
  gtk_widget_size_allocate (widget, &widget->allocation);
 
1233
}
 
1234
 
 
1235
/**
 
1236
 * gtk_container_forall:
 
1237
 * @container: a #GtkContainer
 
1238
 * @callback: a callback
 
1239
 * @callback_data: callback user data
 
1240
 * 
 
1241
 * Invokes @callback on each child of @container, including children
 
1242
 * that are considered "internal" (implementation details of the
 
1243
 * container). "Internal" children generally weren't added by the user
 
1244
 * of the container, but were added by the container implementation
 
1245
 * itself.  Most applications should use gtk_container_foreach(),
 
1246
 * rather than gtk_container_forall().
 
1247
 **/
 
1248
void
 
1249
gtk_container_forall (GtkContainer *container,
 
1250
                      GtkCallback   callback,
 
1251
                      gpointer      callback_data)
 
1252
{
 
1253
  GtkContainerClass *class;
 
1254
 
 
1255
  g_return_if_fail (GTK_IS_CONTAINER (container));
 
1256
  g_return_if_fail (callback != NULL);
 
1257
 
 
1258
  class = GTK_CONTAINER_GET_CLASS (container);
 
1259
 
 
1260
  if (class->forall)
 
1261
    class->forall (container, TRUE, callback, callback_data);
 
1262
}
 
1263
 
 
1264
/**
 
1265
 * gtk_container_foreach:
 
1266
 * @container: a #GtkContainer
 
1267
 * @callback: a callback
 
1268
 * @callback_data: callback user data
 
1269
 * 
 
1270
 * Invokes @callback on each non-internal child of @container.  See
 
1271
 * gtk_container_forall() for details on what constitutes an
 
1272
 * "internal" child.  Most applications should use
 
1273
 * gtk_container_foreach(), rather than gtk_container_forall().
 
1274
 **/
 
1275
void
 
1276
gtk_container_foreach (GtkContainer *container,
 
1277
                       GtkCallback   callback,
 
1278
                       gpointer      callback_data)
 
1279
{
 
1280
  GtkContainerClass *class;
 
1281
  
 
1282
  g_return_if_fail (GTK_IS_CONTAINER (container));
 
1283
  g_return_if_fail (callback != NULL);
 
1284
 
 
1285
  class = GTK_CONTAINER_GET_CLASS (container);
 
1286
 
 
1287
  if (class->forall)
 
1288
    class->forall (container, FALSE, callback, callback_data);
 
1289
}
 
1290
 
 
1291
typedef struct _GtkForeachData  GtkForeachData;
 
1292
struct _GtkForeachData
 
1293
{
 
1294
  GtkObject         *container;
 
1295
  GtkCallbackMarshal callback;
 
1296
  gpointer           callback_data;
 
1297
};
 
1298
 
 
1299
static void
 
1300
gtk_container_foreach_unmarshal (GtkWidget *child,
 
1301
                                 gpointer data)
 
1302
{
 
1303
  GtkForeachData *fdata = (GtkForeachData*) data;
 
1304
  GtkArg args[2];
 
1305
  
 
1306
  /* first argument */
 
1307
  args[0].name = NULL;
 
1308
  args[0].type = G_TYPE_FROM_INSTANCE (child);
 
1309
  GTK_VALUE_OBJECT (args[0]) = GTK_OBJECT (child);
 
1310
  
 
1311
  /* location for return value */
 
1312
  args[1].name = NULL;
 
1313
  args[1].type = G_TYPE_NONE;
 
1314
  
 
1315
  fdata->callback (fdata->container, fdata->callback_data, 1, args);
 
1316
}
 
1317
 
 
1318
void
 
1319
gtk_container_foreach_full (GtkContainer       *container,
 
1320
                            GtkCallback         callback,
 
1321
                            GtkCallbackMarshal  marshal,
 
1322
                            gpointer            callback_data,
 
1323
                            GtkDestroyNotify    notify)
 
1324
{
 
1325
  g_return_if_fail (GTK_IS_CONTAINER (container));
 
1326
 
 
1327
  if (marshal)
 
1328
    {
 
1329
      GtkForeachData fdata;
 
1330
  
 
1331
      fdata.container     = GTK_OBJECT (container);
 
1332
      fdata.callback      = marshal;
 
1333
      fdata.callback_data = callback_data;
 
1334
 
 
1335
      gtk_container_foreach (container, gtk_container_foreach_unmarshal, &fdata);
 
1336
    }
 
1337
  else
 
1338
    {
 
1339
      g_return_if_fail (callback != NULL);
 
1340
 
 
1341
      gtk_container_foreach (container, callback, &callback_data);
 
1342
    }
 
1343
 
 
1344
  if (notify)
 
1345
    notify (callback_data);
 
1346
}
 
1347
 
 
1348
void
 
1349
gtk_container_set_focus_child (GtkContainer *container,
 
1350
                               GtkWidget    *widget)
 
1351
{
 
1352
  g_return_if_fail (GTK_IS_CONTAINER (container));
 
1353
  if (widget)
 
1354
    g_return_if_fail (GTK_IS_WIDGET (widget));
 
1355
 
 
1356
  g_signal_emit (container, container_signals[SET_FOCUS_CHILD], 0, widget);
 
1357
}
 
1358
 
 
1359
/**
 
1360
 * gtk_container_get_children:
 
1361
 * @container: a #GtkContainer.
 
1362
 * 
 
1363
 * Returns the container's non-internal children. See
 
1364
 * gtk_container_forall() for details on what constitutes an "internal" child. 
 
1365
 *
 
1366
 * Return value: a newly-allocated list of the container's non-internal children.
 
1367
 **/
 
1368
GList*
 
1369
gtk_container_get_children (GtkContainer *container)
 
1370
{
 
1371
  GList *children = NULL;
 
1372
 
 
1373
  gtk_container_foreach (container,
 
1374
                         gtk_container_children_callback,
 
1375
                         &children);
 
1376
 
 
1377
  return g_list_reverse (children);
 
1378
}
 
1379
 
 
1380
static void
 
1381
gtk_container_child_position_callback (GtkWidget *widget,
 
1382
                                       gpointer   client_data)
 
1383
{
 
1384
  struct {
 
1385
    GtkWidget *child;
 
1386
    guint i;
 
1387
    guint index;
 
1388
  } *data = client_data;
 
1389
 
 
1390
  data->i++;
 
1391
  if (data->child == widget)
 
1392
    data->index = data->i;
 
1393
}
 
1394
 
 
1395
static gchar*
 
1396
gtk_container_child_default_composite_name (GtkContainer *container,
 
1397
                                            GtkWidget    *child)
 
1398
{
 
1399
  struct {
 
1400
    GtkWidget *child;
 
1401
    guint i;
 
1402
    guint index;
 
1403
  } data;
 
1404
  gchar *name;
 
1405
 
 
1406
  /* fallback implementation */
 
1407
  data.child = child;
 
1408
  data.i = 0;
 
1409
  data.index = 0;
 
1410
  gtk_container_forall (container,
 
1411
                        gtk_container_child_position_callback,
 
1412
                        &data);
 
1413
  
 
1414
  name = g_strdup_printf ("%s-%u",
 
1415
                          g_type_name (G_TYPE_FROM_INSTANCE (child)),
 
1416
                          data.index);
 
1417
 
 
1418
  return name;
 
1419
}
 
1420
 
 
1421
gchar*
 
1422
_gtk_container_child_composite_name (GtkContainer *container,
 
1423
                                    GtkWidget    *child)
 
1424
{
 
1425
  g_return_val_if_fail (GTK_IS_CONTAINER (container), NULL);
 
1426
  g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
 
1427
  g_return_val_if_fail (child->parent == GTK_WIDGET (container), NULL);
 
1428
 
 
1429
  if (GTK_WIDGET_COMPOSITE_CHILD (child))
 
1430
    {
 
1431
      static GQuark quark_composite_name = 0;
 
1432
      gchar *name;
 
1433
 
 
1434
      if (!quark_composite_name)
 
1435
        quark_composite_name = g_quark_from_static_string ("gtk-composite-name");
 
1436
 
 
1437
      name = g_object_get_qdata (G_OBJECT (child), quark_composite_name);
 
1438
      if (!name)
 
1439
        {
 
1440
          GtkContainerClass *class;
 
1441
 
 
1442
          class = GTK_CONTAINER_GET_CLASS (container);
 
1443
          if (class->composite_name)
 
1444
            name = class->composite_name (container, child);
 
1445
        }
 
1446
      else
 
1447
        name = g_strdup (name);
 
1448
 
 
1449
      return name;
 
1450
    }
 
1451
  
 
1452
  return NULL;
 
1453
}
 
1454
 
 
1455
static void
 
1456
gtk_container_real_set_focus_child (GtkContainer     *container,
 
1457
                                    GtkWidget        *child)
 
1458
{
 
1459
  g_return_if_fail (GTK_IS_CONTAINER (container));
 
1460
  g_return_if_fail (child == NULL || GTK_IS_WIDGET (child));
 
1461
 
 
1462
  if (child != container->focus_child)
 
1463
    {
 
1464
      if (container->focus_child)
 
1465
        g_object_unref (container->focus_child);
 
1466
      container->focus_child = child;
 
1467
      if (container->focus_child)
 
1468
        g_object_ref (container->focus_child);
 
1469
    }
 
1470
 
 
1471
 
 
1472
  /* check for h/v adjustments
 
1473
   */
 
1474
  if (container->focus_child)
 
1475
    {
 
1476
      GtkAdjustment *hadj;
 
1477
      GtkAdjustment *vadj;
 
1478
      GtkWidget *focus_child;
 
1479
      gint x, y;
 
1480
 
 
1481
      hadj = g_object_get_qdata (G_OBJECT (container), hadjustment_key_id);   
 
1482
      vadj = g_object_get_qdata (G_OBJECT (container), vadjustment_key_id);
 
1483
      if (hadj || vadj) 
 
1484
        {
 
1485
 
 
1486
          focus_child = container->focus_child;
 
1487
          while (GTK_IS_CONTAINER (focus_child) && 
 
1488
                 GTK_CONTAINER (focus_child)->focus_child)
 
1489
            {
 
1490
              focus_child = GTK_CONTAINER (focus_child)->focus_child;
 
1491
            }
 
1492
          
 
1493
          gtk_widget_translate_coordinates (focus_child, container->focus_child, 
 
1494
                                            0, 0, &x, &y);
 
1495
 
 
1496
           x += container->focus_child->allocation.x;
 
1497
           y += container->focus_child->allocation.y;
 
1498
          
 
1499
          if (vadj)
 
1500
            gtk_adjustment_clamp_page (vadj, y, y + focus_child->allocation.height);
 
1501
          
 
1502
          if (hadj)
 
1503
            gtk_adjustment_clamp_page (hadj, x, x + focus_child->allocation.width);
 
1504
        }
 
1505
    }
 
1506
}
 
1507
 
 
1508
static GList*
 
1509
get_focus_chain (GtkContainer *container)
 
1510
{
 
1511
  return g_object_get_data (G_OBJECT (container), "gtk-container-focus-chain");
 
1512
}
 
1513
 
 
1514
/* same as gtk_container_get_children, except it includes internals
 
1515
 */
 
1516
static GList *
 
1517
gtk_container_get_all_children (GtkContainer *container)
 
1518
{
 
1519
  GList *children = NULL;
 
1520
 
 
1521
  gtk_container_forall (container,
 
1522
                         gtk_container_children_callback,
 
1523
                         &children);
 
1524
 
 
1525
  return children;
 
1526
}
 
1527
 
 
1528
static gboolean
 
1529
gtk_container_focus (GtkWidget        *widget,
 
1530
                     GtkDirectionType  direction)
 
1531
{
 
1532
  GList *children;
 
1533
  GList *sorted_children;
 
1534
  gint return_val;
 
1535
  GtkContainer *container;
 
1536
 
 
1537
  g_return_val_if_fail (GTK_IS_CONTAINER (widget), FALSE);
 
1538
 
 
1539
  container = GTK_CONTAINER (widget);
 
1540
 
 
1541
  return_val = FALSE;
 
1542
 
 
1543
  if (GTK_WIDGET_CAN_FOCUS (container))
 
1544
    {
 
1545
      if (!GTK_WIDGET_HAS_FOCUS (container))
 
1546
        {
 
1547
          gtk_widget_grab_focus (GTK_WIDGET (container));
 
1548
          return_val = TRUE;
 
1549
        }
 
1550
    }
 
1551
  else
 
1552
    {
 
1553
      /* Get a list of the containers children, allowing focus
 
1554
       * chain to override.
 
1555
       */
 
1556
      if (container->has_focus_chain)
 
1557
        children = g_list_copy (get_focus_chain (container));
 
1558
      else
 
1559
        children = gtk_container_get_all_children (container);
 
1560
 
 
1561
      if (container->has_focus_chain &&
 
1562
          (direction == GTK_DIR_TAB_FORWARD ||
 
1563
           direction == GTK_DIR_TAB_BACKWARD))
 
1564
        {
 
1565
          sorted_children = g_list_copy (children);
 
1566
          
 
1567
          if (direction == GTK_DIR_TAB_BACKWARD)
 
1568
            sorted_children = g_list_reverse (sorted_children);
 
1569
        }
 
1570
      else
 
1571
        sorted_children = _gtk_container_focus_sort (container, children, direction, NULL);
 
1572
      
 
1573
      return_val = gtk_container_focus_move (container, sorted_children, direction);
 
1574
 
 
1575
      g_list_free (sorted_children);
 
1576
      g_list_free (children);
 
1577
    }
 
1578
 
 
1579
  return return_val;
 
1580
}
 
1581
 
 
1582
static gint
 
1583
tab_compare (gconstpointer a,
 
1584
             gconstpointer b,
 
1585
             gpointer      data)
 
1586
{
 
1587
  const GtkWidget *child1 = a;
 
1588
  const GtkWidget *child2 = b;
 
1589
  GtkTextDirection text_direction = GPOINTER_TO_INT (data);
 
1590
 
 
1591
  gint y1 = child1->allocation.y + child1->allocation.height / 2;
 
1592
  gint y2 = child2->allocation.y + child2->allocation.height / 2;
 
1593
 
 
1594
  if (y1 == y2)
 
1595
    {
 
1596
      gint x1 = child1->allocation.x + child1->allocation.width / 2;
 
1597
      gint x2 = child2->allocation.x + child2->allocation.width / 2;
 
1598
      
 
1599
      if (text_direction == GTK_TEXT_DIR_RTL) 
 
1600
        return (x1 < x2) ? 1 : ((x1 == x2) ? 0 : -1);
 
1601
      else
 
1602
        return (x1 < x2) ? -1 : ((x1 == x2) ? 0 : 1);
 
1603
    }
 
1604
  else
 
1605
    return (y1 < y2) ? -1 : 1;
 
1606
}
 
1607
 
 
1608
static GList *
 
1609
gtk_container_focus_sort_tab (GtkContainer     *container,
 
1610
                              GList            *children,
 
1611
                              GtkDirectionType  direction,
 
1612
                              GtkWidget        *old_focus)
 
1613
{
 
1614
  GtkTextDirection text_direction = gtk_widget_get_direction (GTK_WIDGET (container));
 
1615
  children = g_list_sort_with_data (children, tab_compare, GINT_TO_POINTER (text_direction));
 
1616
 
 
1617
  /* if we are going backwards then reverse the order
 
1618
   *  of the children.
 
1619
   */
 
1620
  if (direction == GTK_DIR_TAB_BACKWARD)
 
1621
    children = g_list_reverse (children);
 
1622
 
 
1623
  return children;
 
1624
}
 
1625
 
 
1626
/* Get coordinates of @widget's allocation with respect to
 
1627
 * allocation of @container.
 
1628
 */
 
1629
static gboolean
 
1630
get_allocation_coords (GtkContainer  *container,
 
1631
                       GtkWidget     *widget,
 
1632
                       GdkRectangle  *allocation)
 
1633
{
 
1634
  *allocation = widget->allocation;
 
1635
 
 
1636
  return gtk_widget_translate_coordinates (widget, GTK_WIDGET (container),
 
1637
                                           0, 0, &allocation->x, &allocation->y);
 
1638
}
 
1639
 
 
1640
/* Look for a child in @children that is intermediate between
 
1641
 * the focus widget and container. This widget, if it exists,
 
1642
 * acts as the starting widget for focus navigation.
 
1643
 */
 
1644
static GtkWidget *
 
1645
find_old_focus (GtkContainer *container,
 
1646
                GList        *children)
 
1647
{
 
1648
  GList *tmp_list = children;
 
1649
  while (tmp_list)
 
1650
    {
 
1651
      GtkWidget *child = tmp_list->data;
 
1652
      GtkWidget *widget = child;
 
1653
 
 
1654
      while (widget && widget != (GtkWidget *)container)
 
1655
        {
 
1656
          GtkWidget *parent = widget->parent;
 
1657
          if (parent && ((GtkContainer *)parent)->focus_child != widget)
 
1658
            goto next;
 
1659
 
 
1660
          widget = parent;
 
1661
        }
 
1662
 
 
1663
      return child;
 
1664
 
 
1665
    next:
 
1666
      tmp_list = tmp_list->next;
 
1667
    }
 
1668
 
 
1669
  return NULL;
 
1670
}
 
1671
 
 
1672
static gboolean
 
1673
old_focus_coords (GtkContainer *container,
 
1674
                  GdkRectangle *old_focus_rect)
 
1675
{
 
1676
  GtkWidget *widget = GTK_WIDGET (container);
 
1677
  GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
 
1678
  
 
1679
  if (toplevel && GTK_IS_WINDOW (toplevel) && GTK_WINDOW (toplevel)->focus_widget)
 
1680
    {
 
1681
      GtkWidget *old_focus = GTK_WINDOW (toplevel)->focus_widget;
 
1682
      
 
1683
      return get_allocation_coords (container, old_focus, old_focus_rect);
 
1684
    }
 
1685
  else
 
1686
    return FALSE;
 
1687
}
 
1688
 
 
1689
typedef struct _CompareInfo CompareInfo;
 
1690
 
 
1691
struct _CompareInfo
 
1692
{
 
1693
  GtkContainer *container;
 
1694
  gint x;
 
1695
  gint y;
 
1696
  gboolean reverse;
 
1697
};
 
1698
 
 
1699
static gint
 
1700
up_down_compare (gconstpointer a,
 
1701
                 gconstpointer b,
 
1702
                 gpointer      data)
 
1703
{
 
1704
  GdkRectangle allocation1;
 
1705
  GdkRectangle allocation2;
 
1706
  CompareInfo *compare = data;
 
1707
  gint y1, y2;
 
1708
 
 
1709
  get_allocation_coords (compare->container, (GtkWidget *)a, &allocation1);
 
1710
  get_allocation_coords (compare->container, (GtkWidget *)b, &allocation2);
 
1711
 
 
1712
  y1 = allocation1.y + allocation1.height / 2;
 
1713
  y2 = allocation2.y + allocation2.height / 2;
 
1714
 
 
1715
  if (y1 == y2)
 
1716
    {
 
1717
      gint x1 = abs (allocation1.x + allocation1.width / 2 - compare->x);
 
1718
      gint x2 = abs (allocation2.x + allocation2.width / 2 - compare->x);
 
1719
 
 
1720
      if (compare->reverse)
 
1721
        return (x1 < x2) ? 1 : ((x1 == x2) ? 0 : -1);
 
1722
      else
 
1723
        return (x1 < x2) ? -1 : ((x1 == x2) ? 0 : 1);
 
1724
    }
 
1725
  else
 
1726
    return (y1 < y2) ? -1 : 1;
 
1727
}
 
1728
 
 
1729
static GList *
 
1730
gtk_container_focus_sort_up_down (GtkContainer     *container,
 
1731
                                  GList            *children,
 
1732
                                  GtkDirectionType  direction,
 
1733
                                  GtkWidget        *old_focus)
 
1734
{
 
1735
  CompareInfo compare;
 
1736
  GList *tmp_list;
 
1737
  GdkRectangle old_allocation;
 
1738
 
 
1739
  compare.container = container;
 
1740
  compare.reverse = (direction == GTK_DIR_UP);
 
1741
 
 
1742
  if (!old_focus)
 
1743
      old_focus = find_old_focus (container, children);
 
1744
  
 
1745
  if (old_focus && get_allocation_coords (container, old_focus, &old_allocation))
 
1746
    {
 
1747
      gint compare_x1;
 
1748
      gint compare_x2;
 
1749
      gint compare_y;
 
1750
 
 
1751
      /* Delete widgets from list that don't match minimum criteria */
 
1752
 
 
1753
      compare_x1 = old_allocation.x;
 
1754
      compare_x2 = old_allocation.x + old_allocation.width;
 
1755
 
 
1756
      if (direction == GTK_DIR_UP)
 
1757
        compare_y = old_allocation.y;
 
1758
      else
 
1759
        compare_y = old_allocation.y + old_allocation.height;
 
1760
      
 
1761
      tmp_list = children;
 
1762
      while (tmp_list)
 
1763
        {
 
1764
          GtkWidget *child = tmp_list->data;
 
1765
          GList *next = tmp_list->next;
 
1766
          gint child_x1, child_x2;
 
1767
          GdkRectangle child_allocation;
 
1768
          
 
1769
          if (child != old_focus)
 
1770
            {
 
1771
              if (get_allocation_coords (container, child, &child_allocation))
 
1772
                {
 
1773
                  child_x1 = child_allocation.x;
 
1774
                  child_x2 = child_allocation.x + child_allocation.width;
 
1775
                  
 
1776
                  if ((child_x2 <= compare_x1 || child_x1 >= compare_x2) /* No horizontal overlap */ ||
 
1777
                      (direction == GTK_DIR_DOWN && child_allocation.y + child_allocation.height < compare_y) || /* Not below */
 
1778
                      (direction == GTK_DIR_UP && child_allocation.y > compare_y)) /* Not above */
 
1779
                    {
 
1780
                      children = g_list_delete_link (children, tmp_list);
 
1781
                    }
 
1782
                }
 
1783
              else
 
1784
                children = g_list_delete_link (children, tmp_list);
 
1785
            }
 
1786
          
 
1787
          tmp_list = next;
 
1788
        }
 
1789
 
 
1790
      compare.x = (compare_x1 + compare_x2) / 2;
 
1791
      compare.y = old_allocation.y + old_allocation.height / 2;
 
1792
    }
 
1793
  else
 
1794
    {
 
1795
      /* No old focus widget, need to figure out starting x,y some other way
 
1796
       */
 
1797
      GtkWidget *widget = GTK_WIDGET (container);
 
1798
      GdkRectangle old_focus_rect;
 
1799
 
 
1800
      if (old_focus_coords (container, &old_focus_rect))
 
1801
        {
 
1802
          compare.x = old_focus_rect.x + old_focus_rect.width / 2;
 
1803
        }
 
1804
      else
 
1805
        {
 
1806
          if (GTK_WIDGET_NO_WINDOW (widget))
 
1807
            compare.x = widget->allocation.x + widget->allocation.width / 2;
 
1808
          else
 
1809
            compare.x = widget->allocation.width / 2;
 
1810
        }
 
1811
      
 
1812
      if (GTK_WIDGET_NO_WINDOW (widget))
 
1813
        compare.y = (direction == GTK_DIR_DOWN) ? widget->allocation.y : widget->allocation.y + widget->allocation.height;
 
1814
      else
 
1815
        compare.y = (direction == GTK_DIR_DOWN) ? 0 : + widget->allocation.height;
 
1816
    }
 
1817
 
 
1818
  children = g_list_sort_with_data (children, up_down_compare, &compare);
 
1819
 
 
1820
  if (compare.reverse)
 
1821
    children = g_list_reverse (children);
 
1822
 
 
1823
  return children;
 
1824
}
 
1825
 
 
1826
static gint
 
1827
left_right_compare (gconstpointer a,
 
1828
                    gconstpointer b,
 
1829
                    gpointer      data)
 
1830
{
 
1831
  GdkRectangle allocation1;
 
1832
  GdkRectangle allocation2;
 
1833
  CompareInfo *compare = data;
 
1834
  gint x1, x2;
 
1835
 
 
1836
  get_allocation_coords (compare->container, (GtkWidget *)a, &allocation1);
 
1837
  get_allocation_coords (compare->container, (GtkWidget *)b, &allocation2);
 
1838
 
 
1839
  x1 = allocation1.x + allocation1.width / 2;
 
1840
  x2 = allocation2.x + allocation2.width / 2;
 
1841
 
 
1842
  if (x1 == x2)
 
1843
    {
 
1844
      gint y1 = abs (allocation1.y + allocation1.height / 2 - compare->y);
 
1845
      gint y2 = abs (allocation2.y + allocation2.height / 2 - compare->y);
 
1846
 
 
1847
      if (compare->reverse)
 
1848
        return (y1 < y2) ? 1 : ((y1 == y2) ? 0 : -1);
 
1849
      else
 
1850
        return (y1 < y2) ? -1 : ((y1 == y2) ? 0 : 1);
 
1851
    }
 
1852
  else
 
1853
    return (x1 < x2) ? -1 : 1;
 
1854
}
 
1855
 
 
1856
static GList *
 
1857
gtk_container_focus_sort_left_right (GtkContainer     *container,
 
1858
                                     GList            *children,
 
1859
                                     GtkDirectionType  direction,
 
1860
                                     GtkWidget        *old_focus)
 
1861
{
 
1862
  CompareInfo compare;
 
1863
  GList *tmp_list;
 
1864
  GdkRectangle old_allocation;
 
1865
 
 
1866
  compare.container = container;
 
1867
  compare.reverse = (direction == GTK_DIR_LEFT);
 
1868
 
 
1869
  if (!old_focus)
 
1870
    old_focus = find_old_focus (container, children);
 
1871
  
 
1872
  if (old_focus && get_allocation_coords (container, old_focus, &old_allocation))
 
1873
    {
 
1874
      gint compare_y1;
 
1875
      gint compare_y2;
 
1876
      gint compare_x;
 
1877
      
 
1878
      /* Delete widgets from list that don't match minimum criteria */
 
1879
 
 
1880
      compare_y1 = old_allocation.y;
 
1881
      compare_y2 = old_allocation.y + old_allocation.height;
 
1882
 
 
1883
      if (direction == GTK_DIR_LEFT)
 
1884
        compare_x = old_allocation.x;
 
1885
      else
 
1886
        compare_x = old_allocation.x + old_allocation.width;
 
1887
      
 
1888
      tmp_list = children;
 
1889
      while (tmp_list)
 
1890
        {
 
1891
          GtkWidget *child = tmp_list->data;
 
1892
          GList *next = tmp_list->next;
 
1893
          gint child_y1, child_y2;
 
1894
          GdkRectangle child_allocation;
 
1895
          
 
1896
          if (child != old_focus)
 
1897
            {
 
1898
              if (get_allocation_coords (container, child, &child_allocation))
 
1899
                {
 
1900
                  child_y1 = child_allocation.y;
 
1901
                  child_y2 = child_allocation.y + child_allocation.height;
 
1902
                  
 
1903
                  if ((child_y2 <= compare_y1 || child_y1 >= compare_y2) /* No vertical overlap */ ||
 
1904
                      (direction == GTK_DIR_RIGHT && child_allocation.x + child_allocation.width < compare_x) || /* Not to left */
 
1905
                      (direction == GTK_DIR_LEFT && child_allocation.x > compare_x)) /* Not to right */
 
1906
                    {
 
1907
                      children = g_list_delete_link (children, tmp_list);
 
1908
                    }
 
1909
                }
 
1910
              else
 
1911
                children = g_list_delete_link (children, tmp_list);
 
1912
            }
 
1913
          
 
1914
          tmp_list = next;
 
1915
        }
 
1916
 
 
1917
      compare.y = (compare_y1 + compare_y2) / 2;
 
1918
      compare.x = old_allocation.x + old_allocation.width / 2;
 
1919
    }
 
1920
  else
 
1921
    {
 
1922
      /* No old focus widget, need to figure out starting x,y some other way
 
1923
       */
 
1924
      GtkWidget *widget = GTK_WIDGET (container);
 
1925
      GdkRectangle old_focus_rect;
 
1926
 
 
1927
      if (old_focus_coords (container, &old_focus_rect))
 
1928
        {
 
1929
          compare.y = old_focus_rect.y + old_focus_rect.height / 2;
 
1930
        }
 
1931
      else
 
1932
        {
 
1933
          if (GTK_WIDGET_NO_WINDOW (widget))
 
1934
            compare.y = widget->allocation.y + widget->allocation.height / 2;
 
1935
          else
 
1936
            compare.y = widget->allocation.height / 2;
 
1937
        }
 
1938
      
 
1939
      if (GTK_WIDGET_NO_WINDOW (widget))
 
1940
        compare.x = (direction == GTK_DIR_RIGHT) ? widget->allocation.x : widget->allocation.x + widget->allocation.width;
 
1941
      else
 
1942
        compare.x = (direction == GTK_DIR_RIGHT) ? 0 : widget->allocation.width;
 
1943
    }
 
1944
 
 
1945
  children = g_list_sort_with_data (children, left_right_compare, &compare);
 
1946
 
 
1947
  if (compare.reverse)
 
1948
    children = g_list_reverse (children);
 
1949
 
 
1950
  return children;
 
1951
}
 
1952
 
 
1953
/**
 
1954
 * gtk_container_focus_sort:
 
1955
 * @container: a #GtkContainer
 
1956
 * @children:  a list of descendents of @container (they don't
 
1957
 *             have to be direct children.
 
1958
 * @direction: focus direction
 
1959
 * @old_focus: widget to use for the starting position, or %NULL
 
1960
 *             to determine this automatically.
 
1961
 *             [ Note, this argument isn't used for GTK_DIR_TAB_*,
 
1962
 *               which is the only @direction we use currently,
 
1963
 *               so perhaps this argument should be removed ]
 
1964
 * 
 
1965
 * Sorts @children in the correct order for focusing with
 
1966
 * direction type @direction.
 
1967
 * 
 
1968
 * Return value: a copy of @children, sorted in correct focusing order,
 
1969
 *   with children that aren't suitable for focusing in this direction
 
1970
 *   removed.
 
1971
 **/
 
1972
GList *
 
1973
_gtk_container_focus_sort (GtkContainer     *container,
 
1974
                           GList            *children,
 
1975
                           GtkDirectionType  direction,
 
1976
                           GtkWidget        *old_focus)
 
1977
{
 
1978
  GList *visible_children = NULL;
 
1979
 
 
1980
  while (children)
 
1981
    {
 
1982
      if (GTK_WIDGET_REALIZED (children->data))
 
1983
        visible_children = g_list_prepend (visible_children, children->data);
 
1984
      children = children->next;
 
1985
    }
 
1986
  
 
1987
  switch (direction)
 
1988
    {
 
1989
    case GTK_DIR_TAB_FORWARD:
 
1990
    case GTK_DIR_TAB_BACKWARD:
 
1991
      return gtk_container_focus_sort_tab (container, visible_children, direction, old_focus);
 
1992
    case GTK_DIR_UP:
 
1993
    case GTK_DIR_DOWN:
 
1994
      return gtk_container_focus_sort_up_down (container, visible_children, direction, old_focus);
 
1995
    case GTK_DIR_LEFT:
 
1996
    case GTK_DIR_RIGHT:
 
1997
      return gtk_container_focus_sort_left_right (container, visible_children, direction, old_focus);
 
1998
    }
 
1999
 
 
2000
  g_assert_not_reached ();
 
2001
 
 
2002
  return NULL;
 
2003
}
 
2004
 
 
2005
static gboolean
 
2006
gtk_container_focus_move (GtkContainer     *container,
 
2007
                          GList            *children,
 
2008
                          GtkDirectionType  direction)
 
2009
{
 
2010
  GtkWidget *focus_child;
 
2011
  GtkWidget *child;
 
2012
 
 
2013
  focus_child = container->focus_child;
 
2014
 
 
2015
  while (children)
 
2016
    {
 
2017
      child = children->data;
 
2018
      children = children->next;
 
2019
 
 
2020
      if (!child)
 
2021
        continue;
 
2022
      
 
2023
      if (focus_child)
 
2024
        {
 
2025
          if (focus_child == child)
 
2026
            {
 
2027
              focus_child = NULL;
 
2028
 
 
2029
                if (gtk_widget_child_focus (child, direction))
 
2030
                  return TRUE;
 
2031
            }
 
2032
        }
 
2033
      else if (GTK_WIDGET_DRAWABLE (child) &&
 
2034
               gtk_widget_is_ancestor (child, GTK_WIDGET (container)))
 
2035
        {
 
2036
          if (gtk_widget_child_focus (child, direction))
 
2037
            return TRUE;
 
2038
        }
 
2039
    }
 
2040
 
 
2041
  return FALSE;
 
2042
}
 
2043
 
 
2044
 
 
2045
static void
 
2046
gtk_container_children_callback (GtkWidget *widget,
 
2047
                                 gpointer   client_data)
 
2048
{
 
2049
  GList **children;
 
2050
 
 
2051
  children = (GList**) client_data;
 
2052
  *children = g_list_prepend (*children, widget);
 
2053
}
 
2054
 
 
2055
static void
 
2056
chain_widget_destroyed (GtkWidget *widget,
 
2057
                        gpointer   user_data)
 
2058
{
 
2059
  GtkContainer *container;
 
2060
  GList *chain;
 
2061
  
 
2062
  container = GTK_CONTAINER (user_data);
 
2063
 
 
2064
  chain = g_object_get_data (G_OBJECT (container),
 
2065
                             "gtk-container-focus-chain");
 
2066
 
 
2067
  chain = g_list_remove (chain, widget);
 
2068
 
 
2069
  g_signal_handlers_disconnect_by_func (widget,
 
2070
                                        chain_widget_destroyed,
 
2071
                                        user_data);
 
2072
  
 
2073
  g_object_set_data (G_OBJECT (container),
 
2074
                     I_("gtk-container-focus-chain"),
 
2075
                     chain);  
 
2076
}
 
2077
 
 
2078
/**
 
2079
 * gtk_container_set_focus_chain: 
 
2080
 * @container: a #GtkContainer.
 
2081
 * @focusable_widgets: the new focus chain.
 
2082
 *
 
2083
 * Sets a focus chain, overriding the one computed automatically by GTK+.
 
2084
 * 
 
2085
 * In principle each widget in the chain should be a descendant of the 
 
2086
 * container, but this is not enforced by this method, since it's allowed 
 
2087
 * to set the focus chain before you pack the widgets, or have a widget 
 
2088
 * in the chain that isn't always packed. The necessary checks are done 
 
2089
 * when the focus chain is actually traversed.
 
2090
 **/
 
2091
void
 
2092
gtk_container_set_focus_chain (GtkContainer *container,
 
2093
                               GList        *focusable_widgets)
 
2094
{
 
2095
  GList *chain;
 
2096
  GList *tmp_list;
 
2097
  
 
2098
  g_return_if_fail (GTK_IS_CONTAINER (container));
 
2099
  
 
2100
  if (container->has_focus_chain)
 
2101
    gtk_container_unset_focus_chain (container);
 
2102
 
 
2103
  container->has_focus_chain = TRUE;
 
2104
  
 
2105
  chain = NULL;
 
2106
  tmp_list = focusable_widgets;
 
2107
  while (tmp_list != NULL)
 
2108
    {
 
2109
      g_return_if_fail (GTK_IS_WIDGET (tmp_list->data));
 
2110
      
 
2111
      /* In principle each widget in the chain should be a descendant
 
2112
       * of the container, but we don't want to check that here, it's
 
2113
       * expensive and also it's allowed to set the focus chain before
 
2114
       * you pack the widgets, or have a widget in the chain that isn't
 
2115
       * always packed. So we check for ancestor during actual traversal.
 
2116
       */
 
2117
 
 
2118
      chain = g_list_prepend (chain, tmp_list->data);
 
2119
 
 
2120
      g_signal_connect (tmp_list->data,
 
2121
                        "destroy",
 
2122
                        G_CALLBACK (chain_widget_destroyed),
 
2123
                        container);
 
2124
      
 
2125
      tmp_list = g_list_next (tmp_list);
 
2126
    }
 
2127
 
 
2128
  chain = g_list_reverse (chain);
 
2129
  
 
2130
  g_object_set_data (G_OBJECT (container),
 
2131
                     I_("gtk-container-focus-chain"),
 
2132
                     chain);
 
2133
}
 
2134
 
 
2135
/**
 
2136
 * gtk_container_get_focus_chain:
 
2137
 * @container:         a #GtkContainer
 
2138
 * @focusable_widgets: location to store the focus chain of the
 
2139
 *                     container, or %NULL. You should free this list
 
2140
 *                     using g_list_free() when you are done with it, however
 
2141
 *                     no additional reference count is added to the
 
2142
 *                     individual widgets in the focus chain.
 
2143
 * 
 
2144
 * Retrieves the focus chain of the container, if one has been
 
2145
 * set explicitly. If no focus chain has been explicitly
 
2146
 * set, GTK+ computes the focus chain based on the positions
 
2147
 * of the children. In that case, GTK+ stores %NULL in
 
2148
 * @focusable_widgets and returns %FALSE.
 
2149
 *
 
2150
 * Return value: %TRUE if the focus chain of the container 
 
2151
 * has been set explicitly.
 
2152
 **/
 
2153
gboolean
 
2154
gtk_container_get_focus_chain (GtkContainer *container,
 
2155
                               GList       **focus_chain)
 
2156
{
 
2157
  g_return_val_if_fail (GTK_IS_CONTAINER (container), FALSE);
 
2158
 
 
2159
  if (focus_chain)
 
2160
    {
 
2161
      if (container->has_focus_chain)
 
2162
        *focus_chain = g_list_copy (get_focus_chain (container));
 
2163
      else
 
2164
        *focus_chain = NULL;
 
2165
    }
 
2166
 
 
2167
  return container->has_focus_chain;
 
2168
}
 
2169
 
 
2170
/**
 
2171
 * gtk_container_unset_focus_chain:
 
2172
 * @container: a #GtkContainer.
 
2173
 * 
 
2174
 * Removes a focus chain explicitly set with gtk_container_set_focus_chain().
 
2175
 **/
 
2176
void
 
2177
gtk_container_unset_focus_chain (GtkContainer  *container)
 
2178
{  
 
2179
  g_return_if_fail (GTK_IS_CONTAINER (container));
 
2180
 
 
2181
  if (container->has_focus_chain)
 
2182
    {
 
2183
      GList *chain;
 
2184
      GList *tmp_list;
 
2185
      
 
2186
      chain = get_focus_chain (container);
 
2187
      
 
2188
      container->has_focus_chain = FALSE;
 
2189
      
 
2190
      g_object_set_data (G_OBJECT (container), 
 
2191
                         I_("gtk-container-focus-chain"),
 
2192
                         NULL);
 
2193
 
 
2194
      tmp_list = chain;
 
2195
      while (tmp_list != NULL)
 
2196
        {
 
2197
          g_signal_handlers_disconnect_by_func (tmp_list->data,
 
2198
                                                chain_widget_destroyed,
 
2199
                                                container);
 
2200
          
 
2201
          tmp_list = g_list_next (tmp_list);
 
2202
        }
 
2203
 
 
2204
      g_list_free (chain);
 
2205
    }
 
2206
}
 
2207
 
 
2208
/**
 
2209
 * gtk_container_set_focus_vadjustment:
 
2210
 * @container: a #GtkContainer
 
2211
 * @adjustment: an adjustment which should be adjusted when the focus is moved among the
 
2212
 *   descendents of @container
 
2213
 * 
 
2214
 * Hooks up an adjustment to focus handling in a container, so when a child of the 
 
2215
 * container is focused, the adjustment is scrolled to show that widget. This function
 
2216
 * sets the vertical alignment. See gtk_scrolled_window_get_vadjustment() for a typical
 
2217
 * way of obtaining the adjustment and gtk_container_set_focus_hadjustment() for setting
 
2218
 * the horizontal adjustment.
 
2219
 *
 
2220
 * The adjustments have to be in pixel units and in the same coordinate system as the 
 
2221
 * allocation for immediate children of the container. 
 
2222
 */
 
2223
void
 
2224
gtk_container_set_focus_vadjustment (GtkContainer  *container,
 
2225
                                     GtkAdjustment *adjustment)
 
2226
{
 
2227
  g_return_if_fail (GTK_IS_CONTAINER (container));
 
2228
  if (adjustment)
 
2229
    g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
 
2230
 
 
2231
  if (adjustment)
 
2232
    g_object_ref (adjustment);
 
2233
 
 
2234
  g_object_set_qdata_full (G_OBJECT (container),
 
2235
                           vadjustment_key_id,
 
2236
                           adjustment,
 
2237
                           g_object_unref);
 
2238
}
 
2239
 
 
2240
/**
 
2241
 * gtk_container_get_focus_vadjustment:
 
2242
 * @container: a #GtkContainer
 
2243
 *
 
2244
 * Retrieves the vertical focus adjustment for the container. See
 
2245
 * gtk_container_set_focus_vadjustment ().
 
2246
 *
 
2247
 * Return value: the vertical focus adjustment, or %NULL if
 
2248
 *   none has been set.
 
2249
 **/
 
2250
GtkAdjustment *
 
2251
gtk_container_get_focus_vadjustment (GtkContainer *container)
 
2252
{
 
2253
  GtkAdjustment *vadjustment;
 
2254
    
 
2255
  g_return_val_if_fail (GTK_IS_CONTAINER (container), NULL);
 
2256
 
 
2257
  vadjustment = g_object_get_qdata (G_OBJECT (container), vadjustment_key_id);
 
2258
 
 
2259
  return vadjustment;
 
2260
}
 
2261
 
 
2262
/**
 
2263
 * gtk_container_set_focus_hadjustment:
 
2264
 * @container: a #GtkContainer
 
2265
 * @adjustment: an adjustment which should be adjusted when the focus is moved among the
 
2266
 *   descendents of @container
 
2267
 * 
 
2268
 * Hooks up an adjustment to focus handling in a container, so when a child of the 
 
2269
 * container is focused, the adjustment is scrolled to show that widget. This function
 
2270
 * sets the horizontal alignment. See gtk_scrolled_window_get_hadjustment() for a typical
 
2271
 * way of obtaining the adjustment and gtk_container_set_focus_vadjustment() for setting
 
2272
 * the vertical adjustment.
 
2273
 *
 
2274
 * The adjustments have to be in pixel units and in the same coordinate system as the 
 
2275
 * allocation for immediate children of the container. 
 
2276
 */
 
2277
void
 
2278
gtk_container_set_focus_hadjustment (GtkContainer  *container,
 
2279
                                     GtkAdjustment *adjustment)
 
2280
{
 
2281
  g_return_if_fail (GTK_IS_CONTAINER (container));
 
2282
  if (adjustment)
 
2283
    g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
 
2284
 
 
2285
  if (adjustment)
 
2286
    g_object_ref (adjustment);
 
2287
 
 
2288
  g_object_set_qdata_full (G_OBJECT (container),
 
2289
                           hadjustment_key_id,
 
2290
                           adjustment,
 
2291
                           g_object_unref);
 
2292
}
 
2293
 
 
2294
/**
 
2295
 * gtk_container_get_focus_hadjustment:
 
2296
 * @container: a #GtkContainer
 
2297
 *
 
2298
 * Retrieves the horizontal focus adjustment for the container. See
 
2299
 * gtk_container_set_focus_hadjustment ().
 
2300
 *
 
2301
 * Return value: the horizontal focus adjustment, or %NULL if
 
2302
 *   none has been set.
 
2303
 **/
 
2304
GtkAdjustment *
 
2305
gtk_container_get_focus_hadjustment (GtkContainer *container)
 
2306
{
 
2307
  GtkAdjustment *hadjustment;
 
2308
 
 
2309
  g_return_val_if_fail (GTK_IS_CONTAINER (container), NULL);
 
2310
 
 
2311
  hadjustment = g_object_get_qdata (G_OBJECT (container), hadjustment_key_id);
 
2312
 
 
2313
  return hadjustment;
 
2314
}
 
2315
 
 
2316
 
 
2317
static void
 
2318
gtk_container_show_all (GtkWidget *widget)
 
2319
{
 
2320
  g_return_if_fail (GTK_IS_CONTAINER (widget));
 
2321
 
 
2322
  gtk_container_foreach (GTK_CONTAINER (widget),
 
2323
                         (GtkCallback) gtk_widget_show_all,
 
2324
                         NULL);
 
2325
  gtk_widget_show (widget);
 
2326
}
 
2327
 
 
2328
static void
 
2329
gtk_container_hide_all (GtkWidget *widget)
 
2330
{
 
2331
  g_return_if_fail (GTK_IS_CONTAINER (widget));
 
2332
 
 
2333
  gtk_widget_hide (widget);
 
2334
  gtk_container_foreach (GTK_CONTAINER (widget),
 
2335
                         (GtkCallback) gtk_widget_hide_all,
 
2336
                         NULL);
 
2337
}
 
2338
 
 
2339
 
 
2340
static void
 
2341
gtk_container_expose_child (GtkWidget *child,
 
2342
                            gpointer   client_data)
 
2343
{
 
2344
  struct {
 
2345
    GtkWidget *container;
 
2346
    GdkEventExpose *event;
 
2347
  } *data = client_data;
 
2348
  
 
2349
  gtk_container_propagate_expose (GTK_CONTAINER (data->container),
 
2350
                                  child,
 
2351
                                  data->event);
 
2352
}
 
2353
 
 
2354
static gint 
 
2355
gtk_container_expose (GtkWidget      *widget,
 
2356
                      GdkEventExpose *event)
 
2357
{
 
2358
  struct {
 
2359
    GtkWidget *container;
 
2360
    GdkEventExpose *event;
 
2361
  } data;
 
2362
 
 
2363
  g_return_val_if_fail (GTK_IS_CONTAINER (widget), FALSE);
 
2364
  g_return_val_if_fail (event != NULL, FALSE);
 
2365
 
 
2366
  
 
2367
  if (GTK_WIDGET_DRAWABLE (widget)) 
 
2368
    {
 
2369
      data.container = widget;
 
2370
      data.event = event;
 
2371
      
 
2372
      gtk_container_forall (GTK_CONTAINER (widget),
 
2373
                            gtk_container_expose_child,
 
2374
                            &data);
 
2375
    }   
 
2376
  
 
2377
  return FALSE;
 
2378
}
 
2379
 
 
2380
static void
 
2381
gtk_container_map_child (GtkWidget *child,
 
2382
                         gpointer   client_data)
 
2383
{
 
2384
  if (GTK_WIDGET_VISIBLE (child) &&
 
2385
      GTK_WIDGET_CHILD_VISIBLE (child) &&
 
2386
      !GTK_WIDGET_MAPPED (child))
 
2387
    gtk_widget_map (child);
 
2388
}
 
2389
 
 
2390
static void
 
2391
gtk_container_map (GtkWidget *widget)
 
2392
{
 
2393
  GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
 
2394
 
 
2395
  gtk_container_forall (GTK_CONTAINER (widget),
 
2396
                        gtk_container_map_child,
 
2397
                        NULL);
 
2398
 
 
2399
  if (!GTK_WIDGET_NO_WINDOW (widget))
 
2400
    gdk_window_show (widget->window);
 
2401
}
 
2402
 
 
2403
static void
 
2404
gtk_container_unmap (GtkWidget *widget)
 
2405
{
 
2406
  GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
 
2407
 
 
2408
  if (!GTK_WIDGET_NO_WINDOW (widget))
 
2409
    gdk_window_hide (widget->window);
 
2410
  else
 
2411
    gtk_container_forall (GTK_CONTAINER (widget),
 
2412
                          (GtkCallback)gtk_widget_unmap,
 
2413
                          NULL);
 
2414
}
 
2415
 
 
2416
/**
 
2417
 * gtk_container_propagate_expose:
 
2418
 * @container: a #GtkContainer
 
2419
 * @child: a child of @container
 
2420
 * @event: a expose event sent to container
 
2421
 *
 
2422
 * When a container receives an expose event, it must send synthetic
 
2423
 * expose events to all children that don't have their own #GdkWindows.
 
2424
 * This function provides a convenient way of doing this. A container,
 
2425
 * when it receives an expose event, calls gtk_container_propagate_expose() 
 
2426
 * once for each child, passing in the event the container received.
 
2427
 *
 
2428
 * gtk_container_propagate_expose() takes care of deciding whether
 
2429
 * an expose event needs to be sent to the child, intersecting
 
2430
 * the event's area with the child area, and sending the event.
 
2431
 * 
 
2432
 * In most cases, a container can simply either simply inherit the
 
2433
 * ::expose implementation from #GtkContainer, or, do some drawing 
 
2434
 * and then chain to the ::expose implementation from #GtkContainer.
 
2435
 **/
 
2436
void
 
2437
gtk_container_propagate_expose (GtkContainer   *container,
 
2438
                                GtkWidget      *child,
 
2439
                                GdkEventExpose *event)
 
2440
{
 
2441
  GdkEvent *child_event;
 
2442
 
 
2443
  g_return_if_fail (GTK_IS_CONTAINER (container));
 
2444
  g_return_if_fail (GTK_IS_WIDGET (child));
 
2445
  g_return_if_fail (event != NULL);
 
2446
 
 
2447
  g_assert (child->parent == GTK_WIDGET (container));
 
2448
  
 
2449
  if (GTK_WIDGET_DRAWABLE (child) &&
 
2450
      GTK_WIDGET_NO_WINDOW (child) &&
 
2451
      (child->window == event->window))
 
2452
    {
 
2453
      child_event = gdk_event_new (GDK_EXPOSE);
 
2454
      child_event->expose = *event;
 
2455
      g_object_ref (child_event->expose.window);
 
2456
 
 
2457
      child_event->expose.region = gtk_widget_region_intersect (child, event->region);
 
2458
      if (!gdk_region_empty (child_event->expose.region))
 
2459
        {
 
2460
          gdk_region_get_clipbox (child_event->expose.region, &child_event->expose.area);
 
2461
          gtk_widget_send_expose (child, child_event);
 
2462
        }
 
2463
      gdk_event_free (child_event);
 
2464
    }
 
2465
}
 
2466
 
 
2467
#define __GTK_CONTAINER_C__
 
2468
#include "gtkaliasdef.c"