glade-widget.c 117 KB
Newer Older
Jose Maria Celorio's avatar
Jose Maria Celorio committed
1
2
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
3
 * Copyright (C) 2008 Tristan Van Berkom
4
5
 * Copyright (C) 2004 Joaquin Cuenca Abela
 * Copyright (C) 2001, 2002, 2003 Ximian, Inc.
Jose Maria Celorio's avatar
Jose Maria Celorio committed
6
7
8
9
10
11
12
13
14
15
16
17
18
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Jose Maria Celorio's avatar
Jose Maria Celorio committed
20
21
 *
 * Authors:
22
 *   Joaquin Cuenca Abela <e98cuenc@yahoo.com>
Jose Maria Celorio's avatar
Jose Maria Celorio committed
23
 *   Chema Celorio <chema@celorio.com>
24
 *   Tristan Van Berkom <tvb@gnome.org>
Jose Maria Celorio's avatar
Jose Maria Celorio committed
25
26
 */

27
28
29
30
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

31
32
33
34
35
36
37
38
39
/**
 * SECTION:glade-widget
 * @Short_Description: An object wrapper for the Glade runtime environment.
 *
 * #GladeWidget is the proxy between the instantiated runtime object and
 * the Glade core metadata. This api will be mostly usefull for its
 * convenience api for getting and setting properties (mostly from the plugin).
 */

Jose Maria Celorio's avatar
Jose Maria Celorio committed
40
#include <string.h>
41
#include <glib-object.h>
42
43
#include <gdk/gdkkeysyms.h>
#include <glib/gi18n-lib.h>
Jose Maria Celorio's avatar
Jose Maria Celorio committed
44
#include "glade.h"
45
#include "glade-accumulators.h"
Jose Maria Celorio's avatar
Jose Maria Celorio committed
46
#include "glade-project.h"
47
#include "glade-widget-adaptor.h"
48
49
#include "glade-widget.h"
#include "glade-marshallers.h"
Jose Maria Celorio's avatar
Jose Maria Celorio committed
50
51
#include "glade-property.h"
#include "glade-property-class.h"
52
#include "glade-placeholder.h"
53
#include "glade-signal.h"
54
#include "glade-popup.h"
55
#include "glade-editor.h"
56
#include "glade-app.h"
57
#include "glade-design-view.h"
58
#include "glade-widget-action.h"
59

Jose Maria Celorio's avatar
Jose Maria Celorio committed
60

61

62
63
static void         glade_widget_set_adaptor           (GladeWidget           *widget,
							GladeWidgetAdaptor    *adaptor);
64
65
static void         glade_widget_set_properties        (GladeWidget           *widget,
							GList                 *properties);
66
static gboolean     glade_window_is_embedded           (GtkWindow *window);
67
static gboolean     glade_widget_embed                 (GladeWidget *widget);
68

69
enum
Jose Maria Celorio's avatar
Jose Maria Celorio committed
70
{
71
72
73
	ADD_SIGNAL_HANDLER,
	REMOVE_SIGNAL_HANDLER,
	CHANGE_SIGNAL_HANDLER,
74
75
76
	BUTTON_PRESS_EVENT,
	BUTTON_RELEASE_EVENT,
	MOTION_NOTIFY_EVENT,
77
78
	LAST_SIGNAL
};
Jose Maria Celorio's avatar
Jose Maria Celorio committed
79

80
enum
81
{
82
83
84
	PROP_0,
	PROP_NAME,
	PROP_INTERNAL,
85
	PROP_ANARCHIST,
86
	PROP_OBJECT,
87
	PROP_ADAPTOR,
88
89
	PROP_PROJECT,
	PROP_PROPERTIES,
90
91
92
	PROP_PARENT,
	PROP_INTERNAL_NAME,
	PROP_TEMPLATE,
93
	PROP_TEMPLATE_EXACT,
94
95
	PROP_REASON,
	PROP_TOPLEVEL_WIDTH,
96
97
	PROP_TOPLEVEL_HEIGHT,
	PROP_SUPPORT_WARNING
98
99
};

Tristan Van Berkom's avatar
updated    
Tristan Van Berkom committed
100
101
102
static guint         glade_widget_signals[LAST_SIGNAL] = {0};
static GQuark        glade_widget_name_quark = 0;

103
104
105

G_DEFINE_TYPE (GladeWidget, glade_widget, G_TYPE_OBJECT)

106
107
108
/*******************************************************************************
                           GladeWidget class methods
 *******************************************************************************/
109
110
111
112
113
114
115
116
117
118
static void
glade_widget_set_packing_actions (GladeWidget *widget, GladeWidget *parent)
{
	if (widget->packing_actions)
	{
		g_list_foreach (widget->packing_actions, (GFunc)g_object_unref, NULL);
		g_list_free (widget->packing_actions);
		widget->packing_actions = NULL;
	}
	
119
120
	if (parent->adaptor->packing_actions)
		widget->packing_actions = glade_widget_adaptor_pack_actions_new (parent->adaptor);
121
122
}

123
static void
124
glade_widget_add_child_impl (GladeWidget  *widget,
125
126
			     GladeWidget  *child,
			     gboolean      at_mouse)
127
{
Tristan Van Berkom's avatar
Tristan Van Berkom committed
128
129
130
	/* Safe to set the parent first... setting it afterwards
	 * creates packing properties, and that is not always
	 * desirable.
131
132
133
	 */
	glade_widget_set_parent (child, widget);

134
135
136
137
	/* Set packing actions first so we have access from the plugin
	 */
	glade_widget_set_packing_actions (child, widget);

138
139
	glade_widget_adaptor_add 
		(widget->adaptor, widget->object, child->object);
140

141
142
143
144
145
146
147
148
149
150
151
152
153
154
	/* XXX FIXME:
	 * We have a fundamental flaw here, we set packing props
	 * after parenting the widget so that we can introspect the
	 * values setup by the runtime widget, in which case the plugin
	 * cannot access its packing properties and set them sensitive
	 * or connect to thier signals etc. maybe its not so important
	 * but its a flaw worthy of note, some kind of double pass api
	 * would be needed to accomadate this.
	 */

	
	/* Setup packing properties here so we can introspect the new
	 * values from the backend.
	 */
155
	glade_widget_set_packing_properties (child, widget);
156
}
157

158
static void
159
160
glade_widget_remove_child_impl (GladeWidget  *widget,
				GladeWidget  *child)
161
{
162
163
	glade_widget_adaptor_remove
		(widget->adaptor, widget->object, child->object);
164
}
165

Tristan Van Berkom's avatar
updated    
Tristan Van Berkom committed
166
167
168
169
170
171
172
173
static void
glade_widget_replace_child_impl (GladeWidget *widget,
				 GObject     *old_object,
				 GObject     *new_object)
{
	GladeWidget *gnew_widget = glade_widget_get_from_gobject (new_object);
	GladeWidget *gold_widget = glade_widget_get_from_gobject (old_object);

174
175
176
177
178
179
180
181
182
	if (gnew_widget)
	{
		gnew_widget->parent = widget;

		/* Set packing actions first so we have access from the plugin
		 */
		glade_widget_set_packing_actions (gnew_widget, widget);
	}

Tristan Van Berkom's avatar
Tristan Van Berkom committed
183
184
	if (gold_widget && gold_widget != gnew_widget)
		gold_widget->parent = NULL;
Tristan Van Berkom's avatar
updated    
Tristan Van Berkom committed
185

186
187
	glade_widget_adaptor_replace_child 
		(widget->adaptor, widget->object,
Tristan Van Berkom's avatar
updated    
Tristan Van Berkom committed
188
189
		 old_object, new_object);

190
191
	/* Setup packing properties here so we can introspect the new
	 * values from the backend.
192
	 */
193
	if (gnew_widget)
Tristan Van Berkom's avatar
updated    
Tristan Van Berkom committed
194
195
196
		glade_widget_set_packing_properties (gnew_widget, widget);
}

197
198
199
200
201
static void
glade_widget_add_signal_handler_impl (GladeWidget *widget, GladeSignal *signal_handler)
{
	GPtrArray *signals;
	GladeSignal *new_signal_handler;
202

203
204
205
206
207
208
209
210
	g_return_if_fail (GLADE_IS_WIDGET (widget));
	g_return_if_fail (GLADE_IS_SIGNAL (signal_handler));

	signals = glade_widget_list_signal_handlers (widget, signal_handler->name);
	if (!signals)
	{
		signals = g_ptr_array_new ();
		g_hash_table_insert (widget->signals, g_strdup (signal_handler->name), signals);
211
212
	}

213
214
	new_signal_handler = glade_signal_clone (signal_handler);
	g_ptr_array_add (signals, new_signal_handler);
215
216
}

217
static void
218
glade_widget_remove_signal_handler_impl (GladeWidget *widget, GladeSignal *signal_handler)
219
{
220
221
222
	GPtrArray   *signals;
	GladeSignal *tmp_signal_handler;
	guint        i;
223

224
225
	g_return_if_fail (GLADE_IS_WIDGET (widget));
	g_return_if_fail (GLADE_IS_SIGNAL (signal_handler));
226

227
	signals = glade_widget_list_signal_handlers (widget, signal_handler->name);
228

229
230
	/* trying to remove an inexistent signal? */
	g_assert (signals);
231

232
233
234
235
236
237
238
239
240
241
242
	for (i = 0; i < signals->len; i++)
	{
		tmp_signal_handler = g_ptr_array_index (signals, i);
		if (glade_signal_equal (tmp_signal_handler, signal_handler))
		{
			glade_signal_free (tmp_signal_handler);
			g_ptr_array_remove_index (signals, i);
			break;
		}
	}
}
243

244
245
246
247
248
249
static void
glade_widget_change_signal_handler_impl (GladeWidget *widget,
					 GladeSignal *old_signal_handler,
					 GladeSignal *new_signal_handler)
{
	GPtrArray   *signals;
250
	GladeSignal *signal_handler_iter;
251
252
253
254
255
256
	guint        i;
	
	g_return_if_fail (GLADE_IS_WIDGET (widget));
	g_return_if_fail (GLADE_IS_SIGNAL (old_signal_handler));
	g_return_if_fail (GLADE_IS_SIGNAL (new_signal_handler));
	g_return_if_fail (strcmp (old_signal_handler->name, new_signal_handler->name) == 0);
257

258
	signals = glade_widget_list_signal_handlers (widget, old_signal_handler->name);
259

260
261
	/* trying to remove an inexistent signal? */
	g_assert (signals);
262

263
264
	for (i = 0; i < signals->len; i++)
	{
265
266
		signal_handler_iter = g_ptr_array_index (signals, i);
		if (glade_signal_equal (signal_handler_iter, old_signal_handler))
267
268
269
270
		{
			if (strcmp (old_signal_handler->handler,
				    new_signal_handler->handler) != 0)
			{
271
272
				g_free (signal_handler_iter->handler);
				signal_handler_iter->handler =
273
274
					g_strdup (new_signal_handler->handler);
			}
Tristan Van Berkom's avatar
Tristan Van Berkom committed
275

276
			/* Handler */
277
278
279
			if (signal_handler_iter->handler)
				g_free (signal_handler_iter->handler);
			signal_handler_iter->handler =
280
281
282
				g_strdup (new_signal_handler->handler);
			
			/* Object */
283
284
285
			if (signal_handler_iter->userdata)
				g_free (signal_handler_iter->userdata);
			signal_handler_iter->userdata = 
286
287
				g_strdup (new_signal_handler->userdata);
			
288
289
			signal_handler_iter->after    = new_signal_handler->after;
			signal_handler_iter->swapped  = new_signal_handler->swapped;
290
291
292
293
			break;
		}
	}
}
Tristan Van Berkom's avatar
Tristan Van Berkom committed
294
295


296
static gboolean
297
298
glade_widget_button_press_event_impl (GladeWidget    *gwidget,
				      GdkEvent       *base_event)
299
{
300
	GtkWidget         *widget;
301
	GdkEventButton    *event = (GdkEventButton *)base_event;
302
	gboolean           handled = FALSE;
303

304
	/* make sure to grab focus, since we may stop default handlers */
305
	widget = GTK_WIDGET (glade_widget_get_object (gwidget));
306
	if (gtk_widget_get_can_focus (widget) && !gtk_widget_has_focus (widget))
307
		gtk_widget_grab_focus (widget);
308

309
310
	/* if it's already selected don't stop default handlers, e.g. toggle button */
	if (event->button == 1)
311
	{
312
313
		if (event->state & GDK_CONTROL_MASK)
		{
314
315
			if (glade_project_is_selected (gwidget->project,
						       gwidget->object))
316
				glade_app_selection_remove 
317
					(gwidget->object, TRUE);
318
319
			else
				glade_app_selection_add
320
					(gwidget->object, TRUE);
321
322
			handled = TRUE;
		}
323
324
		else if (glade_project_is_selected (gwidget->project,
						    gwidget->object) == FALSE)
325
326
327
		{
			glade_util_clear_selection ();
			glade_app_selection_set 
328
				(gwidget->object, TRUE);
329
330
331
332
333
334

			/* Add selection without interrupting event flow 
			 * when shift is down, this allows better behaviour
			 * for GladeFixed children 
			 */
			handled = !(event->state & GDK_SHIFT_MASK);
335
336
		}
	}
337
338

	/* Give some kind of access in case of missing right button */
339
	if (!handled && glade_popup_is_popup_event (event))
340
341
342
       	{
			glade_popup_widget_pop (gwidget, event, TRUE);
			handled = TRUE;
343
344
	}

345
346
	return handled;
}
347

348
static gboolean
349
350
glade_widget_event_impl (GladeWidget *gwidget,
			 GdkEvent    *event)
351
{
352
353
	gboolean handled = FALSE;

354
	g_return_val_if_fail (GLADE_IS_WIDGET (gwidget), FALSE);
355
356
357
358

	switch (event->type) 
	{
	case GDK_BUTTON_PRESS:
359
360
361
362
363
364
365
366
367
368
369
370
371
372
		g_signal_emit (gwidget, 
			       glade_widget_signals[BUTTON_PRESS_EVENT], 0, 
			       event, &handled);
		break;
	case GDK_BUTTON_RELEASE:
		g_signal_emit (gwidget, 
			       glade_widget_signals[BUTTON_RELEASE_EVENT], 0, 
			       event, &handled);
		break;
	case GDK_MOTION_NOTIFY:
		g_signal_emit (gwidget, 
			       glade_widget_signals[MOTION_NOTIFY_EVENT], 0, 
			       event, &handled);
		break;
373
374
375
376
	default:
		break;
	}

377
	return handled;
378
379
}

380
381
382
383
384
385
386
387

/**
 * glade_widget_event:
 * @event: A #GdkEvent
 *
 * Feed an event to be handled on the project GladeWidget
 * hierarchy.
 *
388
 * Returns: whether the event was handled or not.
389
390
391
392
 */
gboolean
glade_widget_event (GladeWidget *gwidget,
		    GdkEvent    *event)
Tristan Van Berkom's avatar
updated    
Tristan Van Berkom committed
393
{
394
	gboolean   handled = FALSE;
Tristan Van Berkom's avatar
updated    
Tristan Van Berkom committed
395

396
	/* Lets just avoid some synthetic events (like focus-change) */
397
	if (((GdkEventAny *)event)->window == NULL) return FALSE;
398

399
	handled = GLADE_WIDGET_GET_CLASS (gwidget)->event (gwidget, event);
Tristan Van Berkom's avatar
updated    
Tristan Van Berkom committed
400

401
#if 0
402
403
404
	if (event->type != GDK_EXPOSE)
		g_print ("event widget '%s' handled '%d' event '%d'\n",
			 gwidget->name, handled, event->type);
Tristan Van Berkom's avatar
updated    
Tristan Van Berkom committed
405
#endif
406

407
	return handled;
Tristan Van Berkom's avatar
updated    
Tristan Van Berkom committed
408
409
}

410
411
412
/*******************************************************************************
                      GObjectClass & Object Construction
 *******************************************************************************/
413
414
415

/*
 * This function creates new GObject parameters based on the GType of the 
416
 * GladeWidgetAdaptor and its default values.
417
418
419
420
421
422
423
424
425
 *
 * If a GladeWidget is specified, it will be used to apply the
 * values currently in use.
 */
static GParameter *
glade_widget_template_params (GladeWidget      *widget,
			      gboolean          construct,
			      guint            *n_params)
{
426
	GladeWidgetAdaptor    *klass;
427
428
429
430
431
432
433
434
435
436
	GArray              *params;
	GObjectClass        *oclass;
	GParamSpec         **pspec;
	GladeProperty       *glade_property;
	GladePropertyClass  *pclass;
	guint                n_props, i;

	g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
	g_return_val_if_fail (n_params != NULL, NULL);

437
	klass = widget->adaptor;
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
	
	/* As a slight optimization, we never unref the class
	 */
	oclass = g_type_class_ref (klass->type);
	pspec  = g_object_class_list_properties (oclass, &n_props);
	params = g_array_new (FALSE, FALSE, sizeof (GParameter));

	for (i = 0; i < n_props; i++)
	{
		GParameter parameter = { 0, };

		if ((glade_property = 
		     glade_widget_get_property (widget, pspec[i]->name)) == NULL)
			continue;

453
		pclass = glade_property->klass;
454
455
456
		
		/* Ignore properties based on some criteria
		 */
457
458
		if (!glade_property_get_enabled (glade_property) ||
		    pclass == NULL  || /* Unaccounted for in the builder */
459
		    pclass->virt    || /* should not be set before 
460
461
					  GladeWidget wrapper exists */
		    pclass->ignore)    /* Catalog explicitly ignores the object */
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
			continue;

		if (construct &&
		    (pspec[i]->flags & 
		     (G_PARAM_CONSTRUCT|G_PARAM_CONSTRUCT_ONLY)) == 0)
			continue;
		else if (!construct &&
			 (pspec[i]->flags & 
			  (G_PARAM_CONSTRUCT|G_PARAM_CONSTRUCT_ONLY)) != 0)
			continue;

		if (g_value_type_compatible (G_VALUE_TYPE (pclass->def),
					     pspec[i]->value_type) == FALSE)
		{
			g_critical ("Type mismatch on %s property of %s",
				    parameter.name, klass->name);
			continue;
		}

		if (g_param_values_cmp (pspec[i], 
					glade_property->value, 
					pclass->orig_def) == 0)
			continue;


		parameter.name = pspec[i]->name; /* These are not copied/freed */
		g_value_init (&parameter.value, pspec[i]->value_type);
		g_value_copy (glade_property->value, &parameter.value);
		
		g_array_append_val (params, parameter);
	}
	g_free (pspec);

	*n_params = params->len;
	return (GParameter *)g_array_free (params, FALSE);
}

static void
free_params (GParameter *params, guint n_params)
{
	gint i;
	for (i = 0; i < n_params; i++)
		g_value_unset (&(params[i].value));
	g_free (params);

}

static GObject *
510
511
glade_widget_build_object (GladeWidget *widget,
			   GladeWidget *template,
512
			   GladeCreateReason reason)
513
514
515
{
	GParameter          *params;
	GObject             *object;
516
	guint                n_params, i;
517
518
	
	if (reason == GLADE_CREATE_LOAD)
519
520
521
522
523
	{
		object = glade_widget_adaptor_construct_object (widget->adaptor, 0, NULL);
		glade_widget_set_object (widget, object);
		return object;
	}
524

525
	if (template)
526
		params = glade_widget_template_params (widget, TRUE, &n_params);
527
	else
528
		params = glade_widget_adaptor_default_params (widget->adaptor, TRUE, &n_params);
529
530
531

	/* Create the new object with the correct parameters.
	 */
532
	object = glade_widget_adaptor_construct_object (widget->adaptor, n_params, params);
533
534
535

	free_params (params, n_params);

536
537
538
	glade_widget_set_object (widget, object);

	if (template)
539
		params = glade_widget_template_params (widget, FALSE, &n_params);
540
	else
541
		params = glade_widget_adaptor_default_params (widget->adaptor, FALSE, &n_params);
542
543

	for (i = 0; i < n_params; i++)
544
		glade_widget_adaptor_set_property (widget->adaptor, object, params[i].name, &(params[i].value));
545
546
547

	free_params (params, n_params);

548
549
550
	return object;
}

551
552
/**
 * glade_widget_dup_properties:
553
 * @dest_widget: the widget we are copying properties for
554
555
 * @template_props: the #GladeProperty list to copy
 * @as_load: whether to behave as if loading the project
556
557
 * @copy_parentless: whether to copy reffed widgets at all
 * @exact: whether to copy reffed widgets exactly
558
559
560
561
562
563
 *
 * Copies a list of properties, if @as_load is specified, then
 * properties that are not saved to the glade file are ignored.
 *
 * Returns: A newly allocated #GList of new #GladeProperty objects.
 */
564
GList *
565
glade_widget_dup_properties (GladeWidget *dest_widget, GList *template_props, gboolean as_load, 
566
			     gboolean copy_parentless, gboolean exact)
567
568
569
570
571
572
{
	GList *list, *properties = NULL;

	for (list = template_props; list && list->data; list = list->next)
	{
		GladeProperty *prop = list->data;
573
		
574
		if (prop->klass->save == FALSE && as_load)
575
576
			continue;

577
578
579
580
581
582
583

		if (prop->klass->parentless_widget && copy_parentless)
		{
			GObject *object = NULL;
			GladeWidget *parentless;

			glade_property_get (prop, &object);
584
585
586

			prop = glade_property_dup (prop, NULL);

587
588
589
590
591
592
			if (object)
			{
				parentless = glade_widget_get_from_gobject (object);

				parentless = glade_widget_dup (parentless, exact);

593
594
				glade_widget_set_project (parentless, dest_widget->project);

595
596
597
598
599
600
601
602
				glade_property_set (prop, parentless->object);
			}
		} 
		else 
			prop = glade_property_dup (prop, NULL);


		properties = g_list_prepend (properties, prop);
603
604
605
606
	}
	return g_list_reverse (properties);
}

607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
/**
 * glade_widget_remove_property:
 * @widget: A #GladeWidget
 * @id_property: the name of the property
 *
 * Removes the #GladeProperty indicated by @id_property
 * from @widget (this is intended for use in the plugin, to
 * remove properties from composite children that dont make
 * sence to allow the user to specify, notably - properties
 * that are proxied through the composite widget's properties or
 * style properties).
 */
void
glade_widget_remove_property (GladeWidget  *widget,
			      const gchar  *id_property)
{
	GladeProperty *prop;

	g_return_if_fail (GLADE_IS_WIDGET (widget));
	g_return_if_fail (id_property);

628
629
630
631
	/* XXX FIXME: currently we arent calling this on packing properties,
	 * but doing so could cause crashes because the hash table is not
	 * managed properly
	 */
632
633
634
	if ((prop = glade_widget_get_property (widget, id_property)) != NULL)
	{
		widget->properties = g_list_remove (widget->properties, prop);
635
		g_hash_table_remove (widget->props_hash, prop->klass->id);
636
637
638
639
640
641
642
		g_object_unref (prop);
	}
	else
		g_critical ("Couldnt find property %s on widget %s\n",
			    id_property, widget->name);
}

643
644
645
646
647
648
649
650
651
652
653
654
655
656
static void
glade_widget_set_catalog_defaults (GList *list)
{
	GList *l;
	for (l = list; l && l->data; l = l->next)
	{
		GladeProperty *prop  = l->data;
		GladePropertyClass *klass = prop->klass;
		
		if (glade_property_equals_value (prop, klass->orig_def) &&
		     g_param_values_cmp (klass->pspec, klass->orig_def, klass->def))
			glade_property_reset (prop);
	}
}
657

658
659
660
661
662
663
664
static void
glade_widget_sync_custom_props (GladeWidget *widget)
{
	GList *l;
	for (l = widget->properties; l && l->data; l = l->next)
	{
		GladeProperty *prop  = GLADE_PROPERTY(l->data);
665

666
		if (prop->klass->virt || prop->klass->needs_sync)
667
668
			glade_property_sync (prop);

669
670
671
672
673
674
675
676
677
678
679
680
681
	}
}

static void
glade_widget_sync_packing_props (GladeWidget *widget)
{
	GList *l;
	for (l = widget->packing_properties; l && l->data; l = l->next) {
		GladeProperty *prop  = GLADE_PROPERTY(l->data);
		glade_property_sync (prop);
	}
}

682

683
684
685
686
687
688
689
690
691
static GObject *
glade_widget_constructor (GType                  type,
			  guint                  n_construct_properties,
			  GObjectConstructParam *construct_properties)
{
	GladeWidget      *gwidget;
	GObject          *ret_obj, *object;
	GList            *properties = NULL, *list;

692
	ret_obj = G_OBJECT_CLASS (glade_widget_parent_class)->constructor
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
		(type, n_construct_properties, construct_properties);

	gwidget = GLADE_WIDGET (ret_obj);

	if (gwidget->name == NULL)
	{
		if (gwidget->internal)
		{
			gchar *name_base = g_strdup_printf ("%s-%s", 
							    gwidget->construct_internal, 
							    gwidget->internal);
			
			if (gwidget->project)
			{
				gwidget->name = 
					glade_project_new_widget_name (gwidget->project, 
709
								       gwidget,
710
711
712
713
714
715
716
717
718
								       name_base);
				g_free (name_base);
			}
			else
				gwidget->name = name_base;

		}
		else if (gwidget->project)
			gwidget->name = glade_project_new_widget_name
719
				(gwidget->project, gwidget,
720
				 gwidget->adaptor->generic_name);
721
722
		else
			gwidget->name = 
723
				g_strdup (gwidget->adaptor->generic_name);
724
725
726
727
728
	}

	if (gwidget->construct_template)
	{
		properties = glade_widget_dup_properties
729
			(gwidget, gwidget->construct_template->properties, FALSE, TRUE, gwidget->construct_exact);
730
731
732
733
734
735
		
		glade_widget_set_properties (gwidget, properties);
	}

	if (gwidget->object == NULL)
	{
736
		object = glade_widget_build_object(gwidget, 
737
						   gwidget->construct_template, 
738
						   gwidget->construct_reason);
739
740
	}

741
742
743
744
745
746
747
748
749
750
751
752
	/* Copy sync parentless widget props here after a dup
	 */
	if (gwidget->construct_reason == GLADE_CREATE_COPY)
	{
		for (list = gwidget->properties; list; list = list->next)
		{
			GladeProperty *property = list->data;
			if (property->klass->parentless_widget)
				glade_property_sync (property);
		}
	}

753
754
755
756
	/* Setup width/height */
	gwidget->width  = GWA_DEFAULT_WIDTH (gwidget->adaptor);
	gwidget->height = GWA_DEFAULT_HEIGHT (gwidget->adaptor);

757
758
759
760
	/* Introspect object properties before passing it to post_create,
	 * but only when its freshly created (depend on glade file at
	 * load time and copying properties at dup time).
	 */
761
	if (gwidget->construct_reason == GLADE_CREATE_USER)
762
763
		for (list = gwidget->properties; list; list = list->next)
			glade_property_load (GLADE_PROPERTY (list->data));
764
	
765
766
767
768
	/* We only use catalog defaults when the widget was created by the user! */
	if (gwidget->construct_reason == GLADE_CREATE_USER)
		glade_widget_set_catalog_defaults (gwidget->properties);
	
769
770
771
	/* Only call this once the GladeWidget is completely built
	 * (but before calling custom handlers...)
	 */
772
773
774
	glade_widget_adaptor_post_create (gwidget->adaptor, 
					  gwidget->object,
					  gwidget->construct_reason);
775

776
	/* Virtual properties need to be explicitly synchronized.
777
778
779
780
781
782
	 */
	if (gwidget->construct_reason == GLADE_CREATE_USER)
		glade_widget_sync_custom_props (gwidget);

	if (gwidget->parent && gwidget->packing_properties == NULL)
		glade_widget_set_packing_properties (gwidget, gwidget->parent);
783
	
784
	if (GTK_IS_WIDGET (gwidget->object) && !gtk_widget_is_toplevel (GTK_WIDGET (gwidget->object)))
Tristan Van Berkom's avatar
Tristan Van Berkom committed
785
786
787
788
789
790
791
	{
		gwidget->visible = TRUE;
		gtk_widget_show_all (GTK_WIDGET (gwidget->object));
	}
	else if (GTK_IS_WIDGET (gwidget->object) == FALSE)
		gwidget->visible = TRUE;
	
792
793
794
	return ret_obj;
}

795
796
static void
glade_widget_finalize (GObject *object)
797
{
798
	GladeWidget *widget = GLADE_WIDGET (object);
799

800
	g_return_if_fail (GLADE_IS_WIDGET (object));
801

802
803
	g_free (widget->name);
	g_free (widget->internal);
804
	g_free (widget->support_warning);
805
	g_hash_table_destroy (widget->signals);
806

807
808
809
810
811
	if (widget->props_hash)
		g_hash_table_destroy (widget->props_hash);
	if (widget->pack_props_hash)
		g_hash_table_destroy (widget->pack_props_hash);

812
	G_OBJECT_CLASS(glade_widget_parent_class)->finalize(object);
813
814
}

815
816
static void
glade_widget_dispose (GObject *object)
817
{
818
	GladeWidget *widget = GLADE_WIDGET (object);
819

820
	g_return_if_fail (GLADE_IS_WIDGET (object));
Tristan Van Berkom's avatar
Updated    
Tristan Van Berkom committed
821

822
823
824
825
826
	/* At this point, any callbacks on "object" generated by destroy 
	 * wont come with a GladeWidget 
	 */
	g_object_set_qdata (G_OBJECT (object), glade_widget_name_quark, NULL);

827
828
829
830
831
832
833
834
	/* We do not keep a reference to internal widgets */
	if (widget->internal == NULL)
	{
		if (GTK_IS_OBJECT (widget->object))
			gtk_object_destroy (GTK_OBJECT (widget->object));
		else 
			g_object_unref (widget->object);
	}
835

836
837
838
839
	if (widget->properties)
	{
		g_list_foreach (widget->properties, (GFunc)g_object_unref, NULL);
		g_list_free (widget->properties);
840
	}
841
842
843
844
845
846
	
	if (widget->packing_properties)
	{
		g_list_foreach (widget->packing_properties, (GFunc)g_object_unref, NULL);
		g_list_free (widget->packing_properties);
	}
847
848
849
850
851
852
	
	if (widget->actions)
	{
		g_list_foreach (widget->actions, (GFunc)g_object_unref, NULL);
		g_list_free (widget->actions);
	}
853
854
855
856
857
858
859
	
	if (widget->packing_actions)
	{
		g_list_foreach (widget->packing_actions, (GFunc)g_object_unref, NULL);
		g_list_free (widget->packing_actions);
	}
	
860
	G_OBJECT_CLASS (glade_widget_parent_class)->dispose (object);
861
862
}

863
static void
864
865
866
867
glade_widget_set_real_property (GObject         *object,
				guint            prop_id,
				const GValue    *value,
				GParamSpec      *pspec)
868
{
869
	GladeWidget *widget;
870

871
	widget = GLADE_WIDGET (object);
872

873
	switch (prop_id)
874
	{
875
876
877
878
879
880
881
882
883
884
	case PROP_NAME:
		glade_widget_set_name (widget, g_value_get_string (value));
		break;
	case PROP_INTERNAL:
		glade_widget_set_internal (widget, g_value_get_string (value));
		break;
	case PROP_ANARCHIST:
		widget->anarchist = g_value_get_boolean (value);
		break;
	case PROP_OBJECT:
885
886
		if (g_value_get_object (value))
			glade_widget_set_object (widget, g_value_get_object (value));
887
888
889
890
		break;
	case PROP_PROJECT:
		glade_widget_set_project (widget, GLADE_PROJECT (g_value_get_object (value)));
		break;
891
892
893
	case PROP_ADAPTOR:
		glade_widget_set_adaptor (widget, GLADE_WIDGET_ADAPTOR
					  (g_value_get_object (value)));
894
895
896
897
898
899
900
		break;
	case PROP_PROPERTIES:
		glade_widget_set_properties (widget, (GList *)g_value_get_pointer (value));
		break;
	case PROP_PARENT:
		glade_widget_set_parent (widget, GLADE_WIDGET (g_value_get_object (value)));
		break;
901
902
903
904
905
906
907
	case PROP_INTERNAL_NAME:
		if (g_value_get_string (value))
			widget->construct_internal = g_value_dup_string (value);
		break;
	case PROP_TEMPLATE:
		widget->construct_template = g_value_get_object (value);
		break;
908
909
910
	case PROP_TEMPLATE_EXACT:
		widget->construct_exact = g_value_get_boolean (value);
		break;
911
912
913
	case PROP_REASON:
		widget->construct_reason = g_value_get_int (value);
		break;
914
915
916
917
918
919
	case PROP_TOPLEVEL_WIDTH:
		widget->width = g_value_get_int (value);
		break;
	case PROP_TOPLEVEL_HEIGHT:
		widget->height = g_value_get_int (value);
		break;
920
921
922
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
		break;
923
924
925
926
	}
}

static void
927
928
929
930
glade_widget_get_real_property (GObject         *object,
				guint            prop_id,
				GValue          *value,
				GParamSpec      *pspec)
931
{
932
933
934
935
936
	GladeWidget *widget;

	widget = GLADE_WIDGET (object);

	switch (prop_id)
937
	{
938
939
940
941
942
943
944
945
946
	case PROP_NAME:
		g_value_set_string (value, widget->name);
		break;
	case PROP_INTERNAL:
		g_value_set_string (value, widget->internal);
		break;
	case PROP_ANARCHIST:
		g_value_set_boolean (value, widget->anarchist);
		break;
947
948
	case PROP_ADAPTOR:
		g_value_set_object (value, widget->adaptor);
949
950
951
952
953
954
955
956
957
958
959
960
961
		break;
	case PROP_PROJECT:
		g_value_set_object (value, G_OBJECT (widget->project));
		break;
	case PROP_OBJECT:
		g_value_set_object (value, widget->object);
		break;
	case PROP_PROPERTIES:
		g_value_set_pointer (value, widget->properties);
		break;
	case PROP_PARENT:
		g_value_set_object (value, widget->parent);
		break;
962
963
964
965
966
967
	case PROP_TOPLEVEL_WIDTH:
		g_value_set_int (value, widget->width);
		break;
	case PROP_TOPLEVEL_HEIGHT:
		g_value_set_int (value, widget->height);
		break;
968
969
970
	case PROP_SUPPORT_WARNING:
		g_value_set_string (value, widget->support_warning);
		break;
971
972
973
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
		break;
974
975
976
977
	}
}

static void
978
free_signals (gpointer value)
979
{
980
981
982
	GPtrArray *signals = (GPtrArray*) value;
	guint i;
	guint nb_signals;
983

984
985
	if (signals == NULL)
		return;
986

987
988
989
990
991
	/* g_ptr_array_foreach (signals, (GFunc) glade_signal_free, NULL);
	 * only available in modern versions of Gtk+ */
	nb_signals = signals->len;
	for (i = 0; i < nb_signals; i++)
		glade_signal_free (g_ptr_array_index (signals, i));
992

993
	g_ptr_array_free (signals, TRUE);
994
995
}

996
static void
997
glade_widget_init (GladeWidget *widget)
998
{
999
	widget->adaptor = NULL;
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
	widget->project = NULL;
	widget->name = NULL;
	widget->internal = NULL;
	widget->object = NULL;
	widget->properties = NULL;
	widget->packing_properties = NULL;
	widget->prop_refs = NULL;
	widget->signals = g_hash_table_new_full
		(g_str_hash, g_str_equal,
		 (GDestroyNotify) g_free,
		 (GDestroyNotify) free_signals);
1011
1012
1013
1014
	
	/* Initial invalid values */
	widget->width  = -1;
	widget->height = -1;
1015
1016
}

1017
static void
1018
glade_widget_class_init (GladeWidgetClass *klass)
1019
{
1020
	GObjectClass *object_class;
1021

Tristan Van Berkom's avatar
updated    
Tristan Van Berkom committed
1022
1023
1024
1025
	if (glade_widget_name_quark == 0)
		glade_widget_name_quark = 
			g_quark_from_static_string ("GladeWidgetDataTag");

1026
	object_class = G_OBJECT_CLASS (klass);
1027

1028
	object_class->constructor     = glade_widget_constructor;
1029
1030
1031
1032
	object_class->finalize        = glade_widget_finalize;
	object_class->dispose         = glade_widget_dispose;
	object_class->set_property    = glade_widget_set_real_property;
	object_class->get_property    = glade_widget_get_real_property;
1033

1034
1035
	klass->add_child              = glade_widget_add_child_impl;
	klass->remove_child           = glade_widget_remove_child_impl;
Tristan Van Berkom's avatar
updated    
Tristan Van Berkom committed
1036
	klass->replace_child          = glade_widget_replace_child_impl;
1037
	klass->event                  = glade_widget_event_impl;
1038

1039
1040
1041
	klass->add_signal_handler     = glade_widget_add_signal_handler_impl;
	klass->remove_signal_handler  = glade_widget_remove_signal_handler_impl;
	klass->change_signal_handler  = glade_widget_change_signal_handler_impl;
1042

1043
1044
1045
	klass->button_press_event     = glade_widget_button_press_event_impl;
	klass->button_release_event   = NULL;
	klass->motion_notify_event    = NULL;
1046

1047
1048
1049
1050
1051
1052
1053
	g_object_class_install_property
		(object_class, PROP_NAME,
		 g_param_spec_string ("name", _("Name"),
				      _("The name of the widget"),
				      NULL,
				      G_PARAM_READWRITE |
				      G_PARAM_CONSTRUCT));
1054

1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
	g_object_class_install_property
		(object_class, PROP_INTERNAL,
		 g_param_spec_string ("internal", _("Internal name"),
				      _("The internal name of the widget"),
				      NULL, G_PARAM_READWRITE |
				      G_PARAM_CONSTRUCT));
	
	g_object_class_install_property
		(object_class, PROP_ANARCHIST,
		 g_param_spec_boolean ("anarchist", _("Anarchist"),
				       _("Whether this composite child is "
					 "an ancestral child or an anarchist child"),
				       FALSE, G_PARAM_READWRITE |
				       G_PARAM_CONSTRUCT_ONLY));
1069

1070
1071
1072
1073
1074
1075
1076
	g_object_class_install_property
		(object_class, PROP_OBJECT,
		 g_param_spec_object ("object", _("Object"),
				      _("The object associated"),
				      G_TYPE_OBJECT,
				      G_PARAM_READWRITE |
				      G_PARAM_CONSTRUCT));
1077

1078
	g_object_class_install_property
1079
1080
1081
1082
1083
1084
		(object_class, PROP_ADAPTOR,
		   g_param_spec_object ("adaptor", _("Adaptor"),
					_("The class adaptor for the associated widget"),
					GLADE_TYPE_WIDGET_ADAPTOR,
					G_PARAM_READWRITE |
					G_PARAM_CONSTRUCT_ONLY));
1085

1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
	g_object_class_install_property
		(object_class, PROP_PROJECT,
		 g_param_spec_object ("project", _("Project"),
				      _("The glade project that "
					"this widget belongs to"),
				      GLADE_TYPE_PROJECT,
				      G_PARAM_READWRITE |
				      G_PARAM_CONSTRUCT));

	g_object_class_install_property
		(object_class, PROP_PROPERTIES,
		 g_param_spec_pointer ("properties", _("Properties"),
				       _("A list of GladeProperties"),
				       G_PARAM_READWRITE |
				       G_PARAM_CONSTRUCT_ONLY));
1101

1102
1103
1104
	g_object_class_install_property
		(object_class, 	PROP_PARENT,
		 g_param_spec_object ("parent", _("Parent"),
1105
1106
1107
1108
				      _("A pointer to the parenting GladeWidget"),
				      GLADE_TYPE_WIDGET,
				      G_PARAM_READWRITE |
				      G_PARAM_CONSTRUCT));
1109

1110
1111
1112
1113
1114
	g_object_class_install_property
		(object_class, 	PROP_INTERNAL_NAME,
		 g_param_spec_string ("internal-name", _("Internal Name"),
				      _("A generic name prefix for internal widgets"),
				      NULL, G_PARAM_CONSTRUCT_ONLY|G_PARAM_WRITABLE));
1115

1116
1117
1118
1119
1120
1121
1122
	g_object_class_install_property
		(object_class, 	PROP_TEMPLATE,
		 g_param_spec_object ("template", _("Template"),
				       _("A GladeWidget template to base a new widget on"),
				      GLADE_TYPE_WIDGET,
				      G_PARAM_CONSTRUCT_ONLY|G_PARAM_WRITABLE));

1123
1124
1125
1126
1127
1128
	g_object_class_install_property
		(object_class, PROP_TEMPLATE_EXACT,
		 g_param_spec_boolean ("template-exact", _("Exact Template"),
				       _("Whether we are creating an exact duplicate when using a template"),
				       FALSE, G_PARAM_WRITABLE|G_PARAM_CONSTRUCT_ONLY));

1129
1130
1131
1132
1133
1134
1135
1136
	g_object_class_install_property
		(object_class, 	PROP_REASON,
		 g_param_spec_int ("reason", _("Reason"),
				   _("A GladeCreateReason for this creation"),
				   GLADE_CREATE_USER,
				   GLADE_CREATE_REASONS - 1,
				   GLADE_CREATE_USER,
				   G_PARAM_CONSTRUCT_ONLY|G_PARAM_WRITABLE));
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157

	g_object_class_install_property
		(object_class, 	PROP_TOPLEVEL_WIDTH,
		 g_param_spec_int ("toplevel-width", _("Toplevel Width"),
				   _("The width of the widget when toplevel in "
				     "the GladeDesignLayout"),
				   -1,
				   G_MAXINT,
				   -1,
				   G_PARAM_READWRITE));

	g_object_class_install_property
		(object_class, 	PROP_TOPLEVEL_HEIGHT,
		 g_param_spec_int ("toplevel-height", _("Toplevel Height"),
				   _("The height of the widget when toplevel in "
				     "the GladeDesignLayout"),
				   -1,
				   G_MAXINT,
				   -1,
				   G_PARAM_READWRITE));

1158
1159
1160
1161
1162
1163
	g_object_class_install_property
		(object_class, 	PROP_SUPPORT_WARNING,
		 g_param_spec_string ("support warning", _("Support Warning"),
				      _("A warning string about version mismatches"),
				      NULL, G_PARAM_READABLE));

1164
1165
1166
1167