gtkcontainer.c 76.3 KB
Newer Older
Elliot Lee's avatar
Elliot Lee committed
1 2 3 4
/* GTK - The GIMP Toolkit
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * This library is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
Elliot Lee's avatar
Elliot Lee committed
6 7 8 9 10 11
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 * Lesser General Public License for more details.
Elliot Lee's avatar
Elliot Lee committed
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
15 16 17
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
Elliot Lee's avatar
Elliot Lee committed
18
 */
19 20

/*
21
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22 23 24 25 26
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
 */

27
#include <config.h>
28
#include <stdarg.h>
Elliot Lee's avatar
Elliot Lee committed
29
#include <string.h>
30 31
#include <stdlib.h>

Elliot Lee's avatar
Elliot Lee committed
32
#include "gtkcontainer.h"
Johan Dahlin's avatar
Johan Dahlin committed
33
#include "gtkbuildable.h"
34
#include "gtkprivate.h"
35
#include "gtkmain.h"
36
#include "gtkmarshalers.h"
37
#include "gtkwindow.h"
Alexander Larsson's avatar
Alexander Larsson committed
38
#include "gtkintl.h"
39
#include "gtktoolbar.h"
Tim Janik's avatar
Tim Janik committed
40 41
#include <gobject/gobjectnotifyqueue.c>
#include <gobject/gvaluecollector.h>
42
#include "gtkalias.h"
Tim Janik's avatar
Tim Janik committed
43

Elliot Lee's avatar
Elliot Lee committed
44 45 46 47

enum {
  ADD,
  REMOVE,
48
  CHECK_RESIZE,
49
  SET_FOCUS_CHILD,
Elliot Lee's avatar
Elliot Lee committed
50 51
  LAST_SIGNAL
};
52

53
enum {
Alexander Larsson's avatar
Alexander Larsson committed
54 55 56
  PROP_0,
  PROP_BORDER_WIDTH,
  PROP_RESIZE_MODE,
57
  PROP_CHILD
58
};
Elliot Lee's avatar
Elliot Lee committed
59

Tim Janik's avatar
Tim Janik committed
60 61
#define PARAM_SPEC_PARAM_ID(pspec)              ((pspec)->param_id)
#define PARAM_SPEC_SET_PARAM_ID(pspec, id)      ((pspec)->param_id = (id))
62

Tim Janik's avatar
Tim Janik committed
63 64

/* --- prototypes --- */
65
static void     gtk_container_base_class_init      (GtkContainerClass *klass);
Tim Janik's avatar
Tim Janik committed
66
static void     gtk_container_base_class_finalize  (GtkContainerClass *klass);
67 68 69
static void     gtk_container_class_init           (GtkContainerClass *klass);
static void     gtk_container_init                 (GtkContainer      *container);
static void     gtk_container_destroy              (GtkObject         *object);
Alexander Larsson's avatar
Alexander Larsson committed
70 71 72 73 74 75 76 77
static void     gtk_container_set_property         (GObject         *object,
						    guint            prop_id,
						    const GValue    *value,
						    GParamSpec      *pspec);
static void     gtk_container_get_property         (GObject         *object,
						    guint            prop_id,
						    GValue          *value,
						    GParamSpec      *pspec);
78 79 80 81 82
static void     gtk_container_add_unimplemented    (GtkContainer      *container,
						    GtkWidget         *widget);
static void     gtk_container_remove_unimplemented (GtkContainer      *container,
						    GtkWidget         *widget);
static void     gtk_container_real_check_resize    (GtkContainer      *container);
83
static gboolean gtk_container_focus                (GtkWidget         *widget,
84 85 86
						    GtkDirectionType   direction);
static void     gtk_container_real_set_focus_child (GtkContainer      *container,
						    GtkWidget         *widget);
87

88 89 90 91 92 93 94
static gboolean gtk_container_focus_move           (GtkContainer      *container,
						    GList             *children,
						    GtkDirectionType   direction);
static void     gtk_container_children_callback    (GtkWidget         *widget,
						    gpointer           client_data);
static void     gtk_container_show_all             (GtkWidget         *widget);
static void     gtk_container_hide_all             (GtkWidget         *widget);
95 96
static gint     gtk_container_expose               (GtkWidget         *widget,
						    GdkEventExpose    *event);
97 98 99
static void     gtk_container_map                  (GtkWidget         *widget);
static void     gtk_container_unmap                (GtkWidget         *widget);

100 101 102
static gchar* gtk_container_child_default_composite_name (GtkContainer *container,
							  GtkWidget    *child);

Johan Dahlin's avatar
Johan Dahlin committed
103 104
/* GtkBuildable */
static void gtk_container_buildable_init           (GtkBuildableIface *iface);
105
static void gtk_container_buildable_add_child      (GtkBuildable *buildable,
Johan Dahlin's avatar
Johan Dahlin committed
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
						    GtkBuilder   *builder,
						    GObject      *child,
						    const gchar  *type);
static gboolean gtk_container_buildable_custom_tag_start (GtkBuildable  *buildable,
							  GtkBuilder    *builder,
							  GObject       *child,
							  const gchar   *tagname,
							  GMarkupParser *parser,
							  gpointer      *data);
static void    gtk_container_buildable_custom_tag_end (GtkBuildable *buildable,
						       GtkBuilder   *builder,
						       GObject      *child,
						       const gchar  *tagname,
						       gpointer     *data);

Elliot Lee's avatar
Elliot Lee committed
121

Tim Janik's avatar
Tim Janik committed
122
/* --- variables --- */
123
static const gchar           vadjustment_key[] = "gtk-vadjustment";
Tim Janik's avatar
Tim Janik committed
124
static guint                 vadjustment_key_id = 0;
125
static const gchar           hadjustment_key[] = "gtk-hadjustment";
Tim Janik's avatar
Tim Janik committed
126 127 128 129 130 131
static guint                 hadjustment_key_id = 0;
static GSList	            *container_resize_queue = NULL;
static guint                 container_signals[LAST_SIGNAL] = { 0 };
static GtkWidgetClass       *parent_class = NULL;
extern GParamSpecPool       *_gtk_widget_child_property_pool;
extern GObjectNotifyContext *_gtk_widget_child_property_notify_context;
Johan Dahlin's avatar
Johan Dahlin committed
132
static GtkBuildableIface    *parent_buildable_iface;
Elliot Lee's avatar
Elliot Lee committed
133

134

Tim Janik's avatar
Tim Janik committed
135
/* --- functions --- */
Manish Singh's avatar
Manish Singh committed
136
GType
137
gtk_container_get_type (void)
Elliot Lee's avatar
Elliot Lee committed
138
{
Manish Singh's avatar
Manish Singh committed
139
  static GType container_type = 0;
Elliot Lee's avatar
Elliot Lee committed
140 141 142

  if (!container_type)
    {
143
      const GTypeInfo container_info =
Manish Singh's avatar
Manish Singh committed
144
      {
Elliot Lee's avatar
Elliot Lee committed
145
	sizeof (GtkContainerClass),
Tim Janik's avatar
Tim Janik committed
146 147 148
	(GBaseInitFunc) gtk_container_base_class_init,
	(GBaseFinalizeFunc) gtk_container_base_class_finalize,
	(GClassInitFunc) gtk_container_class_init,
Manish Singh's avatar
Manish Singh committed
149
	NULL        /* class_finalize */,
Tim Janik's avatar
Tim Janik committed
150 151 152 153 154
	NULL        /* class_data */,
	sizeof (GtkContainer),
	0           /* n_preallocs */,
	(GInstanceInitFunc) gtk_container_init,
	NULL,       /* value_table */
Elliot Lee's avatar
Elliot Lee committed
155 156
      };

Johan Dahlin's avatar
Johan Dahlin committed
157 158 159 160 161 162 163
      static const GInterfaceInfo buildable_info =
      {
	(GInterfaceInitFunc) gtk_container_buildable_init,
	NULL,
	NULL
      };

Manish Singh's avatar
Manish Singh committed
164
      container_type =
Matthias Clasen's avatar
Matthias Clasen committed
165
	g_type_register_static (GTK_TYPE_WIDGET, I_("GtkContainer"), 
Manish Singh's avatar
Manish Singh committed
166
				&container_info, G_TYPE_FLAG_ABSTRACT);
Johan Dahlin's avatar
Johan Dahlin committed
167 168 169 170 171

      g_type_add_interface_static (container_type,
				   GTK_TYPE_BUILDABLE,
				   &buildable_info);

Elliot Lee's avatar
Elliot Lee committed
172 173 174 175 176
    }

  return container_type;
}

177 178 179 180
static void
gtk_container_base_class_init (GtkContainerClass *class)
{
  /* reset instance specifc class fields that don't get inherited */
Tim Janik's avatar
Tim Janik committed
181 182
  class->set_child_property = NULL;
  class->get_child_property = NULL;
183 184
}

Elliot Lee's avatar
Elliot Lee committed
185
static void
Tim Janik's avatar
Tim Janik committed
186
gtk_container_base_class_finalize (GtkContainerClass *class)
Elliot Lee's avatar
Elliot Lee committed
187
{
Tim Janik's avatar
Tim Janik committed
188
  GList *list, *node;
Elliot Lee's avatar
Elliot Lee committed
189

190
  list = g_param_spec_pool_list_owned (_gtk_widget_child_property_pool, G_OBJECT_CLASS_TYPE (class));
Tim Janik's avatar
Tim Janik committed
191 192 193
  for (node = list; node; node = node->next)
    {
      GParamSpec *pspec = node->data;
194

Tim Janik's avatar
Tim Janik committed
195 196 197 198 199 200 201 202 203 204 205 206 207
      g_param_spec_pool_remove (_gtk_widget_child_property_pool, pspec);
      PARAM_SPEC_SET_PARAM_ID (pspec, 0);
      g_param_spec_unref (pspec);
    }
  g_list_free (list);
}

static void
gtk_container_class_init (GtkContainerClass *class)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
  GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
208

Tim Janik's avatar
Tim Janik committed
209
  parent_class = g_type_class_peek_parent (class);
210

211 212
  vadjustment_key_id = g_quark_from_static_string (vadjustment_key);
  hadjustment_key_id = g_quark_from_static_string (hadjustment_key);
213
  
Alexander Larsson's avatar
Alexander Larsson committed
214 215 216
  gobject_class->set_property = gtk_container_set_property;
  gobject_class->get_property = gtk_container_get_property;

Tim Janik's avatar
Tim Janik committed
217 218 219 220 221
  object_class->destroy = gtk_container_destroy;

  widget_class->show_all = gtk_container_show_all;
  widget_class->hide_all = gtk_container_hide_all;
  widget_class->expose_event = gtk_container_expose;
222 223
  widget_class->map = gtk_container_map;
  widget_class->unmap = gtk_container_unmap;
Tim Janik's avatar
Tim Janik committed
224 225 226 227 228 229 230 231 232 233
  widget_class->focus = gtk_container_focus;
  
  class->add = gtk_container_add_unimplemented;
  class->remove = gtk_container_remove_unimplemented;
  class->check_resize = gtk_container_real_check_resize;
  class->forall = NULL;
  class->set_focus_child = gtk_container_real_set_focus_child;
  class->child_type = NULL;
  class->composite_name = gtk_container_child_default_composite_name;

Alexander Larsson's avatar
Alexander Larsson committed
234 235
  g_object_class_install_property (gobject_class,
                                   PROP_RESIZE_MODE,
Matthias Clasen's avatar
x  
Matthias Clasen committed
236
                                   g_param_spec_enum ("resize-mode",
237 238
                                                      P_("Resize mode"),
                                                      P_("Specify how resize events are handled"),
Alexander Larsson's avatar
Alexander Larsson committed
239 240
                                                      GTK_TYPE_RESIZE_MODE,
                                                      GTK_RESIZE_PARENT,
241
                                                      GTK_PARAM_READWRITE));
Alexander Larsson's avatar
Alexander Larsson committed
242 243
  g_object_class_install_property (gobject_class,
                                   PROP_BORDER_WIDTH,
Matthias Clasen's avatar
x  
Matthias Clasen committed
244
                                   g_param_spec_uint ("border-width",
245 246
                                                      P_("Border width"),
                                                      P_("The width of the empty border outside the containers children"),
Alexander Larsson's avatar
Alexander Larsson committed
247 248 249
						      0,
						      G_MAXINT,
						      0,
250
                                                      GTK_PARAM_READWRITE));
Alexander Larsson's avatar
Alexander Larsson committed
251 252 253
  g_object_class_install_property (gobject_class,
                                   PROP_CHILD,
                                   g_param_spec_object ("child",
254 255
                                                      P_("Child"),
                                                      P_("Can be used to add a new child to the container"),
Alexander Larsson's avatar
Alexander Larsson committed
256
                                                      GTK_TYPE_WIDGET,
257
						      GTK_PARAM_WRITABLE));
Elliot Lee's avatar
Elliot Lee committed
258
  container_signals[ADD] =
Matthias Clasen's avatar
Matthias Clasen committed
259
    g_signal_new (I_("add"),
Manish Singh's avatar
Manish Singh committed
260 261 262 263 264 265 266
		  G_OBJECT_CLASS_TYPE (object_class),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GtkContainerClass, add),
		  NULL, NULL,
		  _gtk_marshal_VOID__OBJECT,
		  G_TYPE_NONE, 1,
		  GTK_TYPE_WIDGET);
Elliot Lee's avatar
Elliot Lee committed
267
  container_signals[REMOVE] =
Matthias Clasen's avatar
Matthias Clasen committed
268
    g_signal_new (I_("remove"),
Manish Singh's avatar
Manish Singh committed
269 270 271 272 273 274 275
		  G_OBJECT_CLASS_TYPE (object_class),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GtkContainerClass, remove),
		  NULL, NULL,
		  _gtk_marshal_VOID__OBJECT,
		  G_TYPE_NONE, 1,
		  GTK_TYPE_WIDGET);
276
  container_signals[CHECK_RESIZE] =
Matthias Clasen's avatar
Matthias Clasen committed
277
    g_signal_new (I_("check_resize"),
Manish Singh's avatar
Manish Singh committed
278 279 280 281 282 283
		  G_OBJECT_CLASS_TYPE (object_class),
		  G_SIGNAL_RUN_LAST,
		  G_STRUCT_OFFSET (GtkContainerClass, check_resize),
		  NULL, NULL,
		  _gtk_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);
284
  container_signals[SET_FOCUS_CHILD] =
Matthias Clasen's avatar
Matthias Clasen committed
285
    g_signal_new (I_("set-focus-child"),
Manish Singh's avatar
Manish Singh committed
286 287 288 289 290 291 292
		  G_OBJECT_CLASS_TYPE (object_class),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GtkContainerClass, set_focus_child),
		  NULL, NULL,
		  _gtk_marshal_VOID__OBJECT,
		  G_TYPE_NONE, 1,
		  GTK_TYPE_WIDGET);
293 294
}

Johan Dahlin's avatar
Johan Dahlin committed
295 296 297 298
static void
gtk_container_buildable_init (GtkBuildableIface *iface)
{
  parent_buildable_iface = g_type_interface_peek_parent (iface);
299
  iface->add_child = gtk_container_buildable_add_child;
Johan Dahlin's avatar
Johan Dahlin committed
300 301 302 303 304
  iface->custom_tag_start = gtk_container_buildable_custom_tag_start;
  iface->custom_tag_end = gtk_container_buildable_custom_tag_end;
}

static void
305 306 307 308
gtk_container_buildable_add_child (GtkBuildable  *buildable,
				   GtkBuilder    *builder,
				   GObject       *child,
				   const gchar   *type)
Johan Dahlin's avatar
Johan Dahlin committed
309 310 311 312 313 314 315 316
{
  g_return_if_fail (GTK_IS_WIDGET (child));

  gtk_container_add (GTK_CONTAINER (buildable), GTK_WIDGET (child));
}

static void
gtk_container_buildable_set_child_property (GtkContainer *container,
317
					    GtkBuilder   *builder,
Johan Dahlin's avatar
Johan Dahlin committed
318 319 320 321 322 323
					    GtkWidget    *child,
					    gchar        *name,
					    const gchar  *value)
{
  GParamSpec *pspec;
  GValue gvalue = { 0, };
324 325
  GError *error = NULL;
  
Johan Dahlin's avatar
Johan Dahlin committed
326 327 328 329 330 331 332 333 334
  pspec = gtk_container_class_find_child_property
    (G_OBJECT_GET_CLASS (container), name);
  if (!pspec)
    {
      g_warning ("%s does not have a property called %s",
		 g_type_name (G_OBJECT_TYPE (container)), name);
      return;
    }

335
  if (!gtk_builder_value_from_string (builder, pspec, value, &gvalue, &error))
Johan Dahlin's avatar
Johan Dahlin committed
336
    {
337
      g_warning ("Could not read property %s:%s with value %s of type %s: %s",
Johan Dahlin's avatar
Johan Dahlin committed
338 339 340
		 g_type_name (G_OBJECT_TYPE (container)),
		 name,
		 value,
341 342 343
		 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
		 error->message);
      g_error_free (error);
Johan Dahlin's avatar
Johan Dahlin committed
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391
      return;
    }

  gtk_container_child_set_property (container, child, name, &gvalue);
  g_value_unset (&gvalue);
}

typedef struct {
  GtkBuilder   *builder;
  GtkContainer *container;
  GtkWidget    *child;
  gchar        *child_prop_name;
} PackingPropertiesData;

static void
attributes_start_element (GMarkupParseContext *context,
			  const gchar         *element_name,
			  const gchar        **names,
			  const gchar        **values,
			  gpointer             user_data,
			  GError             **error)
{
  PackingPropertiesData *parser_data = (PackingPropertiesData*)user_data;
  guint i;

  if (strcmp (element_name, "property") == 0)
    for (i = 0; names[i]; i++)
      if (strcmp (names[i], "name") == 0)
	parser_data->child_prop_name = g_strdup (values[i]);
  else if (strcmp (element_name, "packing") == 0)
    return;
  else
    g_warning ("Unsupported tag for GtkContainer: %s\n", element_name);
}

static void
attributes_text_element (GMarkupParseContext *context,
			 const gchar         *text,
			 gsize                text_len,
			 gpointer             user_data,
			 GError             **error)
{
  PackingPropertiesData *parser_data = (PackingPropertiesData*)user_data;

  if (!parser_data->child_prop_name)
    return;

  gtk_container_buildable_set_child_property (parser_data->container,
392
					      parser_data->builder,
Johan Dahlin's avatar
Johan Dahlin committed
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457
					      parser_data->child,
					      parser_data->child_prop_name,
					      text);

  g_free (parser_data->child_prop_name);
  parser_data->child_prop_name = NULL;
}

static const GMarkupParser attributes_parser =
  {
    attributes_start_element,
    NULL,
    attributes_text_element,
  };

static gboolean
gtk_container_buildable_custom_tag_start (GtkBuildable  *buildable,
					  GtkBuilder    *builder,
					  GObject       *child,
					  const gchar   *tagname,
					  GMarkupParser *parser,
					  gpointer      *data)
{
  PackingPropertiesData *parser_data;

  if (parent_buildable_iface->custom_tag_start (buildable, builder, child,
						tagname, parser, data))
    return TRUE;

  if (child && strcmp (tagname, "packing") == 0)
    {
      parser_data = g_slice_new0 (PackingPropertiesData);
      parser_data->builder = builder;
      parser_data->container = GTK_CONTAINER (buildable);
      parser_data->child = GTK_WIDGET (child);
      parser_data->child_prop_name = NULL;

      *parser = attributes_parser;
      *data = parser_data;
      return TRUE;
    }

  return FALSE;
}

static void
gtk_container_buildable_custom_tag_end (GtkBuildable *buildable,
					GtkBuilder   *builder,
					GObject      *child,
					const gchar  *tagname,
					gpointer     *data)
{
  if (strcmp (tagname, "packing") == 0)
    {
      g_slice_free (PackingPropertiesData, (gpointer)data);
      return;

    }

  if (parent_buildable_iface->custom_tag_end)
    parent_buildable_iface->custom_tag_end (buildable, builder,
					    child, tagname, data);

}

Matthias Clasen's avatar
Matthias Clasen committed
458 459
/**
 * gtk_container_child_type: 
460
 * @container: a #GtkContainer
Matthias Clasen's avatar
Matthias Clasen committed
461 462 463
 *
 * Returns the type of the children supported by the container.
 *
Manish Singh's avatar
Manish Singh committed
464
 * Note that this may return %G_TYPE_NONE to indicate that no more
Matthias Clasen's avatar
Matthias Clasen committed
465 466 467
 * children can be added, e.g. for a #GtkPaned which already has two 
 * children.
 *
Manish Singh's avatar
Manish Singh committed
468
 * Return value: a #GType.
Matthias Clasen's avatar
Matthias Clasen committed
469
 **/
Manish Singh's avatar
Manish Singh committed
470
GType
Tim Janik's avatar
Tim Janik committed
471
gtk_container_child_type (GtkContainer *container)
472
{
Manish Singh's avatar
Manish Singh committed
473
  GType slot;
474 475 476 477
  GtkContainerClass *class;

  g_return_val_if_fail (GTK_IS_CONTAINER (container), 0);

478
  class = GTK_CONTAINER_GET_CLASS (container);
479 480
  if (class->child_type)
    slot = class->child_type (container);
481
  else
Manish Singh's avatar
Manish Singh committed
482
    slot = G_TYPE_NONE;
483 484 485 486

  return slot;
}

Tim Janik's avatar
Tim Janik committed
487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533
/* --- GtkContainer child property mechanism --- */
static inline void
container_get_child_property (GtkContainer *container,
			      GtkWidget    *child,
			      GParamSpec   *pspec,
			      GValue       *value)
{
  GtkContainerClass *class = g_type_class_peek (pspec->owner_type);
  
  class->get_child_property (container, child, PARAM_SPEC_PARAM_ID (pspec), value, pspec);
}

static inline void
container_set_child_property (GtkContainer       *container,
			      GtkWidget		 *child,
			      GParamSpec         *pspec,
			      const GValue       *value,
			      GObjectNotifyQueue *nqueue)
{
  GValue tmp_value = { 0, };
  GtkContainerClass *class = g_type_class_peek (pspec->owner_type);

  /* provide a copy to work from, convert (if necessary) and validate */
  g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
  if (!g_value_transform (value, &tmp_value))
    g_warning ("unable to set child property `%s' of type `%s' from value of type `%s'",
	       pspec->name,
	       g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
	       G_VALUE_TYPE_NAME (value));
  else if (g_param_value_validate (pspec, &tmp_value) && !(pspec->flags & G_PARAM_LAX_VALIDATION))
    {
      gchar *contents = g_strdup_value_contents (value);

      g_warning ("value \"%s\" of type `%s' is invalid for property `%s' of type `%s'",
		 contents,
		 G_VALUE_TYPE_NAME (value),
		 pspec->name,
		 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
      g_free (contents);
    }
  else
    {
      class->set_child_property (container, child, PARAM_SPEC_PARAM_ID (pspec), &tmp_value, pspec);
      g_object_notify_queue_add (G_OBJECT (child), nqueue, pspec);
    }
  g_value_unset (&tmp_value);
}
534

Matthias Clasen's avatar
Matthias Clasen committed
535 536 537 538
/**
 * gtk_container_child_get_valist:
 * @container: a #GtkContainer
 * @child: a widget which is a child of @container
539
 * @first_property_name: the name of the first property to get
540 541
 * @var_args: return location for the first property, followed 
 *     optionally by more name/return location pairs, followed by %NULL
Matthias Clasen's avatar
Matthias Clasen committed
542 543 544
 * 
 * Gets the values of one or more child properties for @child and @container.
 **/
545
void
Tim Janik's avatar
Tim Janik committed
546 547 548 549
gtk_container_child_get_valist (GtkContainer *container,
				GtkWidget    *child,
				const gchar  *first_property_name,
				va_list       var_args)
550
{
Tim Janik's avatar
Tim Janik committed
551 552
  const gchar *name;

553
  g_return_if_fail (GTK_IS_CONTAINER (container));
Tim Janik's avatar
Tim Janik committed
554 555
  g_return_if_fail (GTK_IS_WIDGET (child));
  g_return_if_fail (child->parent == GTK_WIDGET (container));
556

Tim Janik's avatar
Tim Janik committed
557 558
  g_object_ref (container);
  g_object_ref (child);
559

Tim Janik's avatar
Tim Janik committed
560 561
  name = first_property_name;
  while (name)
562
    {
Tim Janik's avatar
Tim Janik committed
563 564
      GValue value = { 0, };
      GParamSpec *pspec;
565 566
      gchar *error;

Tim Janik's avatar
Tim Janik committed
567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589
      pspec = g_param_spec_pool_lookup (_gtk_widget_child_property_pool,
					name,
					G_OBJECT_TYPE (container),
					TRUE);
      if (!pspec)
	{
	  g_warning ("%s: container class `%s' has no child property named `%s'",
		     G_STRLOC,
		     G_OBJECT_TYPE_NAME (container),
		     name);
	  break;
	}
      if (!(pspec->flags & G_PARAM_READABLE))
	{
	  g_warning ("%s: child property `%s' of container class `%s' is not readable",
		     G_STRLOC,
		     pspec->name,
		     G_OBJECT_TYPE_NAME (container));
	  break;
	}
      g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
      container_get_child_property (container, child, pspec, &value);
      G_VALUE_LCOPY (&value, var_args, 0, &error);
590 591
      if (error)
	{
Tim Janik's avatar
Tim Janik committed
592
	  g_warning ("%s: %s", G_STRLOC, error);
593
	  g_free (error);
Tim Janik's avatar
Tim Janik committed
594 595
	  g_value_unset (&value);
	  break;
596
	}
Tim Janik's avatar
Tim Janik committed
597 598 599 600 601 602 603 604
      g_value_unset (&value);
      name = va_arg (var_args, gchar*);
    }

  g_object_unref (child);
  g_object_unref (container);
}

Matthias Clasen's avatar
Matthias Clasen committed
605 606 607 608 609 610 611 612 613
/**
 * gtk_container_child_get_property:
 * @container: a #GtkContainer
 * @child: a widget which is a child of @container
 * @property_name: the name of the property to get
 * @value: a location to return the value
 * 
 * Gets the value of a child property for @child and @container.
 **/
614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654
void
gtk_container_child_get_property (GtkContainer *container,
				  GtkWidget    *child,
				  const gchar  *property_name,
				  GValue       *value)
{
  GParamSpec *pspec;

  g_return_if_fail (GTK_IS_CONTAINER (container));
  g_return_if_fail (GTK_IS_WIDGET (child));
  g_return_if_fail (child->parent == GTK_WIDGET (container));
  g_return_if_fail (property_name != NULL);
  g_return_if_fail (G_IS_VALUE (value));
  
  g_object_ref (container);
  g_object_ref (child);
  pspec = g_param_spec_pool_lookup (_gtk_widget_child_property_pool, property_name,
				    G_OBJECT_TYPE (container), TRUE);
  if (!pspec)
    g_warning ("%s: container class `%s' has no child property named `%s'",
	       G_STRLOC,
	       G_OBJECT_TYPE_NAME (container),
	       property_name);
  else if (!(pspec->flags & G_PARAM_READABLE))
    g_warning ("%s: child property `%s' of container class `%s' is not readable",
	       G_STRLOC,
	       pspec->name,
	       G_OBJECT_TYPE_NAME (container));
  else
    {
      GValue *prop_value, tmp_value = { 0, };

      /* auto-conversion of the callers value type
       */
      if (G_VALUE_TYPE (value) == G_PARAM_SPEC_VALUE_TYPE (pspec))
	{
	  g_value_reset (value);
	  prop_value = value;
	}
      else if (!g_value_type_transformable (G_PARAM_SPEC_VALUE_TYPE (pspec), G_VALUE_TYPE (value)))
	{
jacob berkman's avatar
jacob berkman committed
655
	  g_warning ("can't retrieve child property `%s' of type `%s' as value of type `%s'",
656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678
		     pspec->name,
		     g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
		     G_VALUE_TYPE_NAME (value));
	  g_object_unref (child);
	  g_object_unref (container);
	  return;
	}
      else
	{
	  g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
	  prop_value = &tmp_value;
	}
      container_get_child_property (container, child, pspec, prop_value);
      if (prop_value != value)
	{
	  g_value_transform (prop_value, value);
	  g_value_unset (&tmp_value);
	}
    }
  g_object_unref (child);
  g_object_unref (container);
}

Matthias Clasen's avatar
Matthias Clasen committed
679 680 681 682
/**
 * gtk_container_child_set_valist:
 * @container: a #GtkContainer
 * @child: a widget which is a child of @container
683 684
 * @first_property_name: the name of the first property to set
 * @var_args: a %NULL-terminated list of property names and values, starting
685
 *           with @first_prop_name
Matthias Clasen's avatar
Matthias Clasen committed
686 687 688
 * 
 * Sets one or more child properties for @child and @container.
 **/
Tim Janik's avatar
Tim Janik committed
689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723
void
gtk_container_child_set_valist (GtkContainer *container,
				GtkWidget    *child,
				const gchar  *first_property_name,
				va_list       var_args)
{
  GObjectNotifyQueue *nqueue;
  const gchar *name;

  g_return_if_fail (GTK_IS_CONTAINER (container));
  g_return_if_fail (GTK_IS_WIDGET (child));
  g_return_if_fail (child->parent == GTK_WIDGET (container));

  g_object_ref (container);
  g_object_ref (child);

  nqueue = g_object_notify_queue_freeze (G_OBJECT (child), _gtk_widget_child_property_notify_context);
  name = first_property_name;
  while (name)
    {
      GValue value = { 0, };
      gchar *error = NULL;
      GParamSpec *pspec = g_param_spec_pool_lookup (_gtk_widget_child_property_pool,
						    name,
						    G_OBJECT_TYPE (container),
						    TRUE);
      if (!pspec)
	{
	  g_warning ("%s: container class `%s' has no child property named `%s'",
		     G_STRLOC,
		     G_OBJECT_TYPE_NAME (container),
		     name);
	  break;
	}
      if (!(pspec->flags & G_PARAM_WRITABLE))
724
	{
Tim Janik's avatar
Tim Janik committed
725 726 727 728 729
	  g_warning ("%s: child property `%s' of container class `%s' is not writable",
		     G_STRLOC,
		     pspec->name,
		     G_OBJECT_TYPE_NAME (container));
	  break;
730
	}
Tim Janik's avatar
Tim Janik committed
731 732 733 734 735 736 737 738 739 740 741 742 743 744 745
      g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
      G_VALUE_COLLECT (&value, var_args, 0, &error);
      if (error)
	{
	  g_warning ("%s: %s", G_STRLOC, error);
	  g_free (error);

	  /* we purposely leak the value here, it might not be
	   * in a sane state if an error condition occoured
	   */
	  break;
	}
      container_set_child_property (container, child, pspec, &value, nqueue);
      g_value_unset (&value);
      name = va_arg (var_args, gchar*);
746
    }
Tim Janik's avatar
Tim Janik committed
747
  g_object_notify_queue_thaw (G_OBJECT (child), nqueue);
748

Tim Janik's avatar
Tim Janik committed
749 750
  g_object_unref (container);
  g_object_unref (child);
751 752
}

Matthias Clasen's avatar
Matthias Clasen committed
753 754 755 756 757 758 759 760 761
/**
 * gtk_container_child_set_property:
 * @container: a #GtkContainer
 * @child: a widget which is a child of @container
 * @property_name: the name of the property to set
 * @value: the value to set the property to
 * 
 * Sets a child property for @child and @container.
 **/
762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801
void
gtk_container_child_set_property (GtkContainer *container,
				  GtkWidget    *child,
				  const gchar  *property_name,
				  const GValue *value)
{
  GObjectNotifyQueue *nqueue;
  GParamSpec *pspec;

  g_return_if_fail (GTK_IS_CONTAINER (container));
  g_return_if_fail (GTK_IS_WIDGET (child));
  g_return_if_fail (child->parent == GTK_WIDGET (container));
  g_return_if_fail (property_name != NULL);
  g_return_if_fail (G_IS_VALUE (value));
  
  g_object_ref (container);
  g_object_ref (child);

  nqueue = g_object_notify_queue_freeze (G_OBJECT (child), _gtk_widget_child_property_notify_context);
  pspec = g_param_spec_pool_lookup (_gtk_widget_child_property_pool, property_name,
				    G_OBJECT_TYPE (container), TRUE);
  if (!pspec)
    g_warning ("%s: container class `%s' has no child property named `%s'",
	       G_STRLOC,
	       G_OBJECT_TYPE_NAME (container),
	       property_name);
  else if (!(pspec->flags & G_PARAM_WRITABLE))
    g_warning ("%s: child property `%s' of container class `%s' is not writable",
	       G_STRLOC,
	       pspec->name,
	       G_OBJECT_TYPE_NAME (container));
  else
    {
      container_set_child_property (container, child, pspec, value, nqueue);
    }
  g_object_notify_queue_thaw (G_OBJECT (child), nqueue);
  g_object_unref (container);
  g_object_unref (child);
}

Matthias Clasen's avatar
Matthias Clasen committed
802 803 804 805 806 807
/**
 * gtk_container_add_with_properties:
 * @container: a #GtkContainer 
 * @widget: a widget to be placed inside @container 
 * @first_prop_name: the name of the first child property to set 
 * @Varargs: a %NULL-terminated list of property names and values, starting
808
 *           with @first_prop_name
Matthias Clasen's avatar
Matthias Clasen committed
809 810 811 812
 * 
 * Adds @widget to @container, setting child properties at the same time.
 * See gtk_container_add() and gtk_container_child_set() for more details.
 **/
813
void
Tim Janik's avatar
Tim Janik committed
814 815 816 817
gtk_container_add_with_properties (GtkContainer *container,
				   GtkWidget    *widget,
				   const gchar  *first_prop_name,
				   ...)
818
{
819 820 821
  g_return_if_fail (GTK_IS_CONTAINER (container));
  g_return_if_fail (GTK_IS_WIDGET (widget));
  g_return_if_fail (widget->parent == NULL);
822

Manish Singh's avatar
Manish Singh committed
823 824
  g_object_ref (container);
  g_object_ref (widget);
Tim Janik's avatar
Tim Janik committed
825
  gtk_widget_freeze_child_notify (widget);
826

Manish Singh's avatar
Manish Singh committed
827
  g_signal_emit (container, container_signals[ADD], 0, widget);
828
  if (widget->parent)
829
    {
Tim Janik's avatar
Tim Janik committed
830
      va_list var_args;
831

Tim Janik's avatar
Tim Janik committed
832 833 834
      va_start (var_args, first_prop_name);
      gtk_container_child_set_valist (container, widget, first_prop_name, var_args);
      va_end (var_args);
835 836
    }

Tim Janik's avatar
Tim Janik committed
837
  gtk_widget_thaw_child_notify (widget);
Manish Singh's avatar
Manish Singh committed
838 839
  g_object_unref (widget);
  g_object_unref (container);
840 841
}

Matthias Clasen's avatar
Matthias Clasen committed
842 843 844 845 846 847
/**
 * gtk_container_child_set:
 * @container: a #GtkContainer
 * @child: a widget which is a child of @container
 * @first_prop_name: the name of the first property to set
 * @Varargs: a %NULL-terminated list of property names and values, starting
848
 *           with @first_prop_name
Matthias Clasen's avatar
Matthias Clasen committed
849 850 851
 * 
 * Sets one or more child properties for @child and @container.
 **/
852
void
853 854
gtk_container_child_set (GtkContainer      *container,
			 GtkWidget         *child,
Tim Janik's avatar
Tim Janik committed
855
			 const gchar       *first_prop_name,
856
			 ...)
857
{
858 859
  va_list var_args;
  
860 861
  g_return_if_fail (GTK_IS_CONTAINER (container));
  g_return_if_fail (GTK_IS_WIDGET (child));
Tim Janik's avatar
Tim Janik committed
862
  g_return_if_fail (child->parent == GTK_WIDGET (container));
863

Tim Janik's avatar
Tim Janik committed
864 865 866
  va_start (var_args, first_prop_name);
  gtk_container_child_set_valist (container, child, first_prop_name, var_args);
  va_end (var_args);
867 868
}

Matthias Clasen's avatar
Matthias Clasen committed
869 870 871 872 873
/**
 * gtk_container_child_get:
 * @container: a #GtkContainer
 * @child: a widget which is a child of @container
 * @first_prop_name: the name of the first property to get
874 875
 * @Varargs: return location for the first property, followed 
 *     optionally by more name/return location pairs, followed by %NULL
Matthias Clasen's avatar
Matthias Clasen committed
876 877 878
 * 
 * Gets the values of one or more child properties for @child and @container.
 **/
879
void
Tim Janik's avatar
Tim Janik committed
880 881 882 883
gtk_container_child_get (GtkContainer      *container,
			 GtkWidget         *child,
			 const gchar       *first_prop_name,
			 ...)
884
{
Tim Janik's avatar
Tim Janik committed
885
  va_list var_args;
886 887 888
  
  g_return_if_fail (GTK_IS_CONTAINER (container));
  g_return_if_fail (GTK_IS_WIDGET (child));
Tim Janik's avatar
Tim Janik committed
889 890 891 892 893
  g_return_if_fail (child->parent == GTK_WIDGET (container));

  va_start (var_args, first_prop_name);
  gtk_container_child_get_valist (container, child, first_prop_name, var_args);
  va_end (var_args);
894 895
}

Matthias Clasen's avatar
Matthias Clasen committed
896 897 898 899 900 901 902 903
/**
 * gtk_container_class_install_child_property:
 * @cclass: a #GtkContainerClass
 * @property_id: the id for the property
 * @pspec: the #GParamSpec for the property
 * 
 * Installs a child property on a container class. 
 **/
904
void
905
gtk_container_class_install_child_property (GtkContainerClass *cclass,
Tim Janik's avatar
Tim Janik committed
906 907
					    guint              property_id,
					    GParamSpec        *pspec)
908
{
909
  g_return_if_fail (GTK_IS_CONTAINER_CLASS (cclass));
Tim Janik's avatar
Tim Janik committed
910 911
  g_return_if_fail (G_IS_PARAM_SPEC (pspec));
  if (pspec->flags & G_PARAM_WRITABLE)
912
    g_return_if_fail (cclass->set_child_property != NULL);
Tim Janik's avatar
Tim Janik committed
913
  if (pspec->flags & G_PARAM_READABLE)
914
    g_return_if_fail (cclass->get_child_property != NULL);
Tim Janik's avatar
Tim Janik committed
915 916 917 918 919
  g_return_if_fail (property_id > 0);
  g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0);  /* paranoid */
  if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY))
    g_return_if_fail ((pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) == 0);

920
  if (g_param_spec_pool_lookup (_gtk_widget_child_property_pool, pspec->name, G_OBJECT_CLASS_TYPE (cclass), FALSE))
921
    {
Matthias Clasen's avatar
Matthias Clasen committed
922
      g_warning (G_STRLOC ": class `%s' already contains a child property named `%s'",
923
		 G_OBJECT_CLASS_NAME (cclass),
Tim Janik's avatar
Tim Janik committed
924
		 pspec->name);
925
      return;
926
    }
Tim Janik's avatar
Tim Janik committed
927 928 929
  g_param_spec_ref (pspec);
  g_param_spec_sink (pspec);
  PARAM_SPEC_SET_PARAM_ID (pspec, property_id);
930
  g_param_spec_pool_insert (_gtk_widget_child_property_pool, pspec, G_OBJECT_CLASS_TYPE (cclass));
931 932
}

933 934
/**
 * gtk_container_class_find_child_property:
935
 * @cclass: a #GtkContainerClass
936
 * @property_name: the name of the child property to find
937
 * @returns: the #GParamSpec of the child property or %NULL if @class has no
938 939 940 941
 *   child property with that name.
 *
 * Finds a child property of a container class by name.
 */
Tim Janik's avatar
Tim Janik committed
942
GParamSpec*
943
gtk_container_class_find_child_property (GObjectClass *cclass,
Tim Janik's avatar
Tim Janik committed
944
					 const gchar  *property_name)
945
{
946
  g_return_val_if_fail (GTK_IS_CONTAINER_CLASS (cclass), NULL);
Tim Janik's avatar
Tim Janik committed
947
  g_return_val_if_fail (property_name != NULL, NULL);
948

Tim Janik's avatar
Tim Janik committed
949 950
  return g_param_spec_pool_lookup (_gtk_widget_child_property_pool,
				   property_name,
951
				   G_OBJECT_CLASS_TYPE (cclass),
Tim Janik's avatar
Tim Janik committed
952
				   TRUE);
953
}
954

955 956
/**
 * gtk_container_class_list_child_properties:
957
 * @cclass: a #GtkContainerClass
958
 * @n_properties: location to return the number of child properties found
959 960
 * @returns: a newly allocated %NULL-terminated array of #GParamSpec*. 
 *           The array must be freed with g_free().
961 962 963 964
 *
 * Returns all child properties of a container class.
 */
GParamSpec**
965
gtk_container_class_list_child_properties (GObjectClass *cclass,
Tim Janik's avatar
Tim Janik committed
966
					   guint        *n_properties)
967
{
Tim Janik's avatar
Tim Janik committed
968 969
  GParamSpec **pspecs;
  guint n;
970

971
  g_return_val_if_fail (GTK_IS_CONTAINER_CLASS (cclass), NULL);
972

Tim Janik's avatar
Tim Janik committed
973
  pspecs = g_param_spec_pool_list (_gtk_widget_child_property_pool,
974
				   G_OBJECT_CLASS_TYPE (cclass),
Tim Janik's avatar
Tim Janik committed
975 976 977
				   &n);
  if (n_properties)
    *n_properties = n;
Elliot Lee's avatar
Elliot Lee committed
978

Tim Janik's avatar
Tim Janik committed
979 980
  return pspecs;
}
981

982 983 984 985
static void
gtk_container_add_unimplemented (GtkContainer     *container,
				 GtkWidget        *widget)
{
Manish Singh's avatar
Manish Singh committed
986
  g_warning ("GtkContainerClass::add not implemented for `%s'", g_type_name (G_TYPE_FROM_INSTANCE (container)));
987 988 989 990 991 992
}

static void
gtk_container_remove_unimplemented (GtkContainer     *container,
				    GtkWidget        *widget)
{
Manish Singh's avatar
Manish Singh committed
993
  g_warning ("GtkContainerClass::remove not implemented for `%s'", g_type_name (G_TYPE_FROM_INSTANCE (container)));
994 995
}

Elliot Lee's avatar
Elliot Lee committed
996 997 998 999 1000 1001
static void
gtk_container_init (GtkContainer *container)
{
  container->focus_child = NULL;
  container->border_width = 0;
  container->need_resize = FALSE;
1002
  container->resize_mode = GTK_RESIZE_PARENT;
1003
  container->reallocate_redraws = FALSE;
1004 1005 1006 1007 1008
}

static void
gtk_container_destroy (GtkObject *object)
{
1009
  GtkContainer *container = GTK_CONTAINER (object);
1010
  
1011
  if (GTK_CONTAINER_RESIZE_PENDING (container))
1012
    _gtk_container_dequeue_resize_handler (container);
1013 1014 1015 1016 1017 1018

  /* do this before walking child widgets, to avoid
   * removing children from focus chain one by one.
   */
  if (container->has_focus_chain)
    gtk_container_unset_focus_chain (container);
1019
  
1020
  gtk_container_foreach (container, (GtkCallback) gtk_widget_destroy, NULL);
1021 1022 1023
  
  if (GTK_OBJECT_CLASS (parent_class)->destroy)
    (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
Elliot Lee's avatar
Elliot Lee committed
1024 1025 1026
}

static void
Alexander Larsson's avatar
Alexander Larsson committed
1027 1028 1029 1030
gtk_container_set_property (GObject         *object,
			    guint            prop_id,
			    const GValue    *value,
			    GParamSpec      *pspec)
Elliot Lee's avatar
Elliot Lee committed
1031
{
1032
  GtkContainer *container = GTK_CONTAINER (object);
1033

Alexander Larsson's avatar
Alexander Larsson committed
1034
  switch (prop_id)
Elliot Lee's avatar
Elliot Lee committed
1035
    {
Alexander Larsson's avatar
Alexander Larsson committed
1036 1037
    case PROP_BORDER_WIDTH:
      gtk_container_set_border_width (container, g_value_get_uint (value));
1038
      break;
Alexander Larsson's avatar
Alexander Larsson committed
1039 1040
    case PROP_RESIZE_MODE:
      gtk_container_set_resize_mode (container, g_value_get_enum (value));
1041
      break;
Alexander Larsson's avatar
Alexander Larsson committed
1042 1043
    case PROP_CHILD:
      gtk_container_add (container, GTK_WIDGET (g_value_get_object (value)));
1044
      break;
Tim Janik's avatar
Tim Janik committed
1045
    default:
Alexander Larsson's avatar
Alexander Larsson committed
1046
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Tim Janik's avatar
Tim Janik committed
1047
      break;
1048 1049 1050 1051
    }
}

static void
Alexander Larsson's avatar
Alexander Larsson committed
1052 1053 1054 1055
gtk_container_get_property (GObject         *object,
			    guint            prop_id,
			    GValue          *value,
			    GParamSpec      *pspec)
1056
{
1057
  GtkContainer *container = GTK_CONTAINER (object);
1058
  
Alexander Larsson's avatar
Alexander Larsson committed
1059
  switch (prop_id)
1060
    {
Alexander Larsson's avatar
Alexander Larsson committed
1061 1062
    case PROP_BORDER_WIDTH:
      g_value_set_uint (value, container->border_width);
1063
      break;
Alexander Larsson's avatar
Alexander Larsson committed
1064 1065
    case PROP_RESIZE_MODE:
      g_value_set_enum (value, container->resize_mode);
1066
      break;
1067
    default:
Alexander Larsson's avatar
Alexander Larsson committed
1068
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Tim Janik's avatar
Tim Janik committed
1069
      break;
Elliot Lee's avatar
Elliot Lee committed
1070 1071 1072
    }
}

1073 1074 1075
/**
 * gtk_container_set_border_width:
 * @container: a #GtkContainer
1076 1077
 * @border_width: amount of blank space to leave <emphasis>outside</emphasis> 
 *   the container. Valid values are in the range 0-65535 pixels.
1078
 *
Matthias Clasen's avatar
Matthias Clasen committed
1079 1080
 * Sets the border width of the container.
 *
1081 1082 1083 1084 1085
 * The border width of a container is the amount of space to leave
 * around the outside of the container. The only exception to this is
 * #GtkWindow; because toplevel windows can't leave space outside,
 * they leave the space inside. The border is added on all sides of
 * the container. To add space to only one side, one approach is to
1086 1087 1088
 * create a #GtkAlignment widget, call gtk_widget_set_size_request()
 * to give it a size, and place it on the side of the container as
 * a spacer.
1089
 **/
Elliot Lee's avatar
Elliot Lee committed
1090
void
1091 1092
gtk_container_set_border_width (GtkContainer *container,
				guint         border_width)
Elliot Lee's avatar
Elliot Lee committed
1093 1094 1095 1096 1097 1098
{
  g_return_if_fail (GTK_IS_CONTAINER (container));

  if (container->border_width != border_width)
    {
      container->border_width = border_width;
1099
      g_object_notify (G_OBJECT (container), "border-width");
Alexander Larsson's avatar
Alexander Larsson committed
1100
      
Tim Janik's avatar
Tim Janik committed
1101 1102
      if (GTK_WIDGET_REALIZED (container))
	gtk_widget_queue_resize (GTK_WIDGET (container));
Elliot Lee's avatar
Elliot Lee committed
1103 1104 1105
    }
}

1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122
/**
 * gtk_container_get_border_width:
 * @container: a #GtkContainer
 * 
 * Retrieves the border width of the container. See
 * gtk_container_set_border_width().
 *
 * Return value: the current border width
 **/
guint
gtk_container_get_border_width (GtkContainer *container)
{
  g_return_val_if_fail (GTK_IS_CONTAINER (container), 0);

  return container->border_width;
}

1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136
/**
 * gtk_container_add:
 * @container: a #GtkContainer
 * @widget: a widget to be placed inside @container
 * 
 * Adds @widget to @container. Typically used for simple containers
 * such as #GtkWindow, #GtkFrame, or #GtkButton; for more complicated
 * layout containers such as #GtkBox or #GtkTable, this function will
 * pick default packing parameters that may not be correct.  So
 * consider functions such as gtk_box_pack_start() and
 * gtk_table_attach() as an alternative to gtk_container_add() in
 * those cases. A widget may be added to only one container at a time;
 * you can't place the same widget inside two different containers.
 **/
Elliot Lee's avatar
Elliot Lee committed
1137 1138 1139 1140
void
gtk_container_add (GtkContainer *container,
		   GtkWidget    *widget)
{
1141 1142
  g_return_if_fail (GTK_IS_CONTAINER (container));
  g_return_if_fail (GTK_IS_WIDGET (widget));
1143 1144 1145 1146

  if (widget->parent != NULL)
    {
      g_warning ("Attempting to add a widget with type %s to a container of "
Havoc Pennington's avatar
Havoc Pennington committed
1147 1148
                 "type %s, but the widget is already inside a container of type %s, "
                 "the GTK+ FAQ at http://www.gtk.org/faq/ explains how to reparent a widget.",
Tim Janik's avatar
Tim Janik committed
1149 1150 1151
                 g_type_name (G_OBJECT_TYPE (widget)),
                 g_type_name (G_OBJECT_TYPE (container)),
                 g_type_name (G_OBJECT_TYPE (widget->parent)));
1152 1153
      return;
    }
1154

Manish Singh's avatar
Manish Singh committed
1155
  g_signal_emit (container, container_signals[ADD], 0, widget);
Elliot Lee's avatar
Elliot Lee committed
1156 1157
}

1158 1159 1160 1161 1162 1163 1164 1165 1166 1167
/**
 * gtk_container_remove:
 * @container: a #GtkContainer
 * @widget: a current child of @container
 * 
 * Removes @widget from @container. @widget must be inside @container.
 * Note that @container will own a reference to @widget, and that this
 * may be the last reference held; so removing a widget from its
 * container can destroy that widget. If you want to use @widget
 * again, you need to add a reference to it while it's not inside
1168 1169 1170 1171
 * a container, using g_object_ref(). If you don't want to use @widget
 * again it's usually more efficient to simply destroy it directly
 * using gtk_widget_destroy() since this will remove it from the
 * container and help break any circular reference count cycles.
1172
 **/
Elliot Lee's avatar
Elliot Lee committed
1173 1174 1175 1176 1177
void
gtk_container_remove (GtkContainer *container,
		      GtkWidget    *widget)
{
  g_return_if_fail (GTK_IS_CONTAINER (container));
1178
  g_return_if_fail (GTK_IS_WIDGET (widget));
1179 1180 1181 1182 1183 1184 1185

  /* When using the deprecated API of the toolbar, it is possible
   * to legitimately call this function with a widget that is not
   * a direct child of the container.
   */
  g_return_if_fail (GTK_IS_TOOLBAR (container) ||
		    widget->parent == GTK_WIDGET (container));
1186
  
Manish Singh's avatar
Manish Singh committed
1187
  g_signal_emit (container, container_signals[REMOVE], 0, widget);
Elliot Lee's avatar
Elliot Lee committed
1188 1189
}

1190
void
1191
_gtk_container_dequeue_resize_handler (GtkContainer *container)
1192 1193 1194 1195 1196 1197 1198 1199
{
  g_return_if_fail (GTK_IS_CONTAINER (container));
  g_return_if_fail (GTK_CONTAINER_RESIZE_PENDING (container));

  container_resize_queue = g_slist_remove (container_resize_queue, container);
  GTK_PRIVATE_UNSET_FLAG (container, GTK_RESIZE_PENDING);
}

Matthias Clasen's avatar
Matthias Clasen committed
1200 1201
/**
 * gtk_container_set_resize_mode:
1202 1203
 * @container: a #GtkContainer
 * @resize_mode: the new resize mode
Matthias Clasen's avatar
Matthias Clasen committed
1204 1205 1206 1207 1208 1209 1210
 * 
 * Sets the resize mode for the container.
 *
 * The resize mode of a container determines whether a resize request 
 * will be passed to the container's parent, queued for later execution
 * or executed immediately.
 **/
Elliot Lee's avatar
Elliot Lee committed
1211
void
1212 1213
gtk_container_set_resize_mode (GtkContainer  *container,
			       GtkResizeMode  resize_mode)
Elliot Lee's avatar
Elliot Lee committed
1214 1215
{
  g_return_if_fail (GTK_IS_CONTAINER (container));
1216 1217 1218 1219
  g_return_if_fail (resize_mode <= GTK_RESIZE_IMMEDIATE);
  
  if (GTK_WIDGET_TOPLEVEL (container) &&
      resize_mode == GTK_RESIZE_PARENT)
Alexander Larsson's avatar
Alexander Larsson committed
1220 1221 1222
    {
      resize_mode = GTK_RESIZE_QUEUE;
    }
1223 1224
  
  if (container->resize_mode != resize_mode)
1225
    {
1226 1227
      container->resize_mode = resize_mode;
      
1228
      gtk_widget_queue_resize (GTK_WIDGET (container));
1229
      g_object_notify (G_OBJECT (container), "resize-mode");
1230 1231 1232
    }
}

1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249
/**
 * gtk_container_get_resize_mode:
 * @container: a #GtkContainer
 * 
 * Returns the resize mode for the container. See
 * gtk_container_set_resize_mode ().
 *
 * Return value: the current resize mode
 **/
GtkResizeMode
gtk_container_get_resize_mode (GtkContainer *container)
{
  g_return_val_if_fail (GTK_IS_CONTAINER (container), GTK_RESIZE_PARENT);

  return container->resize_mode;
}

Matthias Clasen's avatar
Matthias Clasen committed
1250 1251
/**
 * gtk_container_set_reallocate_redraws:
1252 1253
 * @container: a #GtkContainer
 * @needs_redraws: the new value for the container's @reallocate_redraws flag
Matthias Clasen's avatar
Matthias Clasen committed
1254 1255 1256 1257 1258 1259
 *
 * Sets the @reallocate_redraws flag of the container to the given value.
 * 
 * Containers requesting reallocation redraws get automatically
 * redrawn if any of their children changed allocation. 
 **/ 
1260 1261 1262 1263 1264 1265
void
gtk_container_set_reallocate_redraws (GtkContainer *container,
				      gboolean      needs_redraws)
{
  g_return_if_fail (GTK_IS_CONTAINER (container));

1266
  container->reallocate_redraws = needs_redraws ? TRUE : FALSE;
1267 1268
}

1269 1270 1271
static GtkContainer*
gtk_container_get_resize_container (GtkContainer *container)
{
1272
  GtkWidget *widget = GTK_WIDGET (container);
1273 1274 1275 1276

  while (widget->parent)
    {
      widget = widget->parent;
1277
      if (GTK_IS_RESIZE_CONTAINER (widget))
1278 1279 1280 1281 1282 1283 1284 1285 1286
	break;
    }

  return GTK_IS_RESIZE_CONTAINER (widget) ? (GtkContainer*) widget : NULL;
}

static gboolean
gtk_container_idle_sizer (gpointer data)
{
1287 1288 1289 1290 1291 1292 1293
  /* we may be invoked with a container_resize_queue of NULL, because
   * queue_resize could have been adding an extra idle function while
   * the queue still got processed. we better just ignore such case
   * than trying to explicitely work around them with some extra flags,
   * since it doesn't cause any actual harm.
   */
  while (container_resize_queue)
1294
    {
1295 1296 1297 1298 1299 1300 1301 1302 1303 1304
      GSList *slist;
      GtkWidget *widget;

      slist = container_resize_queue;
      container_resize_queue = slist->next;
      widget = slist->data;
      g_slist_free_1 (slist);

      GTK_PRIVATE_UNSET_FLAG (widget, GTK_RESIZE_PENDING);
      gtk_container_check_resize (GTK_CONTAINER (widget));
1305
    }
1306

1307 1308
  gdk_window_process_all_updates ();

1309 1310 1311 1312
  return FALSE;
}

void
1313
_gtk_container_queue_resize (GtkContainer *container)
1314 1315
{
  GtkContainer *resize_container;
1316
  GtkWidget *widget;
1317 1318 1319
  
  g_return_if_fail (GTK_IS_CONTAINER (container));

1320
  widget = GTK_WIDGET (container);
1321
  resize_container = gtk_container_get_resize_container (container);
1322
  
1323
  while (TRUE)
1324
    {
1325 1326 1327 1328 1329
      GTK_PRIVATE_SET_FLAG (widget, GTK_ALLOC_NEEDED);
      GTK_PRIVATE_SET_FLAG (widget, GTK_REQUEST_NEEDED);
      if ((resize_container && widget == GTK_WIDGET (resize_container)) ||
	  !widget->parent)
	break;
1330
      
1331 1332
      widget = widget->parent;
    }
1333
      
1334 1335
  if (resize_container)
    {