1 /*
2  * Copyright (C) 2008 Tristan Van Berkom
3  * Copyright (C) 2004 Joaquin Cuenca Abela
4  * Copyright (C) 2001, 2002, 2003 Ximian, Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * Authors:
21  *   Joaquin Cuenca Abela <e98cuenc@yahoo.com>
22  *   Chema Celorio <chema@celorio.com>
23  *   Tristan Van Berkom <tvb@gnome.org>
24  */
25 
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29 
30 /**
31  * SECTION:glade-widget
32  * @Short_Description: An object wrapper for the Glade runtime environment.
33  *
34  * #GladeWidget is the proxy between the instantiated runtime object and
35  * the Glade core metadata. This api will be mostly usefull for its
36  * convenience api for getting and setting properties (mostly from the plugin).
37  */
38 
39 #include <string.h>
40 #include <glib-object.h>
41 #include <gdk/gdkkeysyms.h>
42 #include <glib/gi18n-lib.h>
43 #include "glade.h"
44 #include "glade-accumulators.h"
45 #include "glade-project.h"
46 #include "glade-widget-adaptor.h"
47 #include "glade-private.h"
48 #include "glade-marshallers.h"
49 #include "glade-property.h"
50 #include "glade-property-class.h"
51 #include "glade-placeholder.h"
52 #include "glade-signal.h"
53 #include "glade-popup.h"
54 #include "glade-editor.h"
55 #include "glade-app.h"
56 #include "glade-design-view.h"
57 #include "glade-widget-action.h"
58 #include "glade-signal-model.h"
59 #include "glade-object-stub.h"
60 #include "glade-dnd.h"
61 
62 static void glade_widget_set_adaptor    (GladeWidget        *widget,
63                                          GladeWidgetAdaptor *adaptor);
64 static void glade_widget_set_properties (GladeWidget        *widget,
65                                          GList              *properties);
66 static void glade_widget_set_object     (GladeWidget        *gwidget,
67                                          GObject            *new_object);
68 
69 
70 struct _GladeWidgetPrivate {
71 
72   GladeWidgetAdaptor *adaptor; /* An adaptor class for the object type */
73 
74   GladeProject       *project; /* A pointer to the project that this
75 				  widget currently belongs to. */
76 
77   GladeWidget  *parent;  /* A pointer to the parent widget in the hierarchy */
78 
79   gchar *name; /* The name of the widget. For example window1 or
80 		* button2. This is a unique name and is the one
81 		* used when loading widget with libglade
82 		*/
83 
84   gchar *support_warning; /* A warning message for version incompatabilities
85 			   * in this widget
86 			   */
87 
88   gchar *internal; /* If the widget is an internal child of
89 		    * another widget this is the name of the
90 		    * internal child, otherwise is NULL.
91 		    * Internal children cannot be deleted.
92 		    */
93 
94   gboolean anarchist; /* Some composite widgets have internal children
95 		       * that are not part of the same hierarchy; hence 'anarchists',
96 		       * typicly a popup window or its child (we need to mark
97 		       * them so we can avoid bookkeeping packing props on them etc.).
98 		       */
99 
100   GObject *object; /* A pointer to the object that was created.
101 		    * if it is a GtkWidget; it is shown as a "view"
102 		    * of the GladeWidget. This object is updated as
103 		    * the properties are modified for the GladeWidget.
104 		    */
105 
106   GList *properties; /* A list of GladeProperty. A GladeProperty is an
107 		      * instance of a GladePropertyClass. If a
108 		      * GladePropertyClass for a gtkbutton is label, its
109 		      * property is "Ok".
110 		      */
111 
112   GList *packing_properties; /* A list of GladeProperty. Note that these
113 			      * properties are related to the container
114 			      * of the widget, thus they change after
115 			      * pasting the widget to a different
116 			      * container. Toplevels widget do not have
117 			      * packing properties.
118 			      * See also child_properties of
119 			      * GladeWidgetClass.
120 			      */
121 
122   GHashTable *props_hash; /* A Quick reference table to speed up calls to glade_widget_get_property()
123 			   */
124   GHashTable *pack_props_hash; /* A Quick reference table to speed up calls to glade_widget_get_pack_property()
125 				*/
126 
127   GHashTable *signals; /* A table with a GPtrArray of GladeSignals (signal handlers),
128 			* indexed by its name */
129 
130   GList     *prop_refs; /* List of properties in the project who's value are `this object'
131 			 * (this is used to set/unset those properties when the object is
132 			 * added/removed from the project).
133 			 */
134 
135   gint               width;   /* Current size used in the UI, this is only */
136   gint               height;  /* usefull for parentless widgets in the
137 			       * GladeDesignLayout */
138 
139   GList *actions;		/* A GladeWidgetAction list */
140 
141   GList *packing_actions;	/* A GladeWidgetAction list, this actions are
142 				 * related to the container and they are not always present.
143 				 */
144 
145   GladeWidget    *lock; /* The glade widget that has locked this widget down.
146 			 */
147   GList          *locked_widgets; /* A list of widgets this widget has locked down.
148 				   */
149 
150   GtkTreeModel   *signal_model; /* Signal model (or NULL if not yet requested) */
151 
152   /* Construct parameters: */
153   GladeWidget       *construct_template;
154   GladeCreateReason  construct_reason;
155   gchar             *construct_internal;
156   guint              construct_exact : 1;
157 
158   guint              in_project : 1;
159 
160   guint              visible : 1; /* Local copy of widget visibility, we need to keep track of this
161 				   * since the objects copy may be invalid due to a rebuild.
162 				   */
163   guint              rebuilding : 1;
164   guint              composite : 1;
165 };
166 
167 enum
168 {
169   ADD_SIGNAL_HANDLER,
170   REMOVE_SIGNAL_HANDLER,
171   CHANGE_SIGNAL_HANDLER,
172   BUTTON_PRESS_EVENT,
173   BUTTON_RELEASE_EVENT,
174   MOTION_NOTIFY_EVENT,
175   SUPPORT_CHANGED,
176   LAST_SIGNAL
177 };
178 
179 enum
180 {
181   PROP_0,
182   PROP_NAME,
183   PROP_INTERNAL,
184   PROP_ANARCHIST,
185   PROP_ADAPTOR,
186   PROP_OBJECT,
187   PROP_PROJECT,
188   PROP_PROPERTIES,
189   PROP_PARENT,
190   PROP_INTERNAL_NAME,
191   PROP_TEMPLATE,
192   PROP_TEMPLATE_EXACT,
193   PROP_REASON,
194   PROP_TOPLEVEL_WIDTH,
195   PROP_TOPLEVEL_HEIGHT,
196   PROP_SUPPORT_WARNING,
197   PROP_VISIBLE,
198   PROP_COMPOSITE,
199   N_PROPERTIES
200 };
201 
202 static GParamSpec *properties[N_PROPERTIES];
203 static guint glade_widget_signals[LAST_SIGNAL] = { 0 };
204 
205 static GQuark glade_widget_name_quark = 0;
206 
207 static void glade_widget_drag_init (_GladeDragInterface *iface);
208 
G_DEFINE_TYPE_WITH_CODE(GladeWidget,glade_widget,G_TYPE_INITIALLY_UNOWNED,G_ADD_PRIVATE (GladeWidget)G_IMPLEMENT_INTERFACE (GLADE_TYPE_DRAG,glade_widget_drag_init))209 G_DEFINE_TYPE_WITH_CODE (GladeWidget, glade_widget, G_TYPE_INITIALLY_UNOWNED,
210                          G_ADD_PRIVATE (GladeWidget)
211                          G_IMPLEMENT_INTERFACE (GLADE_TYPE_DRAG,
212                                                 glade_widget_drag_init))
213 
214 /*******************************************************************************
215                            GladeWidget class methods
216  *******************************************************************************/
217 static void
218 glade_widget_set_packing_actions (GladeWidget *widget,
219 				  GladeWidget *parent)
220 {
221   if (widget->priv->packing_actions)
222     {
223       g_list_foreach (widget->priv->packing_actions, (GFunc) g_object_unref, NULL);
224       g_list_free (widget->priv->packing_actions);
225       widget->priv->packing_actions = NULL;
226     }
227 
228   widget->priv->packing_actions =
229     glade_widget_adaptor_pack_actions_new (parent->priv->adaptor);
230 }
231 
232 static void
glade_widget_add_child_impl(GladeWidget * widget,GladeWidget * child,gboolean at_mouse)233 glade_widget_add_child_impl (GladeWidget *widget,
234                              GladeWidget *child, gboolean at_mouse)
235 {
236   g_object_ref (child);
237 
238   /* Safe to set the parent first... setting it afterwards
239    * creates packing properties, and that is not always
240    * desirable.
241    */
242   glade_widget_set_parent (child, widget);
243 
244   /* Set packing actions first so we have access from the plugin
245    */
246   glade_widget_set_packing_actions (child, widget);
247 
248   glade_widget_adaptor_add (widget->priv->adaptor,
249 			    widget->priv->object,
250 			    child->priv->object);
251 
252   /* XXX FIXME:
253    * We have a fundamental flaw here, we set packing props
254    * after parenting the widget so that we can introspect the
255    * values setup by the runtime widget, in which case the plugin
256    * cannot access its packing properties and set them sensitive
257    * or connect to thier signals etc. maybe its not so important
258    * but its a flaw worthy of note, some kind of double pass api
259    * would be needed to accomadate this.
260    */
261 
262 
263   /* Setup packing properties here so we can introspect the new
264    * values from the backend.
265    */
266   glade_widget_set_packing_properties (child, widget);
267 }
268 
269 static void
glade_widget_remove_child_impl(GladeWidget * widget,GladeWidget * child)270 glade_widget_remove_child_impl (GladeWidget *widget, GladeWidget *child)
271 {
272   glade_widget_adaptor_remove (widget->priv->adaptor, widget->priv->object, child->priv->object);
273 
274   child->priv->parent = NULL;
275 
276   g_object_unref (child);
277 }
278 
279 static void
glade_widget_replace_child_impl(GladeWidget * widget,GObject * old_object,GObject * new_object)280 glade_widget_replace_child_impl (GladeWidget *widget,
281                                  GObject     *old_object,
282                                  GObject     *new_object)
283 {
284   GladeWidget *gnew_widget = glade_widget_get_from_gobject (new_object);
285   GladeWidget *gold_widget = glade_widget_get_from_gobject (old_object);
286 
287   if (gnew_widget)
288     {
289       g_object_ref (gnew_widget);
290 
291       gnew_widget->priv->parent = widget;
292 
293       /* Set packing actions first so we have access from the plugin
294        */
295       glade_widget_set_packing_actions (gnew_widget, widget);
296     }
297 
298   if (gold_widget)
299     {
300       g_object_unref (gold_widget);
301 
302       if (gold_widget != gnew_widget)
303         gold_widget->priv->parent = NULL;
304     }
305 
306   glade_widget_adaptor_replace_child
307       (widget->priv->adaptor, widget->priv->object, old_object, new_object);
308 
309   /* Setup packing properties here so we can introspect the new
310    * values from the backend.
311    */
312   if (gnew_widget)
313     glade_widget_set_packing_properties (gnew_widget, widget);
314 }
315 
316 /**
317  * glade_widget_add_signal_handler:
318  * @widget: A #GladeWidget
319  * @signal_handler: The #GladeSignal
320  *
321  * Adds a signal handler for @widget
322  */
323 void
glade_widget_add_signal_handler(GladeWidget * widget,const GladeSignal * signal_handler)324 glade_widget_add_signal_handler (GladeWidget       *widget,
325                                  const GladeSignal *signal_handler)
326 {
327   GPtrArray *signals;
328   GladeSignal *new_signal_handler;
329 
330   g_return_if_fail (GLADE_IS_WIDGET (widget));
331   g_return_if_fail (GLADE_IS_SIGNAL (signal_handler));
332 
333   signals = glade_widget_list_signal_handlers (widget, glade_signal_get_name (signal_handler));
334   if (!signals)
335     {
336       signals = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
337       g_hash_table_insert (widget->priv->signals,
338 			   g_strdup (glade_signal_get_name (signal_handler)),
339                            signals);
340     }
341 
342   new_signal_handler = glade_signal_clone (signal_handler);
343   g_ptr_array_add (signals, new_signal_handler);
344   g_signal_emit (widget, glade_widget_signals[ADD_SIGNAL_HANDLER], 0, new_signal_handler);
345 
346   glade_project_verify_signal (widget, new_signal_handler);
347 
348   if (glade_signal_get_support_warning (new_signal_handler))
349     glade_widget_verify (widget);
350 }
351 
352 /**
353  * glade_widget_remove_signal_handler:
354  * @widget: A #GladeWidget
355  * @signal_handler: The #GladeSignal
356  *
357  * Removes a signal handler from @widget
358  */
359 
360 void
glade_widget_remove_signal_handler(GladeWidget * widget,const GladeSignal * signal_handler)361 glade_widget_remove_signal_handler (GladeWidget       *widget,
362                                     const GladeSignal *signal_handler)
363 {
364   GPtrArray *signals;
365   GladeSignal *tmp_signal_handler;
366   guint i;
367 
368   g_return_if_fail (GLADE_IS_WIDGET (widget));
369   g_return_if_fail (GLADE_IS_SIGNAL (signal_handler));
370 
371   signals = glade_widget_list_signal_handlers (widget, glade_signal_get_name (signal_handler));
372 
373   /* trying to remove an inexistent signal? */
374   g_assert (signals);
375 
376   for (i = 0; i < signals->len; i++)
377     {
378       tmp_signal_handler = g_ptr_array_index (signals, i);
379       if (glade_signal_equal (tmp_signal_handler, signal_handler))
380         {
381 	  g_signal_emit (widget, glade_widget_signals[REMOVE_SIGNAL_HANDLER], 0, tmp_signal_handler);
382           g_ptr_array_remove_index (signals, i);
383 
384 	  if (glade_signal_get_support_warning (tmp_signal_handler))
385 	    glade_widget_verify (widget);
386 
387           g_object_unref (tmp_signal_handler);
388           break;
389         }
390     }
391 }
392 
393 /**
394  * glade_widget_change_signal_handler:
395  * @widget: A #GladeWidget
396  * @old_signal_handler: the old #GladeSignal
397  * @new_signal_handler: the new #GladeSignal
398  *
399  * Changes a #GladeSignal on @widget
400  */
401 void
glade_widget_change_signal_handler(GladeWidget * widget,const GladeSignal * old_signal_handler,const GladeSignal * new_signal_handler)402 glade_widget_change_signal_handler (GladeWidget       *widget,
403                                     const GladeSignal *old_signal_handler,
404                                     const GladeSignal *new_signal_handler)
405 {
406   GPtrArray *signals;
407   GladeSignal *signal_handler_iter;
408   guint i;
409 
410   g_return_if_fail (GLADE_IS_WIDGET (widget));
411   g_return_if_fail (GLADE_IS_SIGNAL (old_signal_handler));
412   g_return_if_fail (GLADE_IS_SIGNAL (new_signal_handler));
413   g_return_if_fail (strcmp (glade_signal_get_name (old_signal_handler),
414 			    glade_signal_get_name (new_signal_handler)) == 0);
415 
416   signals =
417     glade_widget_list_signal_handlers (widget, glade_signal_get_name (old_signal_handler));
418 
419   /* trying to remove an inexistent signal? */
420   g_assert (signals);
421 
422   for (i = 0; i < signals->len; i++)
423     {
424       signal_handler_iter = g_ptr_array_index (signals, i);
425       if (glade_signal_equal (signal_handler_iter, old_signal_handler))
426         {
427           /* Detail */
428 	  glade_signal_set_detail (signal_handler_iter,
429 				   glade_signal_get_detail (new_signal_handler));
430 
431           /* Handler */
432 	  glade_signal_set_handler (signal_handler_iter,
433 				    glade_signal_get_handler (new_signal_handler));
434 
435           /* Object */
436 	  glade_signal_set_userdata (signal_handler_iter,
437 				     glade_signal_get_userdata (new_signal_handler));
438 
439 	  /* Flags */
440 	  glade_signal_set_after (signal_handler_iter,
441 				  glade_signal_get_after (new_signal_handler));
442 	  glade_signal_set_swapped (signal_handler_iter,
443 				    glade_signal_get_swapped (new_signal_handler));
444 
445 	  g_signal_emit (widget, glade_widget_signals[CHANGE_SIGNAL_HANDLER], 0,
446 	                 signal_handler_iter);
447 
448 	  break;
449         }
450     }
451 }
452 
453 static gboolean
glade_widget_button_press_event_impl(GladeWidget * gwidget,GdkEvent * base_event)454 glade_widget_button_press_event_impl (GladeWidget *gwidget,
455                                       GdkEvent    *base_event)
456 {
457   GtkWidget *widget;
458   GdkEventButton *event = (GdkEventButton *) base_event;
459   gboolean handled = FALSE;
460 
461   /* make sure to grab focus, since we may stop default handlers */
462   widget = GTK_WIDGET (glade_widget_get_object (gwidget));
463   if (gtk_widget_get_can_focus (widget) && !gtk_widget_has_focus (widget))
464     gtk_widget_grab_focus (widget);
465 
466   /* if it's already selected don't stop default handlers, e.g. toggle button */
467   if (event->button == 1)
468     {
469       if (event->state & GDK_CONTROL_MASK)
470         {
471           if (glade_project_is_selected (gwidget->priv->project, gwidget->priv->object))
472             glade_project_selection_remove (gwidget->priv->project, gwidget->priv->object, TRUE);
473           else
474             glade_project_selection_add (gwidget->priv->project, gwidget->priv->object, TRUE);
475           handled = TRUE;
476         }
477       else if (glade_project_is_selected (gwidget->priv->project,
478                                           gwidget->priv->object) == FALSE)
479         {
480           glade_project_selection_set (gwidget->priv->project,
481 				       gwidget->priv->object, TRUE);
482 
483           /* Add selection without interrupting event flow
484            * when shift is down, this allows better behaviour
485            * for GladeFixed children
486            */
487           handled = !(event->state & GDK_SHIFT_MASK);
488         }
489     }
490 
491   /* Give some kind of access in case of missing right button */
492   if (!handled && glade_popup_is_popup_event (event))
493     {
494       glade_popup_widget_pop (gwidget, event, TRUE);
495       handled = TRUE;
496     }
497 
498   return handled;
499 }
500 
501 static gboolean
glade_widget_event_impl(GladeWidget * gwidget,GdkEvent * event)502 glade_widget_event_impl (GladeWidget *gwidget, GdkEvent *event)
503 {
504   gboolean handled = FALSE;
505 
506   g_return_val_if_fail (GLADE_IS_WIDGET (gwidget), FALSE);
507 
508   switch (event->type)
509     {
510       case GDK_BUTTON_PRESS:
511         g_signal_emit (gwidget,
512                        glade_widget_signals[BUTTON_PRESS_EVENT], 0,
513                        event, &handled);
514         break;
515       case GDK_BUTTON_RELEASE:
516         g_signal_emit (gwidget,
517                        glade_widget_signals[BUTTON_RELEASE_EVENT], 0,
518                        event, &handled);
519         break;
520       case GDK_MOTION_NOTIFY:
521         g_signal_emit (gwidget,
522                        glade_widget_signals[MOTION_NOTIFY_EVENT], 0,
523                        event, &handled);
524         break;
525       default:
526         break;
527     }
528 
529   return handled;
530 }
531 
532 
533 /**
534  * glade_widget_event:
535  * @event: A #GdkEvent
536  *
537  * Feed an event to be handled on the project GladeWidget
538  * hierarchy.
539  *
540  * Returns: whether the event was handled or not.
541  */
542 gboolean
glade_widget_event(GladeWidget * gwidget,GdkEvent * event)543 glade_widget_event (GladeWidget *gwidget, GdkEvent *event)
544 {
545   gboolean handled = FALSE;
546 
547   /* Lets just avoid some synthetic events (like focus-change) */
548   if (((GdkEventAny *) event)->window == NULL)
549     return FALSE;
550 
551   handled = GLADE_WIDGET_GET_CLASS (gwidget)->event (gwidget, event);
552 
553 #ifdef GLADE_ENABLE_DEBUG
554   if (event->type != GDK_EXPOSE)
555     GLADE_NOTE (WIDGET_EVENTS,
556 		g_print ("event widget '%s' handled '%d' event '%d'\n",
557 			 gwidget->priv->name, handled, event->type));
558 #endif
559 
560   return handled;
561 }
562 
563 /*******************************************************************************
564                       GObjectClass & Object Construction
565  *******************************************************************************/
566 
567 /*
568  * This function creates new GObject parameters based on the GType of the
569  * GladeWidgetAdaptor and its default values.
570  *
571  * If a GladeWidget is specified, it will be used to apply the
572  * values currently in use.
573  */
574 static GParameter *
glade_widget_template_params(GladeWidget * widget,gboolean construct,guint * n_params)575 glade_widget_template_params (GladeWidget *widget,
576                               gboolean     construct,
577                               guint       *n_params)
578 {
579   GladeWidgetAdaptor *adaptor;
580   GArray             *params;
581   GObjectClass       *oclass;
582   GParamSpec        **pspec;
583   GladeProperty      *glade_property;
584   GladePropertyClass *pclass;
585   guint               n_props, i;
586 
587   g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
588   g_return_val_if_fail (n_params != NULL, NULL);
589 
590   adaptor = widget->priv->adaptor;
591 
592   /* As a slight optimization, we never unref the class
593    */
594   oclass = g_type_class_ref (glade_widget_adaptor_get_object_type (adaptor));
595   pspec = g_object_class_list_properties (oclass, &n_props);
596   params = g_array_new (FALSE, FALSE, sizeof (GParameter));
597 
598   for (i = 0; i < n_props; i++)
599     {
600       GParameter parameter = { 0, };
601 
602       if ((glade_property =
603            glade_widget_get_property (widget, pspec[i]->name)) == NULL)
604         continue;
605 
606       pclass = glade_property_get_class (glade_property);
607 
608       /* Ignore properties based on some criteria
609        */
610       if (!glade_property_get_enabled (glade_property) ||
611 	  pclass == NULL ||     /* Unaccounted for in the builder */
612           glade_property_class_get_virtual (pclass) ||  /* should not be set before
613 							   GladeWidget wrapper exists */
614           glade_property_class_get_ignore (pclass))     /* Catalog explicitly ignores the object */
615         continue;
616 
617       if (construct &&
618           (pspec[i]->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) == 0)
619         continue;
620       else if (!construct &&
621                (pspec[i]->flags &
622                 (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) != 0)
623         continue;
624 
625       if (g_value_type_compatible (G_VALUE_TYPE (glade_property_class_get_default (pclass)),
626                                    pspec[i]->value_type) == FALSE)
627         {
628           g_critical ("Type mismatch on %s property of %s",
629                       parameter.name,
630 		      glade_widget_adaptor_get_name (adaptor));
631           continue;
632         }
633 
634       /* We only check equality on properties introduced by the same class because
635        * others properties could change its default in a derivated class
636        * so its is better to transfer every property and reset them.
637        */
638       if (pspec[i]->owner_type == glade_widget_adaptor_get_object_type (adaptor) &&
639           g_param_values_cmp (pspec[i],
640                               glade_property_inline_value (glade_property),
641                               glade_property_class_get_original_default (pclass)) == 0)
642         continue;
643 
644       /* Not sure if it's safe to use glade_property_get_value() instead as the
645        * value type might differ than the real pspec
646        */
647       parameter.name = pspec[i]->name;  /* These are not copied/freed */
648       g_value_init (&parameter.value, pspec[i]->value_type);
649       g_value_copy (glade_property_inline_value (glade_property), &parameter.value);
650 
651       g_array_append_val (params, parameter);
652     }
653   g_free (pspec);
654 
655   *n_params = params->len;
656   return (GParameter *) g_array_free (params, FALSE);
657 }
658 
659 static void
free_params(GParameter * params,guint n_params)660 free_params (GParameter *params, guint n_params)
661 {
662   gint i;
663   for (i = 0; i < n_params; i++)
664     g_value_unset (&(params[i].value));
665   g_free (params);
666 
667 }
668 
669 static GObject *
glade_widget_build_object(GladeWidget * widget,GladeWidget * template,GladeCreateReason reason)670 glade_widget_build_object (GladeWidget      *widget,
671                            GladeWidget      *template,
672                            GladeCreateReason reason)
673 {
674   GParameter *params;
675   GObject *object;
676   guint n_params, i;
677 
678   if (reason == GLADE_CREATE_LOAD)
679     {
680       object = glade_widget_adaptor_construct_object (widget->priv->adaptor, 0, NULL);
681       glade_widget_set_object (widget, object);
682       return object;
683     }
684 
685   if (template)
686     params = glade_widget_template_params (widget, TRUE, &n_params);
687   else
688     params =
689         glade_widget_adaptor_default_params (widget->priv->adaptor, TRUE, &n_params);
690 
691   /* Create the new object with the correct parameters.
692    */
693   object =
694       glade_widget_adaptor_construct_object (widget->priv->adaptor, n_params, params);
695 
696   free_params (params, n_params);
697 
698   glade_widget_set_object (widget, object);
699 
700   if (template)
701     params = glade_widget_template_params (widget, FALSE, &n_params);
702   else
703     params =
704         glade_widget_adaptor_default_params (widget->priv->adaptor, FALSE, &n_params);
705 
706   for (i = 0; i < n_params; i++)
707     glade_widget_adaptor_set_property (widget->priv->adaptor, object, params[i].name,
708                                        &(params[i].value));
709 
710   free_params (params, n_params);
711 
712   return object;
713 }
714 
715 /**
716  * glade_widget_dup_properties:
717  * @dest_widget: the widget we are copying properties for
718  * @template_props: the #GladeProperty list to copy
719  * @as_load: whether to behave as if loading the project
720  * @copy_parentless: whether to copy reffed widgets at all
721  * @exact: whether to copy reffed widgets exactly
722  *
723  * Copies a list of properties, if @as_load is specified, then
724  * properties that are not saved to the glade file are ignored.
725  *
726  * Returns: A newly allocated #GList of new #GladeProperty objects.
727  */
728 GList *
glade_widget_dup_properties(GladeWidget * dest_widget,GList * template_props,gboolean as_load,gboolean copy_parentless,gboolean exact)729 glade_widget_dup_properties (GladeWidget *dest_widget,
730                              GList       *template_props,
731                              gboolean     as_load,
732                              gboolean     copy_parentless,
733                              gboolean     exact)
734 {
735   GList *list, *properties = NULL;
736 
737   for (list = template_props; list && list->data; list = list->next)
738     {
739       GladeProperty      *prop = list->data;
740       GladePropertyClass *pclass = glade_property_get_class (prop);
741 
742       if (glade_property_class_save (pclass) == FALSE && as_load)
743         continue;
744 
745       if (glade_property_class_parentless_widget (pclass) && copy_parentless)
746         {
747           GObject *object = NULL;
748           GladeWidget *parentless;
749 
750           glade_property_get (prop, &object);
751 
752           prop = glade_property_dup (prop, NULL);
753 
754           if (object)
755             {
756               parentless = glade_widget_get_from_gobject (object);
757 
758               parentless = glade_widget_dup (parentless, exact);
759 
760               glade_widget_set_project (parentless, dest_widget->priv->project);
761 
762               glade_property_set (prop, parentless->priv->object);
763             }
764         }
765       else
766         prop = glade_property_dup (prop, NULL);
767 
768 
769       properties = g_list_prepend (properties, prop);
770     }
771   return g_list_reverse (properties);
772 }
773 
774 /**
775  * glade_widget_remove_property:
776  * @widget: A #GladeWidget
777  * @id_property: the name of the property
778  *
779  * Removes the #GladeProperty indicated by @id_property
780  * from @widget (this is intended for use in the plugin, to
781  * remove properties from composite children that dont make
782  * sence to allow the user to specify, notably - properties
783  * that are proxied through the composite widget's properties or
784  * style properties).
785  */
786 void
glade_widget_remove_property(GladeWidget * widget,const gchar * id_property)787 glade_widget_remove_property (GladeWidget *widget, const gchar *id_property)
788 {
789   GladeProperty *prop;
790 
791   g_return_if_fail (GLADE_IS_WIDGET (widget));
792   g_return_if_fail (id_property);
793 
794   /* XXX FIXME: currently we arent calling this on packing properties,
795    * but doing so could cause crashes because the hash table is not
796    * managed properly
797    */
798   if ((prop = glade_widget_get_property (widget, id_property)) != NULL)
799     {
800       widget->priv->properties = g_list_remove (widget->priv->properties, prop);
801       g_hash_table_remove (widget->priv->props_hash, id_property);
802       g_object_unref (prop);
803     }
804   else
805     g_critical ("Couldnt find property %s on widget %s\n",
806                 id_property, widget->priv->name);
807 }
808 
809 static void
glade_widget_set_catalog_defaults(GList * list)810 glade_widget_set_catalog_defaults (GList *list)
811 {
812   GList *l;
813   for (l = list; l && l->data; l = l->next)
814     {
815       GladeProperty      *prop = l->data;
816       GladePropertyClass *klass = glade_property_get_class (prop);
817       GParamSpec         *pspec = glade_property_class_get_pspec (klass);
818 
819       if (glade_property_equals_value (prop, glade_property_class_get_original_default (klass)) &&
820           g_param_values_cmp (pspec,
821 			      glade_property_class_get_original_default (klass),
822 			      glade_property_class_get_default (klass)))
823         glade_property_reset (prop);
824     }
825 }
826 
827 static void
glade_widget_sync_custom_props(GladeWidget * widget)828 glade_widget_sync_custom_props (GladeWidget *widget)
829 {
830   GList *l;
831   for (l = widget->priv->properties; l && l->data; l = l->next)
832     {
833       GladeProperty      *prop = GLADE_PROPERTY (l->data);
834       GladePropertyClass *pclass = glade_property_get_class (prop);
835 
836       if (glade_property_class_get_virtual (pclass) ||
837 	  glade_property_class_needs_sync (pclass))
838         glade_property_sync (prop);
839     }
840 }
841 
842 static void
glade_widget_sync_packing_props(GladeWidget * widget)843 glade_widget_sync_packing_props (GladeWidget *widget)
844 {
845   GList *l;
846   for (l = widget->priv->packing_properties; l && l->data; l = l->next)
847     {
848       GladeProperty *prop = GLADE_PROPERTY (l->data);
849       glade_property_sync (prop);
850     }
851 }
852 
853 
854 static GObject *
glade_widget_constructor(GType type,guint n_construct_properties,GObjectConstructParam * construct_properties)855 glade_widget_constructor (GType                  type,
856                           guint                  n_construct_properties,
857                           GObjectConstructParam *construct_properties)
858 {
859   GladeWidget *gwidget;
860   GObject *ret_obj;
861   GList *properties = NULL, *list;
862 
863   ret_obj = G_OBJECT_CLASS (glade_widget_parent_class)->constructor
864       (type, n_construct_properties, construct_properties);
865 
866   gwidget = GLADE_WIDGET (ret_obj);
867 
868   if (gwidget->priv->name == NULL)
869     {
870       if (gwidget->priv->project)
871         gwidget->priv->name = glade_project_new_widget_name (gwidget->priv->project, gwidget, GLADE_UNNAMED_PREFIX);
872       else
873         gwidget->priv->name = g_strdup (GLADE_UNNAMED_PREFIX);
874     }
875 
876   if (gwidget->priv->construct_template)
877     {
878       properties = glade_widget_dup_properties
879           (gwidget, gwidget->priv->construct_template->priv->properties, FALSE, TRUE,
880            gwidget->priv->construct_exact);
881 
882       glade_widget_set_properties (gwidget, properties);
883     }
884 
885   if (gwidget->priv->object == NULL)
886     glade_widget_build_object (gwidget,
887                                gwidget->priv->construct_template,
888                                gwidget->priv->construct_reason);
889 
890   /* Copy sync parentless widget props here after a dup
891    */
892   if (gwidget->priv->construct_reason == GLADE_CREATE_COPY)
893     {
894       for (list = gwidget->priv->properties; list; list = list->next)
895         {
896           GladeProperty      *property = list->data;
897 	  GladePropertyClass *pclass = glade_property_get_class (property);
898 
899           if (glade_property_class_parentless_widget (pclass))
900             glade_property_sync (property);
901         }
902     }
903 
904   /* Setup width/height */
905   gwidget->priv->width = GWA_DEFAULT_WIDTH (gwidget->priv->adaptor);
906   gwidget->priv->height = GWA_DEFAULT_HEIGHT (gwidget->priv->adaptor);
907 
908   /* Introspect object properties before passing it to post_create,
909    * but only when its freshly created (depend on glade file at
910    * load time and copying properties at dup time).
911    */
912   if (gwidget->priv->construct_reason == GLADE_CREATE_USER)
913     for (list = gwidget->priv->properties; list; list = list->next)
914       glade_property_load (GLADE_PROPERTY (list->data));
915 
916   /* We only use catalog defaults when the widget was created by the user!
917    * and or is not an internal widget.
918    */
919   if (gwidget->priv->construct_reason == GLADE_CREATE_USER &&
920       gwidget->priv->internal == NULL)
921     glade_widget_set_catalog_defaults (gwidget->priv->properties);
922 
923   /* Only call this once the GladeWidget is completely built
924    * (but before calling custom handlers...)
925    */
926   glade_widget_adaptor_post_create (gwidget->priv->adaptor,
927                                     gwidget->priv->object, gwidget->priv->construct_reason);
928 
929   /* Virtual properties need to be explicitly synchronized.
930    */
931   if (gwidget->priv->construct_reason == GLADE_CREATE_USER)
932     glade_widget_sync_custom_props (gwidget);
933 
934   if (gwidget->priv->parent && gwidget->priv->packing_properties == NULL)
935     glade_widget_set_packing_properties (gwidget, gwidget->priv->parent);
936 
937   if (GTK_IS_WIDGET (gwidget->priv->object) &&
938       !gtk_widget_is_toplevel (GTK_WIDGET (gwidget->priv->object)))
939     {
940       gwidget->priv->visible = TRUE;
941       gtk_widget_show_all (GTK_WIDGET (gwidget->priv->object));
942     }
943   else if (GTK_IS_WIDGET (gwidget->priv->object) == FALSE)
944     gwidget->priv->visible = TRUE;
945 
946   /* Verify support warnings to start off */
947   glade_widget_verify (gwidget);
948 
949   return ret_obj;
950 }
951 
952 static void
glade_widget_finalize(GObject * object)953 glade_widget_finalize (GObject *object)
954 {
955   GladeWidget *widget = GLADE_WIDGET (object);
956 
957   g_return_if_fail (GLADE_IS_WIDGET (object));
958 
959   GLADE_NOTE (REF_COUNTS,
960 	      g_print ("Finalizing widget %s\n", widget->priv->name));
961 
962   g_free (widget->priv->name);
963   g_free (widget->priv->internal);
964   g_free (widget->priv->construct_internal);
965   g_free (widget->priv->support_warning);
966   g_hash_table_destroy (widget->priv->signals);
967 
968   if (widget->priv->props_hash)
969     g_hash_table_destroy (widget->priv->props_hash);
970   if (widget->priv->pack_props_hash)
971     g_hash_table_destroy (widget->priv->pack_props_hash);
972 
973   G_OBJECT_CLASS (glade_widget_parent_class)->finalize (object);
974 }
975 
976 static void
reset_object_property(GladeProperty * property,GladeProject * project)977 reset_object_property (GladeProperty *property, GladeProject *project)
978 {
979   GladePropertyClass *pclass = glade_property_get_class (property);
980 
981   if (glade_property_class_is_object (pclass))
982     glade_property_reset (property);
983 }
984 
985 static void
glade_widget_dispose(GObject * object)986 glade_widget_dispose (GObject *object)
987 {
988   GladeWidget *widget = GLADE_WIDGET (object);
989   GList *children, *l;
990 
991   glade_widget_push_superuser ();
992 
993   /* Remove all children at dispose */
994   children = glade_widget_get_children (widget);
995   for (l = children; l; l = l->next)
996     {
997       GladeWidget *child = glade_widget_get_from_gobject (l->data);
998 
999       if (glade_widget_get_internal (child) == NULL)
1000 	glade_widget_remove_child (widget, child);
1001     }
1002   g_list_free (children);
1003 
1004   /* Release references by way of object properties... */
1005   while (widget->priv->prop_refs)
1006     {
1007       GladeProperty *property = GLADE_PROPERTY (widget->priv->prop_refs->data);
1008       glade_property_set (property, NULL);
1009     }
1010 
1011   if (widget->priv->properties)
1012     g_list_foreach (widget->priv->properties, (GFunc) reset_object_property,
1013                     widget->priv->project);
1014 
1015   /* We have to make sure properties release thier references on other widgets first
1016    * hence the reset (for object properties) */
1017   if (widget->priv->properties)
1018     {
1019       g_list_foreach (widget->priv->properties, (GFunc) g_object_unref, NULL);
1020       g_list_free (widget->priv->properties);
1021       widget->priv->properties = NULL;
1022     }
1023   if (widget->priv->props_hash)
1024     {
1025       g_hash_table_destroy (widget->priv->props_hash);
1026       widget->priv->props_hash = NULL;
1027     }
1028 
1029   glade_widget_set_object (widget, NULL);
1030 
1031   if (widget->priv->packing_properties)
1032     {
1033       g_list_foreach (widget->priv->packing_properties, (GFunc) g_object_unref, NULL);
1034       g_list_free (widget->priv->packing_properties);
1035       widget->priv->packing_properties = NULL;
1036     }
1037 
1038   if (widget->priv->actions)
1039     {
1040       g_list_foreach (widget->priv->actions, (GFunc) g_object_unref, NULL);
1041       g_list_free (widget->priv->actions);
1042       widget->priv->actions = NULL;
1043     }
1044 
1045   if (widget->priv->packing_actions)
1046     {
1047       g_list_foreach (widget->priv->packing_actions, (GFunc) g_object_unref, NULL);
1048       g_list_free (widget->priv->packing_actions);
1049       widget->priv->packing_actions = NULL;
1050     }
1051 
1052   if (widget->priv->signal_model)
1053     {
1054       g_object_unref (widget->priv->signal_model);
1055       widget->priv->signal_model = NULL;
1056     }
1057 
1058   glade_widget_pop_superuser ();
1059 
1060   G_OBJECT_CLASS (glade_widget_parent_class)->dispose (object);
1061 }
1062 
1063 static void
glade_widget_set_real_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)1064 glade_widget_set_real_property (GObject      *object,
1065                                 guint         prop_id,
1066                                 const GValue *value,
1067                                 GParamSpec   *pspec)
1068 {
1069   GladeWidget *widget;
1070 
1071   widget = GLADE_WIDGET (object);
1072 
1073   switch (prop_id)
1074     {
1075       case PROP_NAME:
1076         glade_widget_set_name (widget, g_value_get_string (value));
1077         break;
1078       case PROP_INTERNAL:
1079         glade_widget_set_internal (widget, g_value_get_string (value));
1080         break;
1081       case PROP_ANARCHIST:
1082         widget->priv->anarchist = g_value_get_boolean (value);
1083         break;
1084       case PROP_OBJECT:
1085         if (g_value_get_object (value))
1086           glade_widget_set_object (widget, g_value_get_object (value));
1087         break;
1088       case PROP_PROJECT:
1089         glade_widget_set_project (widget,
1090                                   GLADE_PROJECT (g_value_get_object (value)));
1091         break;
1092       case PROP_ADAPTOR:
1093         glade_widget_set_adaptor (widget, GLADE_WIDGET_ADAPTOR
1094                                   (g_value_get_object (value)));
1095         break;
1096       case PROP_PROPERTIES:
1097         glade_widget_set_properties (widget,
1098                                      (GList *) g_value_get_pointer (value));
1099         break;
1100       case PROP_PARENT:
1101         glade_widget_set_parent (widget,
1102                                  GLADE_WIDGET (g_value_get_object (value)));
1103         break;
1104       case PROP_INTERNAL_NAME:
1105         if (g_value_get_string (value))
1106           widget->priv->construct_internal = g_value_dup_string (value);
1107         break;
1108       case PROP_TEMPLATE:
1109         widget->priv->construct_template = g_value_get_object (value);
1110         break;
1111       case PROP_TEMPLATE_EXACT:
1112         widget->priv->construct_exact = g_value_get_boolean (value);
1113         break;
1114       case PROP_REASON:
1115         widget->priv->construct_reason = g_value_get_int (value);
1116         break;
1117       case PROP_TOPLEVEL_WIDTH:
1118         widget->priv->width = g_value_get_int (value);
1119         break;
1120       case PROP_TOPLEVEL_HEIGHT:
1121         widget->priv->height = g_value_get_int (value);
1122         break;
1123     case PROP_COMPOSITE:
1124         glade_widget_set_is_composite (widget, g_value_get_boolean (value));
1125 	break;
1126       default:
1127         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1128         break;
1129     }
1130 }
1131 
1132 static void
glade_widget_get_real_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1133 glade_widget_get_real_property (GObject    *object,
1134                                 guint       prop_id,
1135                                 GValue     *value,
1136                                 GParamSpec *pspec)
1137 {
1138   GladeWidget *widget;
1139 
1140   widget = GLADE_WIDGET (object);
1141 
1142   switch (prop_id)
1143     {
1144       case PROP_NAME:
1145         g_value_set_string (value, widget->priv->name);
1146         break;
1147       case PROP_INTERNAL:
1148         g_value_set_string (value, widget->priv->internal);
1149         break;
1150       case PROP_ANARCHIST:
1151         g_value_set_boolean (value, widget->priv->anarchist);
1152         break;
1153       case PROP_ADAPTOR:
1154         g_value_set_object (value, widget->priv->adaptor);
1155         break;
1156       case PROP_PROJECT:
1157         g_value_set_object (value, G_OBJECT (widget->priv->project));
1158         break;
1159       case PROP_OBJECT:
1160         g_value_set_object (value, widget->priv->object);
1161         break;
1162       case PROP_PROPERTIES:
1163         g_value_set_pointer (value, widget->priv->properties);
1164         break;
1165       case PROP_PARENT:
1166         g_value_set_object (value, widget->priv->parent);
1167         break;
1168       case PROP_TOPLEVEL_WIDTH:
1169         g_value_set_int (value, widget->priv->width);
1170         break;
1171       case PROP_TOPLEVEL_HEIGHT:
1172         g_value_set_int (value, widget->priv->height);
1173         break;
1174       case PROP_SUPPORT_WARNING:
1175         g_value_set_string (value, widget->priv->support_warning);
1176         break;
1177       case PROP_VISIBLE:
1178         g_value_set_boolean (value, widget->priv->visible);
1179         break;
1180       case PROP_REASON:
1181         g_value_set_int (value, widget->priv->construct_reason);
1182         break;
1183       case PROP_COMPOSITE:
1184         g_value_set_boolean (value, glade_widget_get_is_composite (widget));
1185 	break;
1186       default:
1187         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1188         break;
1189     }
1190 }
1191 
1192 static void
free_signals(GPtrArray * signals)1193 free_signals (GPtrArray *signals)
1194 {
1195   g_assert (signals);
1196   g_ptr_array_free (signals, TRUE);
1197 }
1198 
1199 static void
glade_widget_init(GladeWidget * widget)1200 glade_widget_init (GladeWidget *widget)
1201 {
1202   widget->priv = glade_widget_get_instance_private (widget);
1203 
1204   widget->priv->adaptor = NULL;
1205   widget->priv->project = NULL;
1206   widget->priv->name = NULL;
1207   widget->priv->internal = NULL;
1208   widget->priv->object = NULL;
1209   widget->priv->properties = NULL;
1210   widget->priv->packing_properties = NULL;
1211   widget->priv->prop_refs = NULL;
1212   widget->priv->signals = g_hash_table_new_full
1213       (g_str_hash, g_str_equal,
1214        (GDestroyNotify) g_free, (GDestroyNotify) free_signals);
1215 
1216   /* Initial invalid values */
1217   widget->priv->width = -1;
1218   widget->priv->height = -1;
1219 }
1220 
1221 static gboolean
glade_widget_drag_can_drag(_GladeDrag * source)1222 glade_widget_drag_can_drag (_GladeDrag *source)
1223 {
1224   g_return_val_if_fail (GLADE_IS_DRAG (source), FALSE);
1225 
1226   return GLADE_WIDGET (source)->priv->internal == NULL;
1227 }
1228 
1229 static gboolean
glade_widget_drag_can_drop(_GladeDrag * dest,gint x,gint y,GObject * data)1230 glade_widget_drag_can_drop (_GladeDrag *dest, gint x, gint y, GObject *data)
1231 {
1232   GObject *object;
1233 
1234   g_return_val_if_fail (GLADE_IS_DRAG (dest), FALSE);
1235 
1236   object = GLADE_WIDGET (dest)->priv->object;
1237 
1238   if (!(GTK_IS_FIXED (object) ||
1239         GTK_IS_LAYOUT (object) ||
1240         GTK_IS_OVERLAY (object)))
1241     return FALSE;
1242 
1243   if (GLADE_IS_WIDGET_ADAPTOR (data))
1244     {
1245       GType otype = glade_widget_adaptor_get_object_type (GLADE_WIDGET_ADAPTOR (data));
1246 
1247       if (g_type_is_a (otype, GTK_TYPE_WIDGET) && !GWA_IS_TOPLEVEL (data))
1248         return TRUE;
1249     }
1250   else
1251     {
1252       GladeWidget *new_child, *parent = GLADE_WIDGET (dest);
1253       GObject *object = glade_widget_get_object (parent);
1254 
1255       if (object == data)
1256         return FALSE;
1257 
1258       if (GTK_IS_WIDGET (data) && GTK_IS_WIDGET (object) &&
1259           gtk_widget_is_ancestor (GTK_WIDGET (data), GTK_WIDGET (object)))
1260         return FALSE;
1261 
1262       if ((new_child = glade_widget_get_from_gobject (data)) &&
1263           (!glade_widget_add_verify (parent, new_child, FALSE) ||
1264            glade_widget_placeholder_relation (parent, new_child)))
1265         return FALSE;
1266 
1267       return TRUE;
1268     }
1269 
1270   return FALSE;
1271 }
1272 
1273 static gboolean
glade_widget_drag_drop(_GladeDrag * dest,gint x,gint y,GObject * data)1274 glade_widget_drag_drop (_GladeDrag *dest, gint x, gint y, GObject *data)
1275 {
1276   GladeWidget *gsource;
1277 
1278   g_return_val_if_fail (GLADE_IS_DRAG (dest), FALSE);
1279 
1280   if (!data)
1281     return FALSE;
1282 
1283   if (GLADE_IS_WIDGET_ADAPTOR (data))
1284     {
1285       GladeWidget *parent = GLADE_WIDGET (dest);
1286 
1287       glade_command_create (GLADE_WIDGET_ADAPTOR (data), parent, NULL,
1288                             glade_widget_get_project (parent));
1289       return TRUE;
1290     }
1291   else if ((gsource = glade_widget_get_from_gobject (data)))
1292     {
1293       GladeWidget *parent = GLADE_WIDGET (dest);
1294       GList widgets = {gsource, NULL, NULL};
1295 
1296       /* Check for recursive paste */
1297       if (parent != gsource)
1298         {
1299           glade_command_dnd (&widgets, parent, NULL);
1300           return TRUE;
1301         }
1302     }
1303 
1304   return FALSE;
1305 }
1306 
1307 static void
glade_widget_drag_init(_GladeDragInterface * iface)1308 glade_widget_drag_init (_GladeDragInterface *iface)
1309 {
1310   iface->can_drag = glade_widget_drag_can_drag;
1311   iface->can_drop = glade_widget_drag_can_drop;
1312   iface->drop = glade_widget_drag_drop;
1313 }
1314 
1315 static void
glade_widget_class_init(GladeWidgetClass * klass)1316 glade_widget_class_init (GladeWidgetClass *klass)
1317 {
1318   GObjectClass *object_class;
1319 
1320   if (glade_widget_name_quark == 0)
1321     glade_widget_name_quark = g_quark_from_static_string ("GladeWidgetDataTag");
1322 
1323   object_class = G_OBJECT_CLASS (klass);
1324 
1325   object_class->constructor = glade_widget_constructor;
1326   object_class->finalize = glade_widget_finalize;
1327   object_class->dispose = glade_widget_dispose;
1328   object_class->set_property = glade_widget_set_real_property;
1329   object_class->get_property = glade_widget_get_real_property;
1330 
1331   klass->add_child = glade_widget_add_child_impl;
1332   klass->remove_child = glade_widget_remove_child_impl;
1333   klass->replace_child = glade_widget_replace_child_impl;
1334   klass->event = glade_widget_event_impl;
1335 
1336   klass->button_press_event = glade_widget_button_press_event_impl;
1337   klass->button_release_event = NULL;
1338   klass->motion_notify_event = NULL;
1339 
1340   properties[PROP_NAME] =
1341        g_param_spec_string ("name", _("Name"),
1342                             _("The name of the widget"),
1343                             NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
1344 
1345   properties[PROP_INTERNAL] =
1346        g_param_spec_string ("internal", _("Internal name"),
1347                             _("The internal name of the widget"),
1348                             NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
1349 
1350   properties[PROP_ANARCHIST] =
1351        g_param_spec_boolean ("anarchist", _("Anarchist"),
1352                              _("Whether this composite child is "
1353                                "an ancestral child or an anarchist child"),
1354                              FALSE, G_PARAM_READWRITE |
1355                              G_PARAM_CONSTRUCT_ONLY);
1356 
1357   properties[PROP_OBJECT] =
1358        g_param_spec_object ("object", _("Object"),
1359                             _("The object associated"),
1360                             G_TYPE_OBJECT,
1361                             G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
1362 
1363   properties[PROP_ADAPTOR] =
1364        g_param_spec_object ("adaptor", _("Adaptor"),
1365                             _("The class adaptor for the associated widget"),
1366                             GLADE_TYPE_WIDGET_ADAPTOR,
1367                             G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
1368 
1369   properties[PROP_PROJECT] =
1370        g_param_spec_object ("project", _("Project"),
1371                             _("The glade project that "
1372                               "this widget belongs to"),
1373                             GLADE_TYPE_PROJECT,
1374                             G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
1375 
1376   properties[PROP_PROPERTIES] =
1377        g_param_spec_pointer ("properties", _("Properties"),
1378                              _("A list of GladeProperties"),
1379                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
1380 
1381   properties[PROP_PARENT] =
1382        g_param_spec_object ("parent", _("Parent"),
1383                             _("A pointer to the parenting GladeWidget"),
1384                             GLADE_TYPE_WIDGET,
1385                             G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
1386 
1387   properties[PROP_INTERNAL_NAME] =
1388        g_param_spec_string ("internal-name", _("Internal Name"),
1389                             _("A generic name prefix for internal widgets"),
1390                             NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE);
1391 
1392   properties[PROP_TEMPLATE] =
1393        g_param_spec_object ("template", _("Template"),
1394                             _("A GladeWidget template to base a new widget on"),
1395                             GLADE_TYPE_WIDGET,
1396                             G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE);
1397 
1398   properties[PROP_TEMPLATE_EXACT] =
1399        g_param_spec_boolean ("template-exact", _("Exact Template"),
1400                              _
1401                              ("Whether we are creating an exact duplicate when using a template"),
1402                              FALSE, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
1403 
1404   properties[PROP_REASON] =
1405        g_param_spec_int ("reason", _("Reason"),
1406                          _("A GladeCreateReason for this creation"),
1407                          GLADE_CREATE_USER,
1408                          GLADE_CREATE_REASONS - 1,
1409                          GLADE_CREATE_USER,
1410                          G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
1411 
1412   properties[PROP_TOPLEVEL_WIDTH] =
1413        g_param_spec_int ("toplevel-width", _("Toplevel Width"),
1414                          _("The width of the widget when toplevel in "
1415                            "the GladeDesignLayout"),
1416                          -1, G_MAXINT, -1, G_PARAM_READWRITE);
1417 
1418   properties[PROP_TOPLEVEL_HEIGHT] =
1419        g_param_spec_int ("toplevel-height", _("Toplevel Height"),
1420                          _("The height of the widget when toplevel in "
1421                            "the GladeDesignLayout"),
1422                          -1, G_MAXINT, -1, G_PARAM_READWRITE);
1423 
1424   properties[PROP_SUPPORT_WARNING] =
1425        g_param_spec_string ("support warning", _("Support Warning"),
1426                             _("A warning string about version mismatches"),
1427                             NULL, G_PARAM_READABLE);
1428 
1429   properties[PROP_VISIBLE] =
1430        g_param_spec_boolean ("visible", _("Visible"),
1431                             _("Wether the widget is visible or not"),
1432                              FALSE, G_PARAM_READABLE);
1433 
1434   properties[PROP_COMPOSITE] =
1435        g_param_spec_boolean ("composite", _("Composite"),
1436                             _("Whether this widget is the template for a composite widget"),
1437                             FALSE, G_PARAM_READWRITE);
1438 
1439   /* Install all properties */
1440   g_object_class_install_properties (object_class, N_PROPERTIES, properties);
1441 
1442   /**
1443    * GladeWidget::add-signal-handler:
1444    * @gladewidget: the #GladeWidget which received the signal.
1445    * @arg1: the #GladeSignal that was added to @gladewidget.
1446    */
1447   glade_widget_signals[ADD_SIGNAL_HANDLER] =
1448       g_signal_new ("add-signal-handler",
1449                     G_TYPE_FROM_CLASS (object_class),
1450                     G_SIGNAL_RUN_LAST,
1451                     G_STRUCT_OFFSET (GladeWidgetClass, add_signal_handler),
1452                     NULL, NULL,
1453                     g_cclosure_marshal_VOID__OBJECT,
1454                     G_TYPE_NONE, 1, GLADE_TYPE_SIGNAL);
1455 
1456   /**
1457    * GladeWidget::remove-signal-handler:
1458    * @gladewidget: the #GladeWidget which received the signal.
1459    * @arg1: the #GladeSignal that was removed from @gladewidget.
1460 	 */
1461   glade_widget_signals[REMOVE_SIGNAL_HANDLER] =
1462       g_signal_new ("remove-signal-handler",
1463                     G_TYPE_FROM_CLASS (object_class),
1464                     G_SIGNAL_RUN_LAST,
1465                     G_STRUCT_OFFSET (GladeWidgetClass, remove_signal_handler),
1466                      NULL, NULL,
1467                     g_cclosure_marshal_VOID__OBJECT,
1468                     G_TYPE_NONE, 1, GLADE_TYPE_SIGNAL);
1469 
1470   /**
1471    * GladeWidget::change-signal-handler:
1472    * @gladewidget: the #GladeWidget which received the signal.
1473    * @arg1: the old #GladeSignal
1474    * @arg2: the new #GladeSignal
1475    */
1476   glade_widget_signals[CHANGE_SIGNAL_HANDLER] =
1477       g_signal_new ("change-signal-handler",
1478                     G_TYPE_FROM_CLASS (object_class),
1479                     G_SIGNAL_RUN_LAST,
1480                     G_STRUCT_OFFSET (GladeWidgetClass, change_signal_handler),
1481                      NULL, NULL,
1482                     _glade_marshal_VOID__OBJECT,
1483                     G_TYPE_NONE, 1, GLADE_TYPE_SIGNAL);
1484 
1485   /**
1486    * GladeWidget::button-press-event:
1487    * @gladewidget: the #GladeWidget which received the signal.
1488    * @arg1: the #GdkEvent
1489    */
1490   glade_widget_signals[BUTTON_PRESS_EVENT] =
1491       g_signal_new ("button-press-event",
1492                     G_TYPE_FROM_CLASS (object_class),
1493                     G_SIGNAL_RUN_LAST,
1494                     G_STRUCT_OFFSET (GladeWidgetClass, button_press_event),
1495                     _glade_boolean_handled_accumulator, NULL,
1496                     _glade_marshal_BOOLEAN__BOXED,
1497                     G_TYPE_BOOLEAN, 1,
1498                     GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
1499 
1500   /**
1501    * GladeWidget::button-relese-event:
1502    * @gladewidget: the #GladeWidget which received the signal.
1503    * @arg1: the #GdkEvent
1504    */
1505   glade_widget_signals[BUTTON_RELEASE_EVENT] =
1506       g_signal_new ("button-release-event",
1507                     G_TYPE_FROM_CLASS (object_class),
1508                     G_SIGNAL_RUN_LAST,
1509                     G_STRUCT_OFFSET (GladeWidgetClass, button_release_event),
1510                     _glade_boolean_handled_accumulator, NULL,
1511                     _glade_marshal_BOOLEAN__BOXED,
1512                     G_TYPE_BOOLEAN, 1,
1513                     GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
1514 
1515 
1516   /**
1517    * GladeWidget::motion-notify-event:
1518    * @gladewidget: the #GladeWidget which received the signal.
1519    * @arg1: the #GdkEvent
1520    */
1521   glade_widget_signals[MOTION_NOTIFY_EVENT] =
1522       g_signal_new ("motion-notify-event",
1523                     G_TYPE_FROM_CLASS (object_class),
1524                     G_SIGNAL_RUN_LAST,
1525                     G_STRUCT_OFFSET (GladeWidgetClass, motion_notify_event),
1526                     _glade_boolean_handled_accumulator, NULL,
1527                     _glade_marshal_BOOLEAN__BOXED,
1528                     G_TYPE_BOOLEAN, 1,
1529                     GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
1530 
1531 
1532   /**
1533    * GladeWidget::support-changed:
1534    * @gladewidget: the #GladeWidget which received the signal.
1535    *
1536    * Emitted when property and signal support metadatas and messages
1537    * have been updated.
1538    */
1539   glade_widget_signals[SUPPORT_CHANGED] =
1540       g_signal_new ("support-changed",
1541                     G_TYPE_FROM_CLASS (object_class),
1542                     G_SIGNAL_RUN_LAST,
1543                     0, NULL, NULL,
1544                     g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
1545 }
1546 
1547 /*******************************************************************************
1548                                 Static stuff....
1549  *******************************************************************************/
1550 static void
glade_widget_copy_packing_props(GladeWidget * parent,GladeWidget * child,GladeWidget * template_widget)1551 glade_widget_copy_packing_props (GladeWidget *parent,
1552                                  GladeWidget *child,
1553                                  GladeWidget *template_widget)
1554 {
1555   GladeProperty *dup_prop, *orig_prop;
1556   GList *l;
1557 
1558   g_return_if_fail (child->priv->parent == parent);
1559 
1560   glade_widget_set_packing_properties (child, parent);
1561 
1562   for (l = child->priv->packing_properties; l && l->data; l = l->next)
1563     {
1564       GladePropertyClass *pclass;
1565 
1566       dup_prop  = GLADE_PROPERTY (l->data);
1567       pclass    = glade_property_get_class (dup_prop);
1568       orig_prop = glade_widget_get_pack_property (template_widget, glade_property_class_id (pclass));
1569 
1570       glade_property_set_value (dup_prop, glade_property_inline_value (orig_prop));
1571     }
1572 }
1573 
1574 static void
glade_widget_set_default_packing_properties(GladeWidget * container,GladeWidget * child)1575 glade_widget_set_default_packing_properties (GladeWidget *container,
1576                                              GladeWidget *child)
1577 {
1578   GladePropertyClass *property_class;
1579   const GList *l;
1580 
1581   for (l = glade_widget_adaptor_get_packing_props (container->priv->adaptor); l; l = l->next)
1582     {
1583       const gchar *def;
1584       GValue *value;
1585 
1586       property_class = l->data;
1587 
1588       if ((def =
1589            glade_widget_adaptor_get_packing_default
1590            (child->priv->adaptor, container->priv->adaptor,
1591 	    glade_property_class_id (property_class))) == NULL)
1592         continue;
1593 
1594       value = glade_property_class_make_gvalue_from_string (property_class,
1595                                                             def, child->priv->project);
1596 
1597       glade_widget_child_set_property (container, child,
1598                                        glade_property_class_id (property_class), value);
1599       g_value_unset (value);
1600       g_free (value);
1601     }
1602 }
1603 
1604 /**
1605  * When looking for an internal child we have to walk up the hierarchy...
1606  */
1607 static GObject *
glade_widget_get_internal_child(GladeWidget * main_target,GladeWidget * parent,const gchar * internal)1608 glade_widget_get_internal_child (GladeWidget *main_target,
1609 				 GladeWidget *parent,
1610 				 const gchar *internal)
1611 {
1612   while (parent)
1613     {
1614       if (glade_widget_adaptor_has_internal_children (parent->priv->adaptor))
1615         return glade_widget_adaptor_get_internal_child
1616             (parent->priv->adaptor, parent->priv->object, internal);
1617 
1618       /* Limit the itterations into where the copy routine stared */
1619       if (parent == main_target)
1620         break;
1621 
1622       parent = glade_widget_get_parent (parent);
1623     }
1624   return NULL;
1625 }
1626 
1627 static GladeWidget *
glade_widget_dup_internal(GladeWidget * main_target,GladeWidget * parent,GladeWidget * template_widget,gboolean exact)1628 glade_widget_dup_internal (GladeWidget *main_target,
1629                            GladeWidget *parent,
1630                            GladeWidget *template_widget,
1631                            gboolean     exact)
1632 {
1633   GladeWidget *gwidget = NULL;
1634   GList *children;
1635   GtkWidget *placeholder;
1636   gchar *child_type;
1637   GList *l;
1638 
1639   g_return_val_if_fail (GLADE_IS_WIDGET (template_widget), NULL);
1640   g_return_val_if_fail (parent == NULL || GLADE_IS_WIDGET (parent), NULL);
1641 
1642   /* Dont actually duplicate internal widgets, but recurse through them anyway. */
1643   if (parent && template_widget->priv->internal)
1644     {
1645       GObject *internal_object = NULL;
1646 
1647       if ((internal_object =
1648 	   glade_widget_get_internal_child (main_target,
1649 					    parent,
1650 					    template_widget->priv->internal)) != NULL)
1651 	{
1652 	  gwidget = glade_widget_get_from_gobject (internal_object);
1653 	  g_assert (gwidget);
1654         }
1655     }
1656 
1657   /* If either it was not internal, or we failed to lookup the internal child
1658    * in the copied hierarchy (this can happen when copying an internal vbox from
1659    * a composite dialog for instance). */
1660   if (gwidget == NULL)
1661     {
1662       gchar *name = g_strdup (template_widget->priv->name);
1663       gwidget = glade_widget_adaptor_create_widget
1664           (template_widget->priv->adaptor, FALSE,
1665            "name", name,
1666            "parent", parent,
1667            "project", template_widget->priv->project,
1668            "template", template_widget,
1669            "template-exact", exact, "reason", GLADE_CREATE_COPY, NULL);
1670       g_free (name);
1671     }
1672 
1673   /* Copy signals over here regardless of internal or not... */
1674   if (exact)
1675     glade_widget_copy_signals (gwidget, template_widget);
1676 
1677   if ((children =
1678        glade_widget_adaptor_get_children (template_widget->priv->adaptor,
1679                                           template_widget->priv->object)) != NULL)
1680     {
1681       GList *list;
1682 
1683       for (list = children; list && list->data; list = list->next)
1684         {
1685           GObject *child = G_OBJECT (list->data);
1686           GladeWidget *child_gwidget, *child_dup;
1687 
1688           child_type = g_object_get_data (child, "special-child-type");
1689 
1690           if ((child_gwidget = glade_widget_get_from_gobject (child)) == NULL)
1691             {
1692               /* Bring the placeholders along ...
1693                * but not unmarked internal children */
1694               if (GLADE_IS_PLACEHOLDER (child))
1695                 {
1696                   placeholder = glade_placeholder_new ();
1697 
1698                   g_object_set_data_full (G_OBJECT (placeholder),
1699                                           "special-child-type",
1700                                           g_strdup (child_type), g_free);
1701 
1702                   glade_widget_adaptor_add (gwidget->priv->adaptor,
1703                                             gwidget->priv->object,
1704                                             G_OBJECT (placeholder));
1705                 }
1706             }
1707           else
1708             {
1709               /* Recurse through every GladeWidget (internal or not) */
1710               child_dup =
1711                   glade_widget_dup_internal (main_target, gwidget,
1712                                              child_gwidget, exact);
1713 
1714               if (child_dup->priv->internal == NULL)
1715                 {
1716                   g_object_set_data_full (child_dup->priv->object,
1717                                           "special-child-type",
1718                                           g_strdup (child_type), g_free);
1719 
1720                   glade_widget_add_child (gwidget, child_dup, FALSE);
1721                 }
1722 
1723               /* Internal children that are not heirarchic children
1724                * need to avoid copying these packing props (like popup windows
1725                * created on behalf of composite widgets).
1726                */
1727               if (glade_widget_adaptor_has_child (gwidget->priv->adaptor,
1728                                                   gwidget->priv->object,
1729                                                   child_dup->priv->object))
1730                 glade_widget_copy_packing_props (gwidget, child_dup, child_gwidget);
1731 
1732             }
1733         }
1734       g_list_free (children);
1735     }
1736 
1737   if (gwidget->priv->internal)
1738     glade_widget_copy_properties (gwidget, template_widget, TRUE, exact);
1739 
1740   if (gwidget->priv->packing_properties == NULL)
1741     gwidget->priv->packing_properties =
1742         glade_widget_dup_properties (gwidget,
1743                                      template_widget->priv->packing_properties, FALSE,
1744                                      FALSE, FALSE);
1745 
1746   /* If custom properties are still at thier
1747    * default value, they need to be synced.
1748    */
1749   glade_widget_sync_custom_props (gwidget);
1750 
1751   /* Some properties may not be synced so we reload them */
1752   for (l = gwidget->priv->properties; l; l = l->next)
1753     glade_property_load (GLADE_PROPERTY (l->data));
1754 
1755   if (GWA_IS_TOPLEVEL (gwidget->priv->adaptor) && GTK_IS_WIDGET (gwidget->priv->object))
1756     g_object_set (gwidget,
1757                   "toplevel-width", template_widget->priv->width,
1758                   "toplevel-height", template_widget->priv->height, NULL);
1759   return gwidget;
1760 }
1761 
1762 
1763 typedef struct
1764 {
1765   GladeWidget *widget;
1766   GtkWidget *placeholder;
1767   GList *properties;
1768 
1769   gchar *internal_name;
1770   GList *internal_list;
1771 } GladeChildExtract;
1772 
1773 static GList *
glade_widget_extract_children(GladeWidget * gwidget)1774 glade_widget_extract_children (GladeWidget *gwidget)
1775 {
1776   GladeChildExtract *extract;
1777   GList *extract_list = NULL;
1778   GList *children, *list;
1779 
1780   children = glade_widget_adaptor_get_children
1781       (gwidget->priv->adaptor, gwidget->priv->object);
1782 
1783   for (list = children; list && list->data; list = list->next)
1784     {
1785       GObject *child = G_OBJECT (list->data);
1786       GladeWidget *gchild = glade_widget_get_from_gobject (child);
1787 
1788       if (gchild && gchild->priv->internal)
1789         {
1790           /* Recurse and collect any deep child hierarchies
1791            * inside composite widgets.
1792            */
1793           extract = g_new0 (GladeChildExtract, 1);
1794           extract->internal_name = g_strdup (gchild->priv->internal);
1795           extract->internal_list = glade_widget_extract_children (gchild);
1796           extract->properties =
1797               glade_widget_dup_properties (gchild, gchild->priv->properties, TRUE,
1798                                            FALSE, FALSE);
1799 
1800           extract_list = g_list_prepend (extract_list, extract);
1801 
1802         }
1803       else if (gchild || GLADE_IS_PLACEHOLDER (child))
1804         {
1805           extract = g_new0 (GladeChildExtract, 1);
1806 
1807           if (gchild)
1808             {
1809               extract->widget = g_object_ref (gchild);
1810 
1811               /* Make copies of the packing properties
1812                */
1813               extract->properties =
1814                   glade_widget_dup_properties
1815                   (gchild, gchild->priv->packing_properties, TRUE, FALSE, FALSE);
1816 
1817               glade_widget_remove_child (gwidget, gchild);
1818             }
1819           else
1820             {
1821               /* need to handle placeholders by hand here */
1822               extract->placeholder = g_object_ref (child);
1823               glade_widget_adaptor_remove (gwidget->priv->adaptor,
1824                                            gwidget->priv->object, child);
1825             }
1826           extract_list = g_list_prepend (extract_list, extract);
1827         }
1828     }
1829 
1830   if (children)
1831     g_list_free (children);
1832 
1833   return g_list_reverse (extract_list);
1834 }
1835 
1836 static void
glade_widget_insert_children(GladeWidget * gwidget,GList * children)1837 glade_widget_insert_children (GladeWidget *gwidget, GList *children)
1838 {
1839   GladeChildExtract *extract;
1840   GladeWidget *gchild;
1841   GObject *internal_object;
1842   GList *list, *l;
1843 
1844   for (list = children; list; list = list->next)
1845     {
1846       extract = list->data;
1847 
1848       if (extract->internal_name)
1849         {
1850 
1851           /* Recurse and add deep widget hierarchies to internal
1852            * widgets.
1853            */
1854           internal_object = glade_widget_get_internal_child (NULL,
1855 							     gwidget,
1856 							     extract->internal_name);
1857 
1858 	  /* Some internal children can disappear after a construct only
1859 	   * property has changed, eg. the "has-entry" property of
1860 	   * GtkComboBox decides whether there is an internal entry.
1861 	   *
1862 	   * Just ignore the saved information we have about missing internal
1863 	   * children.
1864 	   */
1865 	  if (!internal_object)
1866 	    {
1867 	      if (extract->properties)
1868 		g_list_free_full (extract->properties, (GDestroyNotify)g_object_unref);
1869 
1870 	      g_free (extract->internal_name);
1871 	      g_free (extract);
1872 	      continue;
1873 	    }
1874 
1875           gchild = glade_widget_get_from_gobject (internal_object);
1876 
1877           /* This will free the list... */
1878           glade_widget_insert_children (gchild, extract->internal_list);
1879 
1880           /* Set the properties after inserting the children */
1881           for (l = extract->properties; l; l = l->next)
1882             {
1883               GValue              value = { 0, };
1884               GladeProperty      *saved_prop = l->data;
1885 	      GladePropertyClass *pclass = glade_property_get_class (saved_prop);
1886               GladeProperty      *widget_prop =
1887 		glade_widget_get_property (gchild, glade_property_class_id (pclass));
1888 
1889               glade_property_get_value (saved_prop, &value);
1890               glade_property_set_value (widget_prop, &value);
1891               g_value_unset (&value);
1892 
1893               /* Free them as we go ... */
1894               g_object_unref (saved_prop);
1895             }
1896 
1897           if (extract->properties)
1898             g_list_free (extract->properties);
1899 
1900           g_free (extract->internal_name);
1901         }
1902       else if (extract->widget)
1903         {
1904           glade_widget_add_child (gwidget, extract->widget, FALSE);
1905           g_object_unref (extract->widget);
1906 
1907           for (l = extract->properties; l; l = l->next)
1908             {
1909               GValue              value = { 0, };
1910               GladeProperty      *saved_prop = l->data;
1911 	      GladePropertyClass *pclass = glade_property_get_class (saved_prop);
1912               GladeProperty      *widget_prop =
1913 		glade_widget_get_pack_property (extract->widget, glade_property_class_id (pclass));
1914 
1915               glade_property_get_value (saved_prop, &value);
1916               glade_property_set_value (widget_prop, &value);
1917               g_value_unset (&value);
1918 
1919               /* Free them as we go ... */
1920               g_object_unref (saved_prop);
1921             }
1922           if (extract->properties)
1923             g_list_free (extract->properties);
1924         }
1925       else
1926         {
1927           glade_widget_adaptor_add (gwidget->priv->adaptor,
1928                                     gwidget->priv->object,
1929                                     G_OBJECT (extract->placeholder));
1930           g_object_unref (extract->placeholder);
1931         }
1932       g_free (extract);
1933     }
1934 
1935   if (children)
1936     g_list_free (children);
1937 }
1938 
1939 static void
glade_widget_set_properties(GladeWidget * widget,GList * properties)1940 glade_widget_set_properties (GladeWidget *widget, GList *properties)
1941 {
1942   GladeProperty *property;
1943   GList *list;
1944 
1945   if (properties)
1946     {
1947       if (widget->priv->properties)
1948         {
1949           g_list_foreach (widget->priv->properties, (GFunc) g_object_unref, NULL);
1950           g_list_free (widget->priv->properties);
1951         }
1952       if (widget->priv->props_hash)
1953         g_hash_table_destroy (widget->priv->props_hash);
1954 
1955       widget->priv->properties = properties;
1956       widget->priv->props_hash = g_hash_table_new (g_str_hash, g_str_equal);
1957 
1958       for (list = properties; list; list = list->next)
1959         {
1960 	  GladePropertyClass *pclass;
1961 
1962           property = list->data;
1963 
1964 	  pclass = glade_property_get_class (property);
1965 	  glade_property_set_widget (property, widget);
1966 
1967           g_hash_table_insert (widget->priv->props_hash,
1968 			       (gchar *)glade_property_class_id (pclass),
1969 			       property);
1970         }
1971     }
1972 }
1973 
1974 static void
glade_widget_set_adaptor(GladeWidget * widget,GladeWidgetAdaptor * adaptor)1975 glade_widget_set_adaptor (GladeWidget *widget, GladeWidgetAdaptor *adaptor)
1976 {
1977   GladePropertyClass *property_class;
1978   GladeProperty      *property;
1979   const GList        *list;
1980   GList              *properties = NULL;
1981 
1982   g_return_if_fail (GLADE_IS_WIDGET (widget));
1983   g_return_if_fail (GLADE_IS_WIDGET_ADAPTOR (adaptor));
1984   /* calling set_class out of the constructor? */
1985   g_return_if_fail (widget->priv->adaptor == NULL);
1986 
1987   widget->priv->adaptor = adaptor;
1988 
1989   /* If we have no properties; we are not in the process of loading
1990    */
1991   if (!widget->priv->properties)
1992     {
1993       for (list = glade_widget_adaptor_get_properties (adaptor); list; list = list->next)
1994         {
1995           property_class = GLADE_PROPERTY_CLASS (list->data);
1996           if ((property = glade_property_new (property_class,
1997                                               widget, NULL)) == NULL)
1998             {
1999               g_warning ("Failed to create [%s] property",
2000 			 glade_property_class_id (property_class));
2001               continue;
2002             }
2003           properties = g_list_prepend (properties, property);
2004         }
2005       glade_widget_set_properties (widget, g_list_reverse (properties));
2006     }
2007 
2008   /* Create actions from adaptor */
2009   widget->priv->actions = glade_widget_adaptor_actions_new (adaptor);
2010 }
2011 
2012 /*
2013  * Returns a list of GladeProperties from a list for the correct
2014  * child type for this widget of this container.
2015  */
2016 static GList *
glade_widget_create_packing_properties(GladeWidget * container,GladeWidget * widget)2017 glade_widget_create_packing_properties (GladeWidget *container,
2018                                         GladeWidget *widget)
2019 {
2020   GladePropertyClass *property_class;
2021   GladeProperty      *property;
2022   const GList        *list;
2023   GList              *packing_props = NULL;
2024 
2025   /* XXX TODO: by checking with some GladePropertyClass metadata, decide
2026    * which packing properties go on which type of children.
2027    */
2028   for (list = glade_widget_adaptor_get_packing_props (container->priv->adaptor);
2029        list && list->data; list = list->next)
2030     {
2031       property_class = list->data;
2032       property = glade_property_new (property_class, widget, NULL);
2033       packing_props = g_list_prepend (packing_props, property);
2034 
2035     }
2036   return g_list_reverse (packing_props);
2037 }
2038 
2039 /* Private API */
2040 
2041 GList *
_glade_widget_peek_prop_refs(GladeWidget * widget)2042 _glade_widget_peek_prop_refs (GladeWidget *widget)
2043 {
2044   return widget->priv->prop_refs;
2045 }
2046 
2047 /*******************************************************************************
2048                                      API
2049  *******************************************************************************/
2050 GladeWidget *
glade_widget_get_from_gobject(gpointer object)2051 glade_widget_get_from_gobject (gpointer object)
2052 {
2053   g_return_val_if_fail (G_IS_OBJECT (object), NULL);
2054 
2055   return g_object_get_qdata (G_OBJECT (object), glade_widget_name_quark);
2056 }
2057 
2058 /**
2059  * glade_widget_show:
2060  * @widget: A #GladeWidget
2061  *
2062  * Display @widget in it's project's GladeDesignView
2063  */
2064 void
glade_widget_show(GladeWidget * widget)2065 glade_widget_show (GladeWidget *widget)
2066 {
2067   GladeProperty *property;
2068   GladeProject *project;
2069 
2070   g_return_if_fail (GLADE_IS_WIDGET (widget));
2071 
2072   /* Position window at saved coordinates or in the center */
2073   if (GTK_IS_WIDGET (widget->priv->object) && !widget->priv->parent)
2074     {
2075       /* Maybe a property references this widget internally, show that widget instead */
2076       if ((property = glade_widget_get_parentless_widget_ref (widget)) != NULL)
2077         {
2078           /* will never happen, paranoid check to avoid endless recursion. */
2079           if (glade_property_get_widget (property) != widget)
2080             glade_widget_show (glade_property_get_widget (property));
2081           return;
2082         }
2083     }
2084   else if (GTK_IS_WIDGET (widget->priv->object))
2085     {
2086       GladeWidget *toplevel = glade_widget_get_toplevel (widget);
2087       if (toplevel != widget)
2088         glade_widget_show (toplevel);
2089     }
2090 
2091   if (widget->priv->visible) return;
2092 
2093   widget->priv->visible = TRUE;
2094   if ((project = glade_widget_get_project (widget)))
2095     glade_project_widget_visibility_changed (project, widget, TRUE);
2096 }
2097 
2098 /**
2099  * glade_widget_hide:
2100  * @widget: A #GladeWidget
2101  *
2102  * Hide @widget
2103  */
2104 void
glade_widget_hide(GladeWidget * widget)2105 glade_widget_hide (GladeWidget *widget)
2106 {
2107   GladeProject *project;
2108 
2109   g_return_if_fail (GLADE_IS_WIDGET (widget));
2110 
2111   if (!widget->priv->visible) return;
2112 
2113   widget->priv->visible = FALSE;
2114   if ((project = glade_widget_get_project (widget)))
2115     glade_project_widget_visibility_changed (project, widget, FALSE);
2116 }
2117 
2118 /**
2119  * glade_widget_add_prop_ref:
2120  * @widget: A #GladeWidget
2121  * @property: the #GladeProperty
2122  *
2123  * Adds @property to @widget 's list of referenced properties.
2124  *
2125  * Note: this is used to track properties on other objects that
2126  *       reffer to this object.
2127  */
2128 void
glade_widget_add_prop_ref(GladeWidget * widget,GladeProperty * property)2129 glade_widget_add_prop_ref (GladeWidget *widget, GladeProperty *property)
2130 {
2131   GladePropertyClass *pclass;
2132 
2133   g_return_if_fail (GLADE_IS_WIDGET (widget));
2134   g_return_if_fail (GLADE_IS_PROPERTY (property));
2135 
2136   if (!g_list_find (widget->priv->prop_refs, property))
2137     widget->priv->prop_refs = g_list_prepend (widget->priv->prop_refs, property);
2138 
2139   /* parentless widget reffed widgets are added to thier reffering widgets.
2140    * they cant be in the design view.
2141    */
2142   pclass = glade_property_get_class (property);
2143   if (glade_property_class_parentless_widget (pclass))
2144     {
2145       GladeProject *project = glade_widget_get_project (widget);
2146 
2147       if (project)
2148 	glade_project_widget_changed (project, widget);
2149 
2150       glade_widget_hide (widget);
2151     }
2152 }
2153 
2154 /**
2155  * glade_widget_remove_prop_ref:
2156  * @widget: A #GladeWidget
2157  * @property: the #GladeProperty
2158  *
2159  * Removes @property from @widget 's list of referenced properties.
2160  *
2161  * Note: this is used to track properties on other objects that
2162  *       reffer to this object.
2163  */
2164 void
glade_widget_remove_prop_ref(GladeWidget * widget,GladeProperty * property)2165 glade_widget_remove_prop_ref (GladeWidget *widget, GladeProperty *property)
2166 {
2167   GladePropertyClass *pclass;
2168 
2169   g_return_if_fail (GLADE_IS_WIDGET (widget));
2170   g_return_if_fail (GLADE_IS_PROPERTY (property));
2171 
2172   widget->priv->prop_refs = g_list_remove (widget->priv->prop_refs, property);
2173 
2174   pclass = glade_property_get_class (property);
2175   if (glade_property_class_parentless_widget (pclass))
2176     {
2177       GladeProject *project = glade_widget_get_project (widget);
2178 
2179       if (project)
2180 	glade_project_widget_changed (project, widget);
2181     }
2182 }
2183 
2184 GList *
glade_widget_list_prop_refs(GladeWidget * widget)2185 glade_widget_list_prop_refs (GladeWidget *widget)
2186 {
2187   g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
2188 
2189   return g_list_copy (widget->priv->prop_refs);
2190 }
2191 
2192 gboolean
glade_widget_has_prop_refs(GladeWidget * widget)2193 glade_widget_has_prop_refs (GladeWidget *widget)
2194 {
2195   g_return_val_if_fail (GLADE_IS_WIDGET (widget), FALSE);
2196 
2197   return widget->priv->prop_refs != NULL;
2198 }
2199 
2200 GladeProperty *
glade_widget_get_parentless_widget_ref(GladeWidget * widget)2201 glade_widget_get_parentless_widget_ref (GladeWidget *widget)
2202 {
2203   GladePropertyClass *pclass;
2204   GladeProperty      *property;
2205   GList              *l;
2206 
2207   g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
2208 
2209   for (l = widget->priv->prop_refs; l && l->data; l = l->next)
2210     {
2211       property = l->data;
2212       pclass   = glade_property_get_class (property);
2213 
2214       if (glade_property_class_parentless_widget (pclass))
2215         /* only one external property can point to this widget */
2216         return property;
2217     }
2218   return NULL;
2219 }
2220 
2221 
2222 GList *
glade_widget_get_parentless_reffed_widgets(GladeWidget * widget)2223 glade_widget_get_parentless_reffed_widgets (GladeWidget *widget)
2224 {
2225   GladeProperty      *property = NULL;
2226   GladePropertyClass *pclass;
2227   GObject            *reffed = NULL;
2228   GList              *l, *widgets = NULL;
2229 
2230   g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
2231 
2232   for (l = widget->priv->properties; l && l->data; l = l->next)
2233     {
2234       property = l->data;
2235       pclass   = glade_property_get_class (property);
2236       reffed = NULL;
2237 
2238       if (glade_property_class_parentless_widget (pclass))
2239         {
2240           glade_property_get (property, &reffed);
2241           if (reffed)
2242             widgets =
2243                 g_list_prepend (widgets,
2244                                 glade_widget_get_from_gobject (reffed));
2245         }
2246     }
2247   return g_list_reverse (widgets);
2248 }
2249 
2250 static void
glade_widget_accum_signal_foreach(const gchar * key,GPtrArray * signals,GList ** list)2251 glade_widget_accum_signal_foreach (const gchar *key,
2252                                    GPtrArray   *signals,
2253                                    GList      **list)
2254 {
2255   GladeSignal *signal;
2256   gint i;
2257 
2258   for (i = 0; i < signals->len; i++)
2259     {
2260       signal = (GladeSignal *) signals->pdata[i];
2261       *list = g_list_append (*list, signal);
2262     }
2263 }
2264 
2265 /**
2266  * glade_widget_get_signal_list:
2267  * @widget:   a 'dest' #GladeWidget
2268  *
2269  * Compiles a list of #GladeSignal elements
2270  *
2271  * Returns: a newly allocated #GList of #GladeSignals, the caller
2272  * must call g_list_free() to free the list.
2273  */
2274 GList *
glade_widget_get_signal_list(GladeWidget * widget)2275 glade_widget_get_signal_list (GladeWidget *widget)
2276 {
2277   GList *signals = NULL;
2278 
2279   g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
2280 
2281   g_hash_table_foreach (widget->priv->signals,
2282                         (GHFunc) glade_widget_accum_signal_foreach, &signals);
2283 
2284   return signals;
2285 }
2286 
2287 static void
glade_widget_copy_signal_foreach(const gchar * key,GPtrArray * signals,GladeWidget * dest)2288 glade_widget_copy_signal_foreach (const gchar *key,
2289                                   GPtrArray   *signals,
2290                                   GladeWidget *dest)
2291 {
2292   GladeSignal *signal;
2293   gint i;
2294 
2295   for (i = 0; i < signals->len; i++)
2296     {
2297       signal = (GladeSignal *) signals->pdata[i];
2298       glade_widget_add_signal_handler (dest, signal);
2299     }
2300 }
2301 
2302 /**
2303  * glade_widget_copy_signals:
2304  * @widget:   a 'dest' #GladeWidget
2305  * @template_widget: a 'src' #GladeWidget
2306  *
2307  * Sets signals in @widget based on the values of
2308  * matching signals in @template_widget
2309  */
2310 void
glade_widget_copy_signals(GladeWidget * widget,GladeWidget * template_widget)2311 glade_widget_copy_signals (GladeWidget *widget, GladeWidget *template_widget)
2312 {
2313   g_return_if_fail (GLADE_IS_WIDGET (widget));
2314   g_return_if_fail (GLADE_IS_WIDGET (template_widget));
2315 
2316   g_hash_table_foreach (template_widget->priv->signals,
2317                         (GHFunc) glade_widget_copy_signal_foreach, widget);
2318 }
2319 
2320 /**
2321  * glade_widget_copy_properties:
2322  * @widget:   a 'dest' #GladeWidget
2323  * @template_widget: a 'src' #GladeWidget
2324  * @copy_parentless: whether to copy reffed widgets at all
2325  * @exact: whether to copy reffed widgets exactly
2326  *
2327  * Sets properties in @widget based on the values of
2328  * matching properties in @template_widget
2329  */
2330 void
glade_widget_copy_properties(GladeWidget * widget,GladeWidget * template_widget,gboolean copy_parentless,gboolean exact)2331 glade_widget_copy_properties (GladeWidget *widget,
2332                               GladeWidget *template_widget,
2333                               gboolean     copy_parentless,
2334                               gboolean     exact)
2335 {
2336   GList *l;
2337 
2338   g_return_if_fail (GLADE_IS_WIDGET (widget));
2339   g_return_if_fail (GLADE_IS_WIDGET (template_widget));
2340 
2341   for (l = widget->priv->properties; l && l->data; l = l->next)
2342     {
2343       GladeProperty *widget_prop = GLADE_PROPERTY (l->data);
2344       GladeProperty *template_prop;
2345       GladePropertyClass *widget_pclass, *template_pclass = NULL;
2346 
2347       widget_pclass = glade_property_get_class (widget_prop);
2348       template_prop = glade_widget_get_property (template_widget,
2349 						 glade_property_class_id (widget_pclass));
2350       if (template_prop)
2351 	template_pclass = glade_property_get_class (template_prop);
2352 
2353       /* Check if they share the same class definition, different
2354        * properties may have the same name (support for
2355        * copying properties across "not-quite" compatible widget
2356        * classes, like GtkImageMenuItem --> GtkCheckMenuItem).
2357        */
2358       if (template_pclass != NULL &&
2359           glade_property_class_match (template_pclass, widget_pclass))
2360         {
2361           if (glade_property_class_parentless_widget (template_pclass) && copy_parentless)
2362             {
2363               GObject *object = NULL;
2364               GladeWidget *parentless;
2365 
2366               glade_property_get (template_prop, &object);
2367               if (object)
2368                 {
2369                   parentless = glade_widget_get_from_gobject (object);
2370                   parentless = glade_widget_dup (parentless, exact);
2371 
2372                   glade_widget_set_project (parentless, widget->priv->project);
2373 
2374                   glade_property_set (widget_prop, parentless->priv->object);
2375                 }
2376               else
2377                 glade_property_set (widget_prop, NULL);
2378             }
2379           else
2380             glade_property_set_value (widget_prop, glade_property_inline_value (template_prop));
2381         }
2382     }
2383 }
2384 
2385 
2386 /**
2387  * glade_widget_add_verify:
2388  * @widget: A #GladeWidget
2389  * @child: The child #GladeWidget to add
2390  * @user_feedback: whether a notification dialog should be
2391  * presented in the case that the child cannot not be added.
2392  *
2393  * Checks whether @child can be added to @parent.
2394  *
2395  * If @user_feedback is %TRUE and @child cannot be
2396  * added then this shows a notification dialog to the user
2397  * explaining why.
2398  *
2399  * Returns: whether @child can be added to @widget.
2400  */
2401 gboolean
glade_widget_add_verify(GladeWidget * widget,GladeWidget * child,gboolean user_feedback)2402 glade_widget_add_verify (GladeWidget *widget,
2403 			 GladeWidget *child,
2404 			 gboolean     user_feedback)
2405 {
2406   g_return_val_if_fail (GLADE_IS_WIDGET (widget), FALSE);
2407   g_return_val_if_fail (GLADE_IS_WIDGET (child), FALSE);
2408 
2409   return glade_widget_adaptor_add_verify (widget->priv->adaptor,
2410 					  widget->priv->object,
2411 					  child->priv->object,
2412 					  user_feedback);
2413 }
2414 
2415 /**
2416  * glade_widget_add_child:
2417  * @parent: A #GladeWidget
2418  * @child: the #GladeWidget to add
2419  * @at_mouse: whether the added widget should be added
2420  *            at the current mouse position
2421  *
2422  * Adds @child to @parent in a generic way for this #GladeWidget parent.
2423  */
2424 void
glade_widget_add_child(GladeWidget * parent,GladeWidget * child,gboolean at_mouse)2425 glade_widget_add_child (GladeWidget *parent,
2426                         GladeWidget *child,
2427                         gboolean     at_mouse)
2428 {
2429   g_return_if_fail (GLADE_IS_WIDGET (parent));
2430   g_return_if_fail (GLADE_IS_WIDGET (child));
2431 
2432   GLADE_WIDGET_GET_CLASS (parent)->add_child (parent, child, at_mouse);
2433 }
2434 
2435 /**
2436  * glade_widget_remove_child:
2437  * @parent: A #GladeWidget
2438  * @child: the #GladeWidget to add
2439  *
2440  * Removes @child from @parent in a generic way for this #GladeWidget parent.
2441  */
2442 void
glade_widget_remove_child(GladeWidget * parent,GladeWidget * child)2443 glade_widget_remove_child (GladeWidget *parent, GladeWidget *child)
2444 {
2445   g_return_if_fail (GLADE_IS_WIDGET (parent));
2446   g_return_if_fail (GLADE_IS_WIDGET (child));
2447 
2448   GLADE_WIDGET_GET_CLASS (parent)->remove_child (parent, child);
2449 }
2450 
2451 /**
2452  * glade_widget_dup:
2453  * @template_widget: a #GladeWidget
2454  * @exact: whether or not to creat an exact duplicate
2455  *
2456  * Creates a deep copy of #GladeWidget. if @exact is specified,
2457  * the widget name is preserved and signals are carried over
2458  * (this is used to maintain names & signals in Cut/Paste context
2459  * as opposed to Copy/Paste contexts).
2460  *
2461  * Returns: The newly created #GladeWidget
2462  */
2463 GladeWidget *
glade_widget_dup(GladeWidget * template_widget,gboolean exact)2464 glade_widget_dup (GladeWidget *template_widget, gboolean exact)
2465 {
2466   GladeWidget *widget;
2467 
2468   g_return_val_if_fail (GLADE_IS_WIDGET (template_widget), NULL);
2469 
2470   glade_widget_push_superuser ();
2471   widget =
2472       glade_widget_dup_internal (template_widget, NULL, template_widget, exact);
2473   glade_widget_pop_superuser ();
2474 
2475   return widget;
2476 }
2477 
2478 typedef struct
2479 {
2480   GladeProperty *property;
2481   GValue value;
2482 } PropertyData;
2483 
2484 /**
2485  * glade_widget_rebuild:
2486  * @gwidget: a #GladeWidget
2487  *
2488  * Replaces the current widget instance with
2489  * a new one while preserving all properties children and
2490  * takes care of reparenting.
2491  *
2492  */
2493 void
glade_widget_rebuild(GladeWidget * gwidget)2494 glade_widget_rebuild (GladeWidget *gwidget)
2495 {
2496   GObject *new_object, *old_object;
2497   GladeWidgetAdaptor *adaptor;
2498   GladeProject *project = NULL;
2499   GladeWidget  *parent = NULL;
2500   GList *children;
2501   GList *selection = NULL;
2502   GList *restore_properties = NULL;
2503   GList *save_properties, *l;
2504 
2505   g_return_if_fail (GLADE_IS_WIDGET (gwidget));
2506 
2507   /* Mark the widget as currently rebuilding,
2508    *
2509    * We avoid rewriting and losing packing properties when
2510    * reparenting in the process of rebuilding a widget instance
2511    */
2512   gwidget->priv->rebuilding = TRUE;
2513   glade_widget_push_superuser ();
2514 
2515   adaptor = gwidget->priv->adaptor;
2516 
2517   if (gwidget->priv->parent &&
2518       glade_widget_adaptor_has_child (gwidget->priv->parent->priv->adaptor,
2519 				      gwidget->priv->parent->priv->object,
2520 				      gwidget->priv->object))
2521     parent = gwidget->priv->parent;
2522 
2523   g_object_ref (gwidget);
2524 
2525   /* Extract and keep the child hierarchies aside... */
2526   children = glade_widget_extract_children (gwidget);
2527 
2528   /* Here we take care removing the widget from the project and
2529    * the selection before rebuilding the instance.
2530    */
2531   if (gwidget->priv->project && glade_project_has_object (gwidget->priv->project,
2532                                                           gwidget->priv->object))
2533     {
2534       project = gwidget->priv->project;
2535 
2536       if (glade_project_is_selected (project, gwidget->priv->object))
2537         selection = g_list_copy (glade_project_selection_get (project));
2538 
2539       glade_project_remove_object (project, gwidget->priv->object);
2540     }
2541 
2542   /* parentless_widget and object properties that reffer to this widget
2543    * should be unset before transfering */
2544   l = g_list_copy (gwidget->priv->properties);
2545   save_properties = g_list_copy (gwidget->priv->prop_refs);
2546   save_properties = g_list_concat (l, save_properties);
2547 
2548   for (l = save_properties; l; l = l->next)
2549     {
2550       GladeProperty      *property = l->data;
2551       GladePropertyClass *pclass = glade_property_get_class (property);
2552 
2553       if (glade_property_get_widget (property) != gwidget ||
2554 	  glade_property_class_parentless_widget (pclass))
2555         {
2556           PropertyData *prop_data;
2557 
2558           if (!G_IS_PARAM_SPEC_OBJECT (glade_property_class_get_pspec (pclass)))
2559             g_warning ("Parentless widget property should be of object type");
2560 
2561           prop_data = g_new0 (PropertyData, 1);
2562           prop_data->property = property;
2563 
2564           if (glade_property_get_widget (property) == gwidget)
2565 	    glade_property_get_value (property, &prop_data->value);
2566 
2567           restore_properties = g_list_prepend (restore_properties, prop_data);
2568           glade_property_set (property, NULL);
2569         }
2570     }
2571   g_list_free (save_properties);
2572 
2573   /* Remove old object from parent
2574    */
2575   if (parent)
2576     glade_widget_remove_child (parent, gwidget);
2577 
2578   /* Hold a reference to the old widget while we transport properties
2579    * and children from it
2580    */
2581   old_object = g_object_ref (glade_widget_get_object (gwidget));
2582   new_object = glade_widget_build_object (gwidget, gwidget, GLADE_CREATE_REBUILD);
2583 
2584   /* Only call this once the object has a proper GladeWidget */
2585   glade_widget_adaptor_post_create (adaptor, new_object, GLADE_CREATE_REBUILD);
2586 
2587   /* Reparent any children of the old object to the new object
2588    * (this function will consume and free the child list).
2589    */
2590   glade_widget_insert_children (gwidget, children);
2591 
2592   /* Add new object to parent
2593    */
2594   if (parent)
2595     glade_widget_add_child (parent, gwidget, FALSE);
2596 
2597   /* Custom properties aren't transfered in build_object, since build_object
2598    * is only concerned with object creation.
2599    */
2600   glade_widget_sync_custom_props (gwidget);
2601 
2602   /* Setting parentless_widget and prop_ref properties back */
2603   for (l = restore_properties; l; l = l->next)
2604     {
2605       PropertyData *prop_data = l->data;
2606       GladeProperty *property = prop_data->property;
2607 
2608       if (glade_property_get_widget (property) == gwidget)
2609         {
2610           glade_property_set_value (property, &prop_data->value);
2611           g_value_unset (&prop_data->value);
2612         }
2613       else
2614         {
2615           /* restore property references on rebuilt objects */
2616           glade_property_set (property, gwidget->priv->object);
2617         }
2618       g_free (prop_data);
2619     }
2620   g_list_free (restore_properties);
2621 
2622   /* Sync packing.
2623    */
2624   if (parent)
2625     glade_widget_sync_packing_props (gwidget);
2626 
2627   /* If the widget was in a project (and maybe the selection), then
2628    * restore that stuff.
2629    */
2630   if (project)
2631     {
2632       glade_project_add_object (project, gwidget->priv->object);
2633 
2634       if (selection)
2635         {
2636           glade_project_selection_clear (project, FALSE);
2637 
2638           for (l = selection; l; l = g_list_next (l))
2639             {
2640               GObject *selected = l->data;
2641 
2642               if (selected == old_object)
2643                 glade_project_selection_add (project, gwidget->priv->object, TRUE);
2644               else
2645                 glade_project_selection_add (project, selected, TRUE);
2646             }
2647 
2648           g_list_free (selection);
2649         }
2650     }
2651 
2652   /* Must call dispose for cases like dialogs and toplevels */
2653   if (GTK_IS_WINDOW (old_object))
2654     gtk_widget_destroy (GTK_WIDGET (old_object));
2655   else
2656     g_object_unref (old_object);
2657 
2658   /* Ensure rebuilt widget visibility */
2659   if (GTK_IS_WIDGET (gwidget->priv->object) &&
2660       !GTK_IS_WINDOW (gwidget->priv->object))
2661     gtk_widget_show_all (GTK_WIDGET (gwidget->priv->object));
2662 
2663   /* We shouldnt show if its not already visible */
2664   if (gwidget->priv->visible)
2665     glade_widget_show (gwidget);
2666 
2667   g_object_unref (gwidget);
2668 
2669   gwidget->priv->rebuilding = FALSE;
2670   glade_widget_pop_superuser ();
2671 }
2672 
2673 /**
2674  * glade_widget_list_signal_handlers:
2675  * @widget: a #GladeWidget
2676  * @signal_name: the name of the signal
2677  *
2678  * Returns: A #GPtrArray of #GladeSignal for @signal_name
2679  */
2680 GPtrArray *
glade_widget_list_signal_handlers(GladeWidget * widget,const gchar * signal_name)2681 glade_widget_list_signal_handlers (GladeWidget *widget, const gchar *signal_name)     /* array of GladeSignal* */
2682 {
2683   g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
2684   return g_hash_table_lookup (widget->priv->signals, signal_name);
2685 }
2686 
2687 /**
2688  * glade_widget_set_name:
2689  * @widget: a #GladeWidget
2690  * @name: a string
2691  *
2692  * Sets @widget's name to @name.
2693  */
2694 void
glade_widget_set_name(GladeWidget * widget,const gchar * name)2695 glade_widget_set_name (GladeWidget *widget, const gchar *name)
2696 {
2697   g_return_if_fail (GLADE_IS_WIDGET (widget));
2698   if (widget->priv->name != name)
2699     {
2700       if (widget->priv->name)
2701         g_free (widget->priv->name);
2702 
2703       widget->priv->name = g_strdup (name);
2704       g_object_notify_by_pspec (G_OBJECT (widget), properties[PROP_NAME]);
2705     }
2706 }
2707 
2708 /**
2709  * glade_widget_get_name:
2710  * @widget: a #GladeWidget
2711  *
2712  * Returns: a pointer to @widget's name
2713  *
2714  * This is what will be serialized as the widget's ID, unless
2715  * the name currently carries the %GLADE_UNNAMED_PREFIX.
2716  */
2717 const gchar *
glade_widget_get_name(GladeWidget * widget)2718 glade_widget_get_name (GladeWidget *widget)
2719 {
2720   g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
2721   return widget->priv->name;
2722 }
2723 
2724 
2725 /**
2726  * glade_widget_get_display_name:
2727  * @widget: a #GladeWidget
2728  *
2729  * Returns: a pointer to @widget's displayable name
2730  *
2731  * This should be used to display the widget's ID in
2732  * the UI, it will automatically return an "(unnamed)"
2733  * string if the widget is not intended to be serialized
2734  * with an ID (i.e. the user did not provide a name).
2735  */
2736 G_CONST_RETURN gchar *
glade_widget_get_display_name(GladeWidget * widget)2737 glade_widget_get_display_name (GladeWidget *widget)
2738 {
2739   g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
2740 
2741   if (g_str_has_prefix (widget->priv->name, GLADE_UNNAMED_PREFIX))
2742     return _("(unnamed)");
2743 
2744   return widget->priv->name;
2745 }
2746 
2747 /**
2748  * glade_widget_has_name:
2749  * @widget: a #GladeWidget
2750  *
2751  * Returns: whether the user has named this widget with an ID
2752  */
2753 gboolean
glade_widget_has_name(GladeWidget * widget)2754 glade_widget_has_name (GladeWidget *widget)
2755 {
2756   g_return_val_if_fail (GLADE_IS_WIDGET (widget), FALSE);
2757 
2758   return !g_str_has_prefix (widget->priv->name, GLADE_UNNAMED_PREFIX);
2759 }
2760 
2761 /**
2762  * glade_widget_set_is_composite:
2763  * @widget: a #GladeWidget
2764  * @composite: whether @widget should be a composite template
2765  *
2766  * Set's this widget to be toplevel composite object to be
2767  * eventually used with gtk_widget_class_set_template()
2768  *
2769  * Only one widget in a project should be composite.
2770  */
2771 void
glade_widget_set_is_composite(GladeWidget * widget,gboolean composite)2772 glade_widget_set_is_composite (GladeWidget *widget, gboolean composite)
2773 {
2774   g_return_if_fail (GLADE_IS_WIDGET (widget));
2775 
2776   composite = !!composite;
2777 
2778   if (widget->priv->composite != composite)
2779     {
2780       GladeProject *project = glade_widget_get_project (widget);
2781 
2782       widget->priv->composite = composite;
2783 
2784       g_object_notify_by_pspec (G_OBJECT (widget), properties[PROP_COMPOSITE]);
2785 
2786       /* Update the project model when this changes */
2787       if (widget->priv->parent == NULL &&
2788 	  widget->priv->project != NULL &&
2789 	  glade_project_has_object (widget->priv->project, widget->priv->object))
2790 	glade_project_widget_changed (project, widget);
2791     }
2792 }
2793 
2794 /**
2795  * glade_widget_get_is_composite:
2796  * @widget: a #GladeWidget
2797  *
2798  * Checks if @widget is a composite template to be used
2799  * with gtk_widget_class_set_template().
2800  *
2801  * Returns: whether @widget is composite.
2802  */
2803 gboolean
glade_widget_get_is_composite(GladeWidget * widget)2804 glade_widget_get_is_composite (GladeWidget *widget)
2805 {
2806   g_return_val_if_fail (GLADE_IS_WIDGET (widget), FALSE);
2807 
2808   return widget->priv->composite;
2809 }
2810 
2811 /**
2812  * glade_widget_set_internal:
2813  * @widget: A #GladeWidget
2814  * @internal: The internal name
2815  *
2816  * Sets the internal name of @widget to @internal
2817  */
2818 void
glade_widget_set_internal(GladeWidget * widget,const gchar * internal)2819 glade_widget_set_internal (GladeWidget *widget, const gchar *internal)
2820 {
2821   g_return_if_fail (GLADE_IS_WIDGET (widget));
2822   if (widget->priv->internal != internal)
2823     {
2824       g_free (widget->priv->internal);
2825       widget->priv->internal = g_strdup (internal);
2826       g_object_notify_by_pspec (G_OBJECT (widget), properties[PROP_INTERNAL]);
2827     }
2828 }
2829 
2830 /**
2831  * glade_widget_get_internal:
2832  * @widget: a #GladeWidget
2833  *
2834  * Returns: the internal name of @widget
2835  */
2836 G_CONST_RETURN gchar *
glade_widget_get_internal(GladeWidget * widget)2837 glade_widget_get_internal (GladeWidget *widget)
2838 {
2839   g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
2840   return widget->priv->internal;
2841 }
2842 
2843 /**
2844  * glade_widget_get_adaptor:
2845  * @widget: a #GladeWidget
2846  *
2847  * Returns: the #GladeWidgetAdaptor of @widget
2848  */
2849 GladeWidgetAdaptor *
glade_widget_get_adaptor(GladeWidget * widget)2850 glade_widget_get_adaptor (GladeWidget *widget)
2851 {
2852   g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
2853   return widget->priv->adaptor;
2854 }
2855 
2856 /**
2857  * glade_widget_set_project:
2858  * @widget: a #GladeWidget
2859  * @project: a #GladeProject
2860  *
2861  * Makes @widget belong to @project.
2862  */
2863 void
glade_widget_set_project(GladeWidget * widget,GladeProject * project)2864 glade_widget_set_project (GladeWidget *widget, GladeProject *project)
2865 {
2866   if (widget->priv->project != project)
2867     {
2868       widget->priv->project = project;
2869       g_object_notify_by_pspec (G_OBJECT (widget), properties[PROP_PROJECT]);
2870     }
2871 }
2872 
2873 /**
2874  * glade_widget_get_project:
2875  * @widget: a #GladeWidget
2876  *
2877  * Returns: the #GladeProject that @widget belongs to
2878  */
2879 GladeProject *
glade_widget_get_project(GladeWidget * widget)2880 glade_widget_get_project (GladeWidget *widget)
2881 {
2882   g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
2883   return widget->priv->project;
2884 }
2885 
2886 void
glade_widget_set_in_project(GladeWidget * widget,gboolean in_project)2887 glade_widget_set_in_project (GladeWidget *widget, gboolean in_project)
2888 {
2889   g_return_if_fail (GLADE_IS_WIDGET (widget));
2890 
2891   widget->priv->in_project = in_project;
2892 }
2893 
2894 gboolean
glade_widget_in_project(GladeWidget * widget)2895 glade_widget_in_project (GladeWidget *widget)
2896 {
2897   g_return_val_if_fail (GLADE_IS_WIDGET (widget), FALSE);
2898 
2899   return widget->priv->in_project;
2900 }
2901 
2902 /**
2903  * glade_widget_get_property:
2904  * @widget: a #GladeWidget
2905  * @id_property: a string naming a #GladeProperty
2906  *
2907  * Returns: the #GladeProperty in @widget named @id_property
2908  */
2909 GladeProperty *
glade_widget_get_property(GladeWidget * widget,const gchar * id_property)2910 glade_widget_get_property (GladeWidget *widget, const gchar *id_property)
2911 {
2912   GladeProperty *property;
2913 
2914   g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
2915   g_return_val_if_fail (id_property != NULL, NULL);
2916 
2917   if (widget->priv->props_hash &&
2918       (property = g_hash_table_lookup (widget->priv->props_hash, id_property)))
2919     return property;
2920 
2921   return glade_widget_get_pack_property (widget, id_property);
2922 }
2923 
2924 /**
2925  * glade_widget_get_pack_property:
2926  * @widget: a #GladeWidget
2927  * @id_property: a string naming a #GladeProperty
2928  *
2929  * Returns: the #GladeProperty in @widget named @id_property
2930  */
2931 GladeProperty *
glade_widget_get_pack_property(GladeWidget * widget,const gchar * id_property)2932 glade_widget_get_pack_property (GladeWidget *widget, const gchar *id_property)
2933 {
2934   GladeProperty *property;
2935 
2936   g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
2937   g_return_val_if_fail (id_property != NULL, NULL);
2938 
2939   if (widget->priv->pack_props_hash &&
2940       (property = g_hash_table_lookup (widget->priv->pack_props_hash, id_property)))
2941     return property;
2942 
2943   return NULL;
2944 }
2945 
2946 
2947 /**
2948  * glade_widget_property_get:
2949  * @widget: a #GladeWidget
2950  * @id_property: a string naming a #GladeProperty
2951  * @...: The return location for the value of the said #GladeProperty
2952  *
2953  * Gets the value of @id_property in @widget
2954  *
2955  * Returns: whether @id_property was found or not.
2956  *
2957  */
2958 gboolean
glade_widget_property_get(GladeWidget * widget,const gchar * id_property,...)2959 glade_widget_property_get (GladeWidget *widget, const gchar *id_property, ...)
2960 {
2961   GladeProperty *property;
2962   va_list vl;
2963 
2964   g_return_val_if_fail (GLADE_IS_WIDGET (widget), FALSE);
2965   g_return_val_if_fail (id_property != NULL, FALSE);
2966 
2967   if ((property = glade_widget_get_property (widget, id_property)) != NULL)
2968     {
2969       va_start (vl, id_property);
2970       glade_property_get_va_list (property, vl);
2971       va_end (vl);
2972       return TRUE;
2973     }
2974   return FALSE;
2975 }
2976 
2977 /**
2978  * glade_widget_property_set:
2979  * @widget: a #GladeWidget
2980  * @id_property: a string naming a #GladeProperty
2981  * @...: A value of the correct type for the said #GladeProperty
2982  *
2983  * Sets the value of @id_property in @widget
2984  *
2985  * Returns: whether @id_property was found or not.
2986  */
2987 gboolean
glade_widget_property_set(GladeWidget * widget,const gchar * id_property,...)2988 glade_widget_property_set (GladeWidget *widget, const gchar *id_property, ...)
2989 {
2990   GladeProperty *property;
2991   va_list vl;
2992 
2993   g_return_val_if_fail (GLADE_IS_WIDGET (widget), FALSE);
2994   g_return_val_if_fail (id_property != NULL, FALSE);
2995 
2996   if ((property = glade_widget_get_property (widget, id_property)) != NULL)
2997     {
2998       va_start (vl, id_property);
2999       glade_property_set_va_list (property, vl);
3000       va_end (vl);
3001       return TRUE;
3002     }
3003   return FALSE;
3004 }
3005 
3006 /**
3007  * glade_widget_pack_property_get:
3008  * @widget: a #GladeWidget
3009  * @id_property: a string naming a #GladeProperty
3010  * @...: The return location for the value of the said #GladeProperty
3011  *
3012  * Gets the value of @id_property in @widget packing properties
3013  *
3014  * Returns: whether @id_property was found or not.
3015  */
3016 gboolean
glade_widget_pack_property_get(GladeWidget * widget,const gchar * id_property,...)3017 glade_widget_pack_property_get (GladeWidget *widget,
3018                                 const gchar *id_property,
3019                                 ...)
3020 {
3021   GladeProperty *property;
3022   va_list vl;
3023 
3024   g_return_val_if_fail (GLADE_IS_WIDGET (widget), FALSE);
3025   g_return_val_if_fail (id_property != NULL, FALSE);
3026 
3027   if ((property = glade_widget_get_pack_property (widget, id_property)) != NULL)
3028     {
3029       va_start (vl, id_property);
3030       glade_property_get_va_list (property, vl);
3031       va_end (vl);
3032       return TRUE;
3033     }
3034   return FALSE;
3035 }
3036 
3037 /**
3038  * glade_widget_pack_property_set:
3039  * @widget: a #GladeWidget
3040  * @id_property: a string naming a #GladeProperty
3041  * @...: The return location for the value of the said #GladeProperty
3042  *
3043  * Sets the value of @id_property in @widget packing properties
3044  *
3045  * Returns: whether @id_property was found or not.
3046  */
3047 gboolean
glade_widget_pack_property_set(GladeWidget * widget,const gchar * id_property,...)3048 glade_widget_pack_property_set (GladeWidget *widget,
3049                                 const gchar *id_property,
3050                                 ...)
3051 {
3052   GladeProperty *property;
3053   va_list vl;
3054 
3055   g_return_val_if_fail (GLADE_IS_WIDGET (widget), FALSE);
3056   g_return_val_if_fail (id_property != NULL, FALSE);
3057 
3058   if ((property = glade_widget_get_pack_property (widget, id_property)) != NULL)
3059     {
3060       va_start (vl, id_property);
3061       glade_property_set_va_list (property, vl);
3062       va_end (vl);
3063       return TRUE;
3064     }
3065   return FALSE;
3066 }
3067 
3068 /**
3069  * glade_widget_property_set_sensitive:
3070  * @widget: a #GladeWidget
3071  * @id_property: a string naming a #GladeProperty
3072  * @sensitive: setting sensitive or insensitive
3073  * @reason: a description of why the user cant edit this property
3074  *          which will be used as a tooltip
3075  *
3076  * Sets the sensitivity of @id_property in @widget
3077  *
3078  * Returns: whether @id_property was found or not.
3079  */
3080 gboolean
glade_widget_property_set_sensitive(GladeWidget * widget,const gchar * id_property,gboolean sensitive,const gchar * reason)3081 glade_widget_property_set_sensitive (GladeWidget *widget,
3082                                      const gchar *id_property,
3083                                      gboolean     sensitive,
3084                                      const gchar *reason)
3085 {
3086   GladeProperty *property;
3087 
3088   g_return_val_if_fail (GLADE_IS_WIDGET (widget), FALSE);
3089   g_return_val_if_fail (id_property != NULL, FALSE);
3090 
3091   if ((property = glade_widget_get_property (widget, id_property)) != NULL)
3092     {
3093       glade_property_set_sensitive (property, sensitive, reason);
3094       return TRUE;
3095     }
3096   return FALSE;
3097 }
3098 
3099 /**
3100  * glade_widget_pack_property_set_sensitive:
3101  * @widget: a #GladeWidget
3102  * @id_property: a string naming a #GladeProperty
3103  * @sensitive: setting sensitive or insensitive
3104  * @reason: a description of why the user cant edit this property
3105  *          which will be used as a tooltip
3106  *
3107  * Sets the sensitivity of @id_property in @widget's packing properties.
3108  *
3109  * Returns: whether @id_property was found or not.
3110  */
3111 gboolean
glade_widget_pack_property_set_sensitive(GladeWidget * widget,const gchar * id_property,gboolean sensitive,const gchar * reason)3112 glade_widget_pack_property_set_sensitive (GladeWidget *widget,
3113                                           const gchar *id_property,
3114                                           gboolean     sensitive,
3115                                           const gchar *reason)
3116 {
3117   GladeProperty *property;
3118 
3119   g_return_val_if_fail (GLADE_IS_WIDGET (widget), FALSE);
3120   g_return_val_if_fail (id_property != NULL, FALSE);
3121 
3122   if ((property = glade_widget_get_pack_property (widget, id_property)) != NULL)
3123     {
3124       glade_property_set_sensitive (property, sensitive, reason);
3125       return TRUE;
3126     }
3127   return FALSE;
3128 }
3129 
3130 /**
3131  * glade_widget_property_set_enabled:
3132  * @widget: a #GladeWidget
3133  * @id_property: a string naming a #GladeProperty
3134  * @enabled: setting enabled or disabled
3135  *
3136  * Sets the enabled state of @id_property in @widget; this is
3137  * used for optional properties.
3138  *
3139  * Returns: whether @id_property was found or not.
3140  */
3141 gboolean
glade_widget_property_set_enabled(GladeWidget * widget,const gchar * id_property,gboolean enabled)3142 glade_widget_property_set_enabled (GladeWidget *widget,
3143                                    const gchar *id_property,
3144                                    gboolean     enabled)
3145 {
3146   GladeProperty *property;
3147 
3148   g_return_val_if_fail (GLADE_IS_WIDGET (widget), FALSE);
3149   g_return_val_if_fail (id_property != NULL, FALSE);
3150 
3151   if ((property = glade_widget_get_property (widget, id_property)) != NULL)
3152     {
3153       glade_property_set_enabled (property, enabled);
3154       return TRUE;
3155     }
3156   return FALSE;
3157 }
3158 
3159 /**
3160  * glade_widget_pack_property_set_enabled:
3161  * @widget: a #GladeWidget
3162  * @id_property: a string naming a #GladeProperty
3163  * @enabled: setting enabled or disabled
3164  *
3165  * Sets the enabled state of @id_property in @widget's packing
3166  * properties; this is used for optional properties.
3167  *
3168  * Returns: whether @id_property was found or not.
3169  */
3170 gboolean
glade_widget_pack_property_set_enabled(GladeWidget * widget,const gchar * id_property,gboolean enabled)3171 glade_widget_pack_property_set_enabled (GladeWidget *widget,
3172                                         const gchar *id_property,
3173                                         gboolean     enabled)
3174 {
3175   GladeProperty *property;
3176 
3177   g_return_val_if_fail (GLADE_IS_WIDGET (widget), FALSE);
3178   g_return_val_if_fail (id_property != NULL, FALSE);
3179 
3180   if ((property = glade_widget_get_pack_property (widget, id_property)) != NULL)
3181     {
3182       glade_property_set_enabled (property, enabled);
3183       return TRUE;
3184     }
3185   return FALSE;
3186 }
3187 
3188 /**
3189  * glade_widget_property_set_save_always:
3190  * @widget: a #GladeWidget
3191  * @id_property: a string naming a #GladeProperty
3192  * @setting: the setting
3193  *
3194  * Sets whether @id_property in @widget should be special cased
3195  * to always be saved regardless of its default value.
3196  * (used for some special cases like properties
3197  * that are assigned initial values in composite widgets
3198  * or derived widget code).
3199  *
3200  * Returns: whether @id_property was found or not.
3201  */
3202 gboolean
glade_widget_property_set_save_always(GladeWidget * widget,const gchar * id_property,gboolean setting)3203 glade_widget_property_set_save_always (GladeWidget *widget,
3204                                        const gchar *id_property,
3205                                        gboolean     setting)
3206 {
3207   GladeProperty *property;
3208 
3209   g_return_val_if_fail (GLADE_IS_WIDGET (widget), FALSE);
3210   g_return_val_if_fail (id_property != NULL, FALSE);
3211 
3212   if ((property = glade_widget_get_property (widget, id_property)) != NULL)
3213     {
3214       glade_property_set_save_always (property, setting);
3215       return TRUE;
3216     }
3217   return FALSE;
3218 }
3219 
3220 /**
3221  * glade_widget_pack_property_set_save_always:
3222  * @widget: a #GladeWidget
3223  * @id_property: a string naming a #GladeProperty
3224  * @setting: the setting
3225  *
3226  * Sets whether @id_property in @widget should be special cased
3227  * to always be saved regardless of its default value.
3228  * (used for some special cases like properties
3229  * that are assigned initial values in composite widgets
3230  * or derived widget code).
3231  *
3232  * Returns: whether @id_property was found or not.
3233  */
3234 gboolean
glade_widget_pack_property_set_save_always(GladeWidget * widget,const gchar * id_property,gboolean setting)3235 glade_widget_pack_property_set_save_always (GladeWidget *widget,
3236                                             const gchar *id_property,
3237                                             gboolean     setting)
3238 {
3239   GladeProperty *property;
3240 
3241   g_return_val_if_fail (GLADE_IS_WIDGET (widget), FALSE);
3242   g_return_val_if_fail (id_property != NULL, FALSE);
3243 
3244   if ((property = glade_widget_get_pack_property (widget, id_property)) != NULL)
3245     {
3246       glade_property_set_save_always (property, setting);
3247       return TRUE;
3248     }
3249   return FALSE;
3250 }
3251 
3252 /**
3253  * glade_widget_property_string:
3254  * @widget: a #GladeWidget
3255  * @id_property: a string naming a #GladeProperty
3256  * @value: the #GValue to print or %NULL
3257  *
3258  * Creates a printable string representing @id_property in
3259  * @widget, if @value is specified it will be used in place
3260  * of @id_property's real value (this is a convinience
3261  * function to print/debug properties usually from plugin
3262  * backends).
3263  *
3264  * Returns: A newly allocated string representing @id_property
3265  */
3266 gchar *
glade_widget_property_string(GladeWidget * widget,const gchar * id_property,const GValue * value)3267 glade_widget_property_string (GladeWidget  *widget,
3268                               const gchar  *id_property,
3269 			      const GValue *value)
3270 {
3271   GladeProperty      *property;
3272   GladePropertyClass *pclass;
3273   gchar              *ret_string = NULL;
3274 
3275   g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
3276   g_return_val_if_fail (id_property != NULL, NULL);
3277 
3278   if ((property = glade_widget_get_property (widget, id_property)) != NULL)
3279     {
3280       pclass     = glade_property_get_class (property);
3281       ret_string = glade_widget_adaptor_string_from_value
3282         (glade_property_class_get_adaptor (pclass), pclass,
3283 	 value ? value : glade_property_inline_value (property));
3284     }
3285 
3286   return ret_string;
3287 }
3288 
3289 /**
3290  * glade_widget_pack_property_string:
3291  * @widget: a #GladeWidget
3292  * @id_property: a string naming a #GladeProperty
3293  * @value: the #GValue to print or %NULL
3294  *
3295  * Same as glade_widget_property_string() but for packing
3296  * properties.
3297  *
3298  * Returns: A newly allocated string representing @id_property
3299  */
3300 gchar *
glade_widget_pack_property_string(GladeWidget * widget,const gchar * id_property,const GValue * value)3301 glade_widget_pack_property_string (GladeWidget  *widget,
3302                                    const gchar  *id_property,
3303                                    const GValue *value)
3304 {
3305   GladeProperty      *property;
3306   GladePropertyClass *pclass;
3307   gchar              *ret_string = NULL;
3308 
3309   g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
3310   g_return_val_if_fail (id_property != NULL, NULL);
3311 
3312   if ((property = glade_widget_get_pack_property (widget, id_property)) != NULL)
3313     {
3314       pclass     = glade_property_get_class (property);
3315       ret_string = glade_widget_adaptor_string_from_value
3316         (glade_property_class_get_adaptor (pclass), pclass,
3317 	 value ? value : glade_property_inline_value (property));
3318     }
3319 
3320   return ret_string;
3321 }
3322 
3323 
3324 /**
3325  * glade_widget_property_reset:
3326  * @widget: a #GladeWidget
3327  * @id_property: a string naming a #GladeProperty
3328  *
3329  * Resets @id_property in @widget to it's default value
3330  *
3331  * Returns: whether @id_property was found or not.
3332  */
3333 gboolean
glade_widget_property_reset(GladeWidget * widget,const gchar * id_property)3334 glade_widget_property_reset (GladeWidget *widget, const gchar *id_property)
3335 {
3336   GladeProperty *property;
3337 
3338   g_return_val_if_fail (GLADE_IS_WIDGET (widget), FALSE);
3339 
3340   if ((property = glade_widget_get_property (widget, id_property)) != NULL)
3341     {
3342       glade_property_reset (property);
3343       return TRUE;
3344     }
3345   return FALSE;
3346 }
3347 
3348 /**
3349  * glade_widget_pack_property_reset:
3350  * @widget: a #GladeWidget
3351  * @id_property: a string naming a #GladeProperty
3352  *
3353  * Resets @id_property in @widget's packing properties to it's default value
3354  *
3355  * Returns: whether @id_property was found or not.
3356  */
3357 gboolean
glade_widget_pack_property_reset(GladeWidget * widget,const gchar * id_property)3358 glade_widget_pack_property_reset (GladeWidget *widget,
3359                                   const gchar *id_property)
3360 {
3361   GladeProperty *property;
3362 
3363   g_return_val_if_fail (GLADE_IS_WIDGET (widget), FALSE);
3364 
3365   if ((property = glade_widget_get_pack_property (widget, id_property)) != NULL)
3366     {
3367       glade_property_reset (property);
3368       return TRUE;
3369     }
3370   return FALSE;
3371 }
3372 
3373 static gboolean
glade_widget_property_default_common(GladeWidget * widget,const gchar * id_property,gboolean original)3374 glade_widget_property_default_common (GladeWidget *widget,
3375                                       const gchar *id_property,
3376                                       gboolean     original)
3377 {
3378   GladeProperty *property;
3379 
3380   g_return_val_if_fail (GLADE_IS_WIDGET (widget), FALSE);
3381 
3382   if ((property = glade_widget_get_property (widget, id_property)) != NULL)
3383     return (original) ? glade_property_original_default (property) :
3384         glade_property_default (property);
3385 
3386   return FALSE;
3387 }
3388 
3389 /**
3390  * glade_widget_property_default:
3391  * @widget: a #GladeWidget
3392  * @id_property: a string naming a #GladeProperty
3393  *
3394  * Returns: whether whether @id_property was found and is
3395  * currently set to it's default value.
3396  */
3397 gboolean
glade_widget_property_default(GladeWidget * widget,const gchar * id_property)3398 glade_widget_property_default (GladeWidget *widget, const gchar *id_property)
3399 {
3400   return glade_widget_property_default_common (widget, id_property, FALSE);
3401 }
3402 
3403 /**
3404  * glade_widget_property_original_default:
3405  * @widget: a #GladeWidget
3406  * @id_property: a string naming a #GladeProperty
3407  *
3408  * Returns: whether whether @id_property was found and is
3409  * currently set to it's original default value.
3410  */
3411 gboolean
glade_widget_property_original_default(GladeWidget * widget,const gchar * id_property)3412 glade_widget_property_original_default (GladeWidget *widget,
3413                                         const gchar *id_property)
3414 {
3415   return glade_widget_property_default_common (widget, id_property, TRUE);
3416 }
3417 
3418 /**
3419  * glade_widget_pack_property_default:
3420  * @widget: a #GladeWidget
3421  * @id_property: a string naming a #GladeProperty
3422  *
3423  * Returns: whether whether @id_property was found and is
3424  * currently set to it's default value.
3425  */
3426 gboolean
glade_widget_pack_property_default(GladeWidget * widget,const gchar * id_property)3427 glade_widget_pack_property_default (GladeWidget *widget,
3428                                     const gchar *id_property)
3429 {
3430   GladeProperty *property;
3431 
3432   g_return_val_if_fail (GLADE_IS_WIDGET (widget), FALSE);
3433 
3434   if ((property = glade_widget_get_pack_property (widget, id_property)) != NULL)
3435     return glade_property_default (property);
3436 
3437   return FALSE;
3438 }
3439 
3440 
3441 /**
3442  * glade_widget_object_set_property:
3443  * @widget:        A #GladeWidget
3444  * @property_name: The property identifier
3445  * @value:         The #GValue
3446  *
3447  * This function applies @value to the property @property_name on
3448  * the runtime object of @widget.
3449  */
3450 void
glade_widget_object_set_property(GladeWidget * widget,const gchar * property_name,const GValue * value)3451 glade_widget_object_set_property (GladeWidget  *widget,
3452                                   const gchar  *property_name,
3453                                   const GValue *value)
3454 {
3455   g_return_if_fail (GLADE_IS_WIDGET (widget));
3456   g_return_if_fail (property_name != NULL && value != NULL);
3457 
3458   glade_widget_adaptor_set_property (widget->priv->adaptor,
3459                                      widget->priv->object, property_name, value);
3460 }
3461 
3462 
3463 /**
3464  * glade_widget_object_get_property:
3465  * @widget:        A #GladeWidget
3466  * @property_name: The property identifier
3467  * @value:         The #GValue
3468  *
3469  * This function retrieves the value of the property @property_name on
3470  * the runtime object of @widget and sets it in @value.
3471  */
3472 void
glade_widget_object_get_property(GladeWidget * widget,const gchar * property_name,GValue * value)3473 glade_widget_object_get_property (GladeWidget *widget,
3474                                   const gchar *property_name,
3475                                   GValue      *value)
3476 {
3477   g_return_if_fail (GLADE_IS_WIDGET (widget));
3478   g_return_if_fail (property_name != NULL && value != NULL);
3479 
3480   glade_widget_adaptor_get_property (widget->priv->adaptor,
3481                                      widget->priv->object, property_name, value);
3482 }
3483 
3484 /**
3485  * glade_widget_child_set_property:
3486  * @widget:        A #GladeWidget
3487  * @child:         The #GladeWidget child
3488  * @property_name: The id of the property
3489  * @value:         The @GValue
3490  *
3491  * Sets @child's packing property identified by @property_name to @value.
3492  */
3493 void
glade_widget_child_set_property(GladeWidget * widget,GladeWidget * child,const gchar * property_name,const GValue * value)3494 glade_widget_child_set_property (GladeWidget  *widget,
3495                                  GladeWidget  *child,
3496                                  const gchar  *property_name,
3497                                  const GValue *value)
3498 {
3499   GladeWidgetPrivate *priv, *cpriv;
3500   GList *old_order;
3501   gboolean check;
3502 
3503   g_return_if_fail (GLADE_IS_WIDGET (widget));
3504   g_return_if_fail (GLADE_IS_WIDGET (child));
3505   g_return_if_fail (property_name != NULL && value != NULL);
3506 
3507   priv = widget->priv;
3508   cpriv = child->priv;
3509 
3510   check = priv->project && priv->in_project && cpriv->project && cpriv->in_project;
3511   old_order = (check) ? glade_widget_get_children (widget) : NULL;
3512 
3513   glade_widget_adaptor_child_set_property (priv->adaptor, priv->object,
3514                                            cpriv->object, property_name, value);
3515 
3516   /* After setting a child property... it's possible the order of children
3517    * in the parent has been effected.
3518    *
3519    * If this is the case then we need to signal the GladeProject that
3520    * it's rows have been reordered so that any connected views update
3521    * themselves properly.
3522    */
3523   if (check)
3524     glade_project_check_reordered (priv->project, widget, old_order);
3525 
3526   g_list_free (old_order);
3527 }
3528 
3529 /**
3530  * glade_widget_child_get_property:
3531  * @widget:        A #GladeWidget
3532  * @child:         The #GladeWidget child
3533  * @property_name: The id of the property
3534  * @value:         The @GValue
3535  *
3536  * Gets @child's packing property identified by @property_name.
3537  */
3538 void
glade_widget_child_get_property(GladeWidget * widget,GladeWidget * child,const gchar * property_name,GValue * value)3539 glade_widget_child_get_property (GladeWidget *widget,
3540                                  GladeWidget *child,
3541                                  const gchar *property_name,
3542                                  GValue      *value)
3543 {
3544   g_return_if_fail (GLADE_IS_WIDGET (widget));
3545   g_return_if_fail (GLADE_IS_WIDGET (child));
3546   g_return_if_fail (property_name != NULL && value != NULL);
3547 
3548   glade_widget_adaptor_child_get_property (widget->priv->adaptor,
3549                                            widget->priv->object,
3550                                            child->priv->object, property_name, value);
3551 
3552 }
3553 
3554 static void
glade_widget_add_events(GtkWidget * widget)3555 glade_widget_add_events (GtkWidget *widget)
3556 {
3557   GList *children, *list;
3558 
3559   gtk_widget_add_events (widget,
3560                          GDK_POINTER_MOTION_MASK |      /* Handle pointer events */
3561                          GDK_POINTER_MOTION_HINT_MASK | /* for drag/resize and   */
3562                          GDK_BUTTON_PRESS_MASK |        /* managing selection.   */
3563                          GDK_BUTTON_RELEASE_MASK);
3564 
3565   /* We also need to get events for any children. */
3566   if (GTK_IS_CONTAINER (widget))
3567     {
3568       if ((children =
3569            glade_util_container_get_all_children (GTK_CONTAINER
3570                                                   (widget))) != NULL)
3571         {
3572           for (list = children; list; list = list->next)
3573             glade_widget_add_events (GTK_WIDGET (list->data));
3574           g_list_free (children);
3575         }
3576     }
3577 }
3578 
3579 static void
glade_widget_set_object(GladeWidget * gwidget,GObject * new_object)3580 glade_widget_set_object (GladeWidget *gwidget, GObject *new_object)
3581 {
3582   GObject *old_object;
3583 
3584   g_return_if_fail (GLADE_IS_WIDGET (gwidget));
3585   g_return_if_fail (new_object == NULL ||
3586                     g_type_is_a (G_OBJECT_TYPE (new_object),
3587                                  glade_widget_adaptor_get_object_type (gwidget->priv->adaptor)));
3588 
3589   if (gwidget->priv->object == new_object)
3590     return;
3591 
3592   old_object = gwidget->priv->object;
3593   gwidget->priv->object = new_object;
3594 
3595   if (new_object)
3596     {
3597       /* Add internal reference to new widget if its not internal */
3598       if (gwidget->priv->internal == NULL)
3599         {
3600           /* Assume initial ref count of all objects */
3601           if (G_IS_INITIALLY_UNOWNED (new_object))
3602             g_object_ref_sink (new_object);
3603         }
3604 
3605       g_object_set_qdata (G_OBJECT (new_object), glade_widget_name_quark,
3606                           gwidget);
3607 
3608       if (g_type_is_a (glade_widget_adaptor_get_object_type (gwidget->priv->adaptor), GTK_TYPE_WIDGET))
3609         {
3610           /* Disable any built-in DnD */
3611           gtk_drag_dest_unset (GTK_WIDGET (new_object));
3612           gtk_drag_source_unset (GTK_WIDGET (new_object));
3613           /* We nee to make sure all widgets set the event glade core needs */
3614           glade_widget_add_events (GTK_WIDGET (new_object));
3615         }
3616     }
3617 
3618   /* Remove internal reference to old widget */
3619   if (old_object)
3620     {
3621       if (gwidget->priv->internal == NULL)
3622         {
3623 	  GLADE_NOTE (REF_COUNTS,
3624 		      g_print ("Killing '%s::%s' widget's object with reference count %d\n",
3625 			       glade_widget_adaptor_get_name (gwidget->priv->adaptor),
3626 			       gwidget->priv->name ? gwidget->priv->name : "(unknown)",
3627 			       old_object->ref_count));
3628 
3629 	  /* Have the adaptor for this widget break any additional references */
3630 	  glade_widget_adaptor_destroy_object (gwidget->priv->adaptor, old_object);
3631         }
3632 
3633       /* From this point on, the GladeWidget is no longer retrievable with
3634        * glade_widget_get_from_gobject()... we let it be for the duration
3635        * of ->destroy_object()
3636        */
3637       g_object_set_qdata (G_OBJECT (old_object), glade_widget_name_quark, NULL);
3638 
3639       if (gwidget->priv->internal == NULL)
3640           g_object_unref (old_object);
3641 
3642 
3643     }
3644   g_object_notify_by_pspec (G_OBJECT (gwidget), properties[PROP_OBJECT]);
3645 }
3646 
3647 /**
3648  * glade_widget_get_object:
3649  * @widget: a #GladeWidget
3650  *
3651  * Returns: the #GObject associated with @widget
3652  */
3653 GObject *
glade_widget_get_object(GladeWidget * widget)3654 glade_widget_get_object (GladeWidget *widget)
3655 {
3656   g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
3657   return widget->priv->object;
3658 }
3659 
3660 /**
3661  * glade_widget_get_parent:
3662  * @widget: A #GladeWidget
3663  *
3664  * Returns: The parenting #GladeWidget
3665  */
3666 GladeWidget *
glade_widget_get_parent(GladeWidget * widget)3667 glade_widget_get_parent (GladeWidget *widget)
3668 {
3669   g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
3670   return widget->priv->parent;
3671 }
3672 
3673 /**
3674  * glade_widget_set_parent:
3675  * @widget: A #GladeWidget
3676  * @parent: the parenting #GladeWidget (or %NULL)
3677  *
3678  * sets the parenting #GladeWidget
3679  */
3680 void
glade_widget_set_parent(GladeWidget * widget,GladeWidget * parent)3681 glade_widget_set_parent (GladeWidget *widget, GladeWidget *parent)
3682 {
3683   GladeWidget *old_parent;
3684 
3685   g_return_if_fail (GLADE_IS_WIDGET (widget));
3686 
3687   old_parent = widget->priv->parent;
3688   widget->priv->parent = parent;
3689 
3690   /* Set packing props only if the object is actually parented by 'parent'
3691    * (a subsequent call should come from glade_command after parenting).
3692    */
3693   if (widget->priv->object && parent != NULL &&
3694       glade_widget_adaptor_has_child
3695       (parent->priv->adaptor, parent->priv->object, widget->priv->object))
3696     {
3697       if (old_parent == NULL || widget->priv->packing_properties == NULL ||
3698           old_parent->priv->adaptor != parent->priv->adaptor)
3699         glade_widget_set_packing_properties (widget, parent);
3700       else
3701         glade_widget_sync_packing_props (widget);
3702     }
3703 
3704   if (parent)
3705     glade_widget_set_packing_actions (widget, parent);
3706 
3707   g_object_notify_by_pspec (G_OBJECT (widget), properties[PROP_PARENT]);
3708 }
3709 
3710 /**
3711  * glade_widget_find_child:
3712  * @widget: A #GladeWidget
3713  * @name: child name
3714  *
3715  * Finds a child widget named @name.
3716  *
3717  * Returns: The child of widget or NULL if it was not found.
3718  */
3719 GladeWidget *
glade_widget_find_child(GladeWidget * widget,const gchar * name)3720 glade_widget_find_child (GladeWidget *widget, const gchar *name)
3721 {
3722   GList *adapter_children;
3723   GladeWidget *real_child = NULL;
3724   GList *node;
3725 
3726   g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
3727 
3728   adapter_children =
3729       glade_widget_adaptor_get_children (glade_widget_get_adaptor (widget),
3730                                          widget->priv->object);
3731 
3732   for (node = adapter_children; node && !real_child; node = g_list_next (node))
3733     {
3734       GladeWidget *child = glade_widget_get_from_gobject (node->data);
3735 
3736       if (child)
3737         {
3738           if (strcmp (child->priv->name, name) == 0)
3739             real_child = child;
3740           else
3741             real_child = glade_widget_find_child (child, name);
3742         }
3743     }
3744   g_list_free (adapter_children);
3745 
3746   return real_child;
3747 }
3748 
3749 /**
3750  * glade_widget_get_children:
3751  * @widget: A #GladeWidget
3752  *
3753  * Fetches any wrapped children of @widget.
3754  *
3755  * Returns: The children of widget
3756  *
3757  * <note><para>This differs from a direct call to glade_widget_adaptor_get_children() as
3758  * it only returns children which have an associated GladeWidget. This function will
3759  * not return any placeholders or internal composite children that have not been
3760  * exposed for Glade configuration</para></note>
3761  */
3762 GList *
glade_widget_get_children(GladeWidget * widget)3763 glade_widget_get_children (GladeWidget *widget)
3764 {
3765   GList *adapter_children;
3766   GList *real_children = NULL;
3767   GList *node;
3768 
3769   g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
3770 
3771   adapter_children =
3772       glade_widget_adaptor_get_children (glade_widget_get_adaptor (widget),
3773                                          widget->priv->object);
3774 
3775   for (node = adapter_children; node != NULL; node = g_list_next (node))
3776     {
3777       if (glade_widget_get_from_gobject (node->data))
3778         {
3779           real_children = g_list_prepend (real_children, node->data);
3780         }
3781     }
3782   g_list_free (adapter_children);
3783 
3784   return g_list_reverse (real_children);
3785 }
3786 
3787 
3788 /**
3789  * glade_widget_get_toplevel:
3790  * @widget: A #GladeWidget
3791  *
3792  * Returns: The toplevel #GladeWidget in the hierarchy (or @widget)
3793  */
3794 GladeWidget *
glade_widget_get_toplevel(GladeWidget * widget)3795 glade_widget_get_toplevel (GladeWidget *widget)
3796 {
3797   GladeWidget *toplevel = widget;
3798   g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
3799 
3800   while (toplevel->priv->parent)
3801     toplevel = toplevel->priv->parent;
3802 
3803   return toplevel;
3804 }
3805 
3806 /**
3807  * glade_widget_set_packing_properties:
3808  * @widget:     A #GladeWidget
3809  * @container:  The parent #GladeWidget
3810  *
3811  * Generates the packing_properties list of the widget, given
3812  * the class of the container we are adding the widget to.
3813  * If the widget already has packing_properties, but the container
3814  * has changed, the current list is freed and replaced.
3815  */
3816 void
glade_widget_set_packing_properties(GladeWidget * widget,GladeWidget * container)3817 glade_widget_set_packing_properties (GladeWidget *widget,
3818                                      GladeWidget *container)
3819 {
3820   GList *list;
3821 
3822   g_return_if_fail (GLADE_IS_WIDGET (widget));
3823   g_return_if_fail (GLADE_IS_WIDGET (container));
3824 
3825   /* Avoid rewriting and losing packing properties when
3826    * reparenting in the process of rebuilding a widget instance.
3827    */
3828   if (widget->priv->rebuilding)
3829     return;
3830 
3831   g_list_foreach (widget->priv->packing_properties, (GFunc) g_object_unref, NULL);
3832   g_list_free (widget->priv->packing_properties);
3833   widget->priv->packing_properties = NULL;
3834 
3835   if (widget->priv->pack_props_hash)
3836     g_hash_table_destroy (widget->priv->pack_props_hash);
3837   widget->priv->pack_props_hash = NULL;
3838 
3839   /* We have to detect whether this is an anarchist child of a composite
3840    * widget or not, in otherwords; whether its really a direct child or
3841    * a child of a popup window created on the composite widget's behalf.
3842    */
3843   if (widget->priv->anarchist)
3844     return;
3845 
3846   widget->priv->packing_properties =
3847       glade_widget_create_packing_properties (container, widget);
3848   widget->priv->pack_props_hash = g_hash_table_new (g_str_hash, g_str_equal);
3849 
3850   /* update the quick reference hash table */
3851   for (list = widget->priv->packing_properties; list && list->data; list = list->next)
3852     {
3853       GladeProperty      *property = list->data;
3854       GladePropertyClass *pclass = glade_property_get_class (property);
3855 
3856       g_hash_table_insert (widget->priv->pack_props_hash,
3857 			   (gchar *)glade_property_class_id (pclass),
3858 			   property);
3859     }
3860 
3861   /* Dont introspect on properties that are not parented yet.
3862    */
3863   if (glade_widget_adaptor_has_child (container->priv->adaptor,
3864                                       container->priv->object,
3865 				      widget->priv->object))
3866     {
3867       glade_widget_set_default_packing_properties (container, widget);
3868 
3869       /* update the values of the properties to the ones we get from gtk */
3870       for (list = widget->priv->packing_properties;
3871            list && list->data; list = list->next)
3872         {
3873 	  /* XXX Ugly dangerous code, plays with the property value inline */
3874           GladeProperty      *property = list->data;
3875 	  GladePropertyClass *pclass   = glade_property_get_class (property);
3876 	  GValue             *value    = glade_property_inline_value (property);
3877 
3878           g_value_reset (value);
3879           glade_widget_child_get_property (container,
3880 					   widget,
3881 					   glade_property_class_id (pclass),
3882 					   value);
3883         }
3884     }
3885 }
3886 
3887 /**
3888  * glade_widget_has_decendant:
3889  * @widget: a #GladeWidget
3890  * @type: a  #GType
3891  *
3892  * Returns: whether this GladeWidget has any decendants of type @type
3893  *          or any decendants that implement the @type interface
3894  */
3895 gboolean
glade_widget_has_decendant(GladeWidget * widget,GType type)3896 glade_widget_has_decendant (GladeWidget *widget, GType type)
3897 {
3898   GladeWidget *child;
3899   GList *children, *l;
3900   gboolean found = FALSE;
3901 
3902   if (glade_widget_adaptor_get_object_type (widget->priv->adaptor) == type ||
3903       g_type_is_a (glade_widget_adaptor_get_object_type (widget->priv->adaptor), type))
3904     return TRUE;
3905 
3906   if ((children = glade_widget_adaptor_get_children
3907        (widget->priv->adaptor, widget->priv->object)) != NULL)
3908     {
3909       for (l = children; l; l = l->next)
3910         if ((child = glade_widget_get_from_gobject (l->data)) != NULL &&
3911             (found = glade_widget_has_decendant (child, type)))
3912           break;
3913       g_list_free (children);
3914     }
3915   return found;
3916 }
3917 
3918 /**
3919  * glade_widget_replace:
3920  * @old_object: a #GObject
3921  * @new_object: a #GObject
3922  *
3923  * Replaces a GObject with another GObject inside a GObject which
3924  * behaves as a container.
3925  *
3926  * Note that both GObjects must be owned by a GladeWidget.
3927  */
3928 void
glade_widget_replace(GladeWidget * parent,GObject * old_object,GObject * new_object)3929 glade_widget_replace (GladeWidget *parent,
3930                       GObject     *old_object,
3931                       GObject     *new_object)
3932 {
3933   g_return_if_fail (G_IS_OBJECT (old_object));
3934   g_return_if_fail (G_IS_OBJECT (new_object));
3935 
3936   GLADE_WIDGET_GET_CLASS (parent)->replace_child (parent, old_object,
3937                                                   new_object);
3938 }
3939 
3940 /*******************************************************************************
3941  *                           Xml Parsing code                                  *
3942  *******************************************************************************/
3943 /* XXX Doc me !*/
3944 void
glade_widget_write_special_child_prop(GladeWidget * parent,GObject * object,GladeXmlContext * context,GladeXmlNode * node)3945 glade_widget_write_special_child_prop (GladeWidget     *parent,
3946                                        GObject         *object,
3947                                        GladeXmlContext *context,
3948                                        GladeXmlNode    *node)
3949 {
3950   gchar *buff, *special_child_type;
3951 
3952   buff = g_object_get_data (object, "special-child-type");
3953   g_object_get (parent->priv->adaptor, "special-child-type", &special_child_type,
3954                 NULL);
3955 
3956   if (special_child_type && buff)
3957     {
3958       glade_xml_node_set_property_string (node, GLADE_XML_TAG_TYPE, buff);
3959     }
3960   g_free (special_child_type);
3961 }
3962 
3963 /* XXX Doc me ! */
3964 void
glade_widget_set_child_type_from_node(GladeWidget * parent,GObject * child,GladeXmlNode * node)3965 glade_widget_set_child_type_from_node (GladeWidget  *parent,
3966                                        GObject      *child,
3967                                        GladeXmlNode *node)
3968 {
3969   gchar *special_child_type, *value;
3970 
3971   if (!glade_xml_node_verify (node, GLADE_XML_TAG_CHILD))
3972     return;
3973 
3974   g_object_get (parent->priv->adaptor,
3975 		"special-child-type", &special_child_type,
3976 		NULL);
3977   if (!special_child_type)
3978     return;
3979 
3980   /* all child types here are depicted by the "type" property */
3981   if ((value = glade_xml_get_property_string (node, GLADE_XML_TAG_TYPE)))
3982     {
3983       g_object_set_data_full (child, "special-child-type", value, g_free);
3984     }
3985   g_free (special_child_type);
3986 }
3987 
3988 
3989 /**
3990  * glade_widget_read_child:
3991  * @widget: A #GladeWidget
3992  * @node: a #GladeXmlNode
3993  *
3994  * Reads in a child widget from the xml (handles 'child' tag)
3995  */
3996 void
glade_widget_read_child(GladeWidget * widget,GladeXmlNode * node)3997 glade_widget_read_child (GladeWidget *widget, GladeXmlNode *node)
3998 {
3999   if (glade_project_load_cancelled (widget->priv->project))
4000     return;
4001 
4002   glade_widget_adaptor_read_child (widget->priv->adaptor, widget, node);
4003 }
4004 
4005 /**
4006  * glade_widget_read:
4007  * @project: a #GladeProject
4008  * @parent: The parent #GladeWidget or %NULL
4009  * @node: a #GladeXmlNode
4010  *
4011  * Returns: a new #GladeWidget for @project, based on @node
4012  */
4013 GladeWidget *
glade_widget_read(GladeProject * project,GladeWidget * parent,GladeXmlNode * node,const gchar * internal)4014 glade_widget_read (GladeProject *project,
4015                    GladeWidget  *parent,
4016                    GladeXmlNode *node,
4017                    const gchar  *internal)
4018 {
4019   GladeWidgetAdaptor *adaptor;
4020   GladeWidget *widget = NULL;
4021   gchar *klass, *id = NULL, *template_parent = NULL;
4022   gboolean template = FALSE;
4023   GType type;
4024   const gchar *type_to_use;
4025 
4026   if (glade_project_load_cancelled (project))
4027     return NULL;
4028 
4029   if (!(glade_xml_node_verify_silent (node, GLADE_XML_TAG_WIDGET) ||
4030 	glade_xml_node_verify_silent (node, GLADE_XML_TAG_TEMPLATE)))
4031       return NULL;
4032 
4033   if (glade_xml_node_verify_silent (node, GLADE_XML_TAG_TEMPLATE))
4034     template = TRUE;
4035 
4036   glade_widget_push_superuser ();
4037 
4038   if ((klass =
4039        glade_xml_get_property_string_required
4040        (node, GLADE_XML_TAG_CLASS, NULL)) != NULL)
4041     {
4042       if (template)
4043 	{
4044 	  template_parent = glade_xml_get_property_string_required (node, GLADE_TAG_PARENT, NULL);
4045 
4046 	  if (template_parent)
4047 	    id = g_strdup (klass);
4048 	}
4049       else
4050 	{
4051 	  id = glade_xml_get_property_string (node, GLADE_XML_TAG_ID);
4052 
4053 	  /* Here we use an internal unnamed prefix to identify unnamed widgets, then
4054 	   * we just issue a warning if anyone was dense enough to actually use
4055 	   * this prefix in a project as a widget name.
4056 	   */
4057 	  if (!id)
4058 	    id = glade_project_new_widget_name (project, NULL, GLADE_UNNAMED_PREFIX);
4059 	  else if (strncmp (id, GLADE_UNNAMED_PREFIX, strlen (GLADE_UNNAMED_PREFIX)) == 0)
4060 	    g_warning ("Loaded widget `%s' has internal glade prefix, please rename this widget", id);
4061 	}
4062 
4063       type_to_use = template_parent ? template_parent : klass;
4064 
4065       /*
4066        * Create GladeWidget instance based on type.
4067        */
4068       if ((adaptor = glade_widget_adaptor_get_by_name (type_to_use)) &&
4069 	  (type = glade_widget_adaptor_get_object_type (adaptor)) &&
4070 	  G_TYPE_IS_INSTANTIATABLE (type) &&
4071 	  G_TYPE_IS_ABSTRACT (type) == FALSE)
4072 	{
4073 	  /* Internal children !!! */
4074 	  if (internal)
4075 	    {
4076 	      GObject *child_object =
4077 		glade_widget_get_internal_child (NULL, parent, internal);
4078 
4079 	      if (!child_object)
4080 		{
4081 		  g_warning ("Failed to locate "
4082 			     "internal child %s of %s",
4083 			     internal, glade_widget_get_name (parent));
4084 		  goto out;
4085 		}
4086 
4087 	      if (!(widget = glade_widget_get_from_gobject (child_object)))
4088 		g_error ("Unable to get GladeWidget "
4089 			 "for internal child %s\n", internal);
4090 
4091 	      /* Apply internal widget name from here */
4092 	      glade_widget_set_name (widget, id);
4093 	    }
4094 	  else
4095 	    {
4096 	      widget = glade_widget_adaptor_create_widget
4097 		(adaptor, FALSE,
4098 		 "name", id,
4099 		 "composite", template,
4100 		 "parent", parent,
4101 		 "project", project, "reason", GLADE_CREATE_LOAD, NULL);
4102 	    }
4103 
4104 	  glade_widget_adaptor_read_widget (adaptor, widget, node);
4105 	}
4106       else
4107 	{
4108 	  GObject *stub = g_object_new (GLADE_TYPE_OBJECT_STUB,
4109 					"object-type", klass,
4110 					"xml-node", node,
4111 					NULL);
4112 
4113 	  widget = glade_widget_adaptor_create_widget (glade_widget_adaptor_get_by_type (GTK_TYPE_WIDGET),
4114 						       FALSE,
4115 						       "parent", parent,
4116 						       "composite", template,
4117 						       "project", project,
4118 						       "reason", GLADE_CREATE_LOAD,
4119 						       "object", stub,
4120 						       "name", id,
4121 						       NULL);
4122 	}
4123       g_free (id);
4124 
4125       g_free (template_parent);
4126       g_free (klass);
4127     }
4128 
4129  out:
4130   glade_widget_pop_superuser ();
4131 
4132   glade_project_push_progress (project);
4133 
4134   return widget;
4135 }
4136 
4137 
4138 /**
4139  * glade_widget_write_child:
4140  * @widget: A #GladeWidget
4141  * @child: The child #GladeWidget to write
4142  * @context: A #GladeXmlContext
4143  * @node: A #GladeXmlNode
4144  *
4145  * Writes out a widget to the xml, takes care
4146  * of packing properties and special child types.
4147  */
4148 void
glade_widget_write_child(GladeWidget * widget,GladeWidget * child,GladeXmlContext * context,GladeXmlNode * node)4149 glade_widget_write_child (GladeWidget     *widget,
4150                           GladeWidget     *child,
4151                           GladeXmlContext *context,
4152                           GladeXmlNode    *node)
4153 {
4154   g_return_if_fail (GLADE_IS_WIDGET (widget));
4155   g_return_if_fail (GLADE_IS_WIDGET (child));
4156   g_return_if_fail (child->priv->parent == widget);
4157 
4158   glade_widget_adaptor_write_child (widget->priv->adaptor, child, context, node);
4159 }
4160 
4161 
4162 /**
4163  * glade_widget_write_placeholder:
4164  * @parent: The parent #GladeWidget
4165  * @object: A #GladePlaceHolder
4166  * @context: A #GladeXmlContext
4167  * @node: A #GladeXmlNode
4168  *
4169  * Writes out a placeholder to the xml
4170  */
4171 void
glade_widget_write_placeholder(GladeWidget * parent,GObject * object,GladeXmlContext * context,GladeXmlNode * node)4172 glade_widget_write_placeholder (GladeWidget     *parent,
4173                                 GObject         *object,
4174                                 GladeXmlContext *context,
4175                                 GladeXmlNode    *node)
4176 {
4177   GladeXmlNode *child_node, *packing_node, *placeholder_node;
4178 
4179   child_node = glade_xml_node_new (context, GLADE_XML_TAG_CHILD);
4180   glade_xml_node_append_child (node, child_node);
4181 
4182   placeholder_node = glade_xml_node_new (context, GLADE_XML_TAG_PLACEHOLDER);
4183   glade_xml_node_append_child (child_node, placeholder_node);
4184 
4185   /* maybe write out special-child-type here */
4186   packing_node = glade_xml_node_new (context, GLADE_XML_TAG_PACKING);
4187   glade_xml_node_append_child (child_node, packing_node);
4188 
4189   glade_widget_write_special_child_prop (parent, object, context, child_node);
4190 
4191   if (!glade_xml_node_get_children (packing_node))
4192     {
4193       glade_xml_node_remove (packing_node);
4194       glade_xml_node_delete (packing_node);
4195     }
4196 }
4197 
4198 static gint
signal_compare(GladeSignal * signal_a,GladeSignal * signal_b)4199 signal_compare (GladeSignal *signal_a, GladeSignal *signal_b)
4200 {
4201   const gchar *handler_a;
4202   const gchar *handler_b;
4203   const GladeSignalClass *class_a;
4204   const GladeSignalClass *class_b;
4205   const gchar *class_name_a;
4206   const gchar *class_name_b;
4207   const gchar *detail_a;
4208   const gchar *detail_b;
4209   const gchar *data_a;
4210   const gchar *data_b;
4211   gint comparison;
4212 
4213   handler_a = glade_signal_get_handler (signal_a);
4214   handler_b = glade_signal_get_handler (signal_b);
4215   detail_a  = glade_signal_get_detail (signal_a);
4216   detail_b  = glade_signal_get_detail (signal_b);
4217   data_a    = glade_signal_get_userdata (signal_a);
4218   data_b    = glade_signal_get_userdata (signal_b);
4219 
4220   class_a   = glade_signal_get_class (signal_a);
4221   class_b   = glade_signal_get_class (signal_b);
4222   class_name_a = glade_signal_class_get_name (class_a);
4223   class_name_b = glade_signal_class_get_name (class_b);
4224 
4225   /* By signal name ... */
4226   comparison = g_strcmp0 (class_name_a, class_name_b);
4227   if (comparison != 0)
4228     return comparison;
4229 
4230   /* By handler name ... */
4231   comparison = g_strcmp0 (handler_a, handler_b);
4232   if (comparison != 0)
4233     return comparison;
4234 
4235   /* By detail name ... */
4236   comparison = g_strcmp0 (detail_a, detail_b);
4237   if (comparison != 0)
4238     return comparison;
4239 
4240   /* By user data ... */
4241   comparison = g_strcmp0 (data_a, data_b);
4242   if (comparison != 0)
4243     return comparison;
4244 
4245   /* By 'after' flag ... */
4246   comparison = glade_signal_get_after (signal_a) - glade_signal_get_after (signal_b);
4247   if (comparison != 0)
4248     return comparison;
4249 
4250   /* By 'swapped' flag ... */
4251   comparison = glade_signal_get_swapped (signal_a) - glade_signal_get_swapped (signal_b);
4252   if (comparison != 0)
4253     return comparison;
4254 
4255   /* They are actually exactly the same ... return 0 */
4256   return 0;
4257 }
4258 
4259 void
glade_widget_write_signals(GladeWidget * widget,GladeXmlContext * context,GladeXmlNode * node)4260 glade_widget_write_signals (GladeWidget     *widget,
4261                             GladeXmlContext *context,
4262                             GladeXmlNode    *node)
4263 {
4264   GHashTableIter iter;
4265   gpointer key, value;
4266   GladeSignal *signal;
4267   GList *sorted_signals = NULL, *l;
4268 
4269   /* Sort signals alphabetically by signal name (and then by handler name)
4270    * before saving them.
4271    *
4272    * Ensure we don't introduce useless project diffs at save time.
4273    */
4274   g_hash_table_iter_init (&iter, widget->priv->signals);
4275   while (g_hash_table_iter_next (&iter, &key, &value))
4276     {
4277       GPtrArray *signals = (GPtrArray *)value;
4278       gint i;
4279 
4280       for (i = 0; i < signals->len; i++)
4281 	{
4282 	  signal = g_ptr_array_index (signals, i);
4283 
4284 	  sorted_signals = g_list_prepend (sorted_signals, signal);
4285 	}
4286     }
4287 
4288   sorted_signals = g_list_sort (sorted_signals, (GCompareFunc)signal_compare);
4289 
4290   for (l = sorted_signals; l; l = l->next)
4291     {
4292 	  signal = l->data;
4293 	  glade_signal_write (signal, context, node);
4294     }
4295 
4296   g_list_free (sorted_signals);
4297 }
4298 
4299 /**
4300  * glade_widget_write:
4301  * @widget: The #GladeWidget
4302  * @context: A #GladeXmlContext
4303  * @node: A #GladeXmlNode
4304  *
4305  * Recursively writes out @widget and its children
4306  * and appends the created #GladeXmlNode to @node.
4307  */
4308 void
glade_widget_write(GladeWidget * widget,GladeXmlContext * context,GladeXmlNode * node)4309 glade_widget_write (GladeWidget     *widget,
4310                     GladeXmlContext *context,
4311                     GladeXmlNode    *node)
4312 {
4313   GObject *object = glade_widget_get_object (widget);
4314   GladeXmlNode *widget_node;
4315   GList *l, *list;
4316 
4317   /* Check if its an unknown object, and use saved xml if so */
4318   if (GLADE_IS_OBJECT_STUB (object))
4319     {
4320       g_object_get (object, "xml-node", &widget_node, NULL);
4321       glade_xml_node_append_child (node, widget_node);
4322       return;
4323     }
4324 
4325   /* Set class and id */
4326   if (widget->priv->composite)
4327     {
4328       widget_node = glade_xml_node_new (context, GLADE_XML_TAG_TEMPLATE);
4329       glade_xml_node_set_property_string (widget_node,
4330 					  GLADE_XML_TAG_CLASS,
4331 					  widget->priv->name);
4332       glade_xml_node_set_property_string (widget_node,
4333 					  GLADE_TAG_PARENT,
4334 					  glade_widget_adaptor_get_name (widget->priv->adaptor));
4335     }
4336   else
4337     {
4338       widget_node = glade_xml_node_new (context, GLADE_XML_TAG_WIDGET);
4339       glade_xml_node_set_property_string (widget_node,
4340 					  GLADE_XML_TAG_CLASS,
4341 					  glade_widget_adaptor_get_name (widget->priv->adaptor));
4342 
4343       /* Conditionally omit the ID in the output if the name is 'unset'
4344        */
4345       if (glade_widget_has_name (widget) || glade_project_writing_preview (widget->priv->project))
4346 	glade_xml_node_set_property_string (widget_node,
4347 					    GLADE_XML_TAG_ID, widget->priv->name);
4348     }
4349 
4350   glade_xml_node_append_child (node, widget_node);
4351 
4352   /* Write out widget content (properties and signals) */
4353   glade_widget_adaptor_write_widget (widget->priv->adaptor, widget, context,
4354                                      widget_node);
4355 
4356   /* Write the signals strictly after all properties and before children
4357    */
4358   glade_widget_write_signals (widget, context, widget_node);
4359 
4360   /* Write the children */
4361   if ((list =
4362        glade_widget_adaptor_get_children (widget->priv->adaptor,
4363                                           widget->priv->object)) != NULL)
4364     {
4365       for (l = list; l; l = l->next)
4366         {
4367           GladeWidget *child = glade_widget_get_from_gobject (l->data);
4368 
4369           if (child)
4370             glade_widget_write_child (widget, child, context, widget_node);
4371           else if (GLADE_IS_PLACEHOLDER (l->data))
4372             glade_widget_write_placeholder (widget,
4373                                             G_OBJECT (l->data),
4374                                             context, widget_node);
4375         }
4376       g_list_free (list);
4377     }
4378 
4379   /* Write out trailing widget content (anything that goes after children) */
4380   glade_widget_adaptor_write_widget_after (widget->priv->adaptor, widget, context, widget_node);
4381 }
4382 
4383 
4384 /**
4385  * glade_widget_is_ancestor:
4386  * @widget: a #GladeWidget
4387  * @ancestor: another #GladeWidget
4388  *
4389  * Determines whether @widget is somewhere inside @ancestor, possibly with
4390  * intermediate containers.
4391  *
4392  * Return value: %TRUE if @ancestor contains @widget as a child,
4393  *    grandchild, great grandchild, etc.
4394  **/
4395 gboolean
glade_widget_is_ancestor(GladeWidget * widget,GladeWidget * ancestor)4396 glade_widget_is_ancestor (GladeWidget *widget, GladeWidget *ancestor)
4397 {
4398   g_return_val_if_fail (GLADE_IS_WIDGET (widget), FALSE);
4399   g_return_val_if_fail (GLADE_IS_WIDGET (ancestor), FALSE);
4400 
4401   while (widget)
4402     {
4403       if (widget->priv->parent == ancestor)
4404         return TRUE;
4405       widget = widget->priv->parent;
4406     }
4407 
4408   return FALSE;
4409 }
4410 
4411 /**
4412  * glade_widget_depends:
4413  * @widget: a #GladeWidget
4414  * @other: another #GladeWidget
4415  *
4416  * Determines whether @widget is somehow dependent on @other, in
4417  * which case it should be serialized after @other.
4418  *
4419  * A widget is dependent on another widget.
4420  * It does not take into account for children dependencies.
4421  *
4422  * Return value: %TRUE if @widget depends on @other.
4423  *
4424  * Deprecated: 3.18
4425  **/
4426 gboolean
glade_widget_depends(GladeWidget * widget,GladeWidget * other)4427 glade_widget_depends (GladeWidget *widget, GladeWidget *other)
4428 {
4429   return FALSE;
4430 }
4431 
4432 /**
4433  * glade_widget_get_device_from_event:
4434  * @event: a GdkEvent
4435  *
4436  * Currently only motion and button events are handled (see IS_GLADE_WIDGET_EVENT)
4437  *
4438  * Returns: the asociated GdkDevice for this glade widget event.
4439  *
4440  * Deprecated: use gdk_event_get_device() instead.
4441  */
4442 GdkDevice *
glade_widget_get_device_from_event(GdkEvent * event)4443 glade_widget_get_device_from_event (GdkEvent *event)
4444 {
4445   return gdk_event_get_device (event);
4446 }
4447 
4448 static gint glade_widget_su_stack = 0;
4449 
4450 /**
4451  * glade_widget_superuser:
4452  *
4453  * Checks if we are in superuser mode.
4454  *
4455  * Superuser mode is when we are
4456  *   - Loading a project
4457  *   - Dupping a widget recursively
4458  *   - Rebuilding an instance for a construct-only property
4459  *
4460  * In these cases, we must act like a load, this should be checked
4461  * from the plugin when implementing containers, when undo/redo comes
4462  * around, the plugin is responsable for maintaining the same container
4463  * size when widgets are added/removed.
4464  */
4465 gboolean
glade_widget_superuser(void)4466 glade_widget_superuser (void)
4467 {
4468   return glade_widget_su_stack > 0;
4469 }
4470 
4471 /**
4472  * glade_widget_push_superuser:
4473  *
4474  * Sets superuser mode
4475  */
4476 void
glade_widget_push_superuser(void)4477 glade_widget_push_superuser (void)
4478 {
4479   glade_property_push_superuser ();
4480   glade_widget_su_stack++;
4481 }
4482 
4483 
4484 /**
4485  * glade_widget_pop_superuser:
4486  *
4487  * Unsets superuser mode
4488  */
4489 void
glade_widget_pop_superuser(void)4490 glade_widget_pop_superuser (void)
4491 {
4492   if (--glade_widget_su_stack < 0)
4493     {
4494       g_critical ("Bug: widget super user stack is corrupt.\n");
4495     }
4496   glade_property_pop_superuser ();
4497 }
4498 
4499 
4500 /**
4501  * glade_widget_placeholder_relation:
4502  * @parent: A #GladeWidget
4503  * @widget: The child #GladeWidget
4504  *
4505  * Returns whether placeholders should be used
4506  * in operations concerning this parent & child.
4507  *
4508  * Currently that criteria is whether @parent is a
4509  * GtkContainer, @widget is a GtkWidget and the parent
4510  * adaptor has been marked to use placeholders.
4511  *
4512  * Returns: whether to use placeholders for this relationship.
4513  */
4514 gboolean
glade_widget_placeholder_relation(GladeWidget * parent,GladeWidget * widget)4515 glade_widget_placeholder_relation (GladeWidget *parent, GladeWidget *widget)
4516 {
4517   g_return_val_if_fail (GLADE_IS_WIDGET (parent), FALSE);
4518   g_return_val_if_fail (GLADE_IS_WIDGET (widget), FALSE);
4519 
4520   return (GTK_IS_CONTAINER (parent->priv->object) &&
4521           GTK_IS_WIDGET (widget->priv->object) &&
4522           GWA_USE_PLACEHOLDERS (parent->priv->adaptor));
4523 }
4524 
4525 static GladeWidgetAction *
glade_widget_action_lookup(GList * actions,const gchar * path)4526 glade_widget_action_lookup (GList *actions, const gchar *path)
4527 {
4528   GList *l;
4529 
4530   for (l = actions; l; l = g_list_next (l))
4531     {
4532       GladeWidgetAction *action   = l->data;
4533       GWActionClass     *aclass   = glade_widget_action_get_class (action);
4534       GList             *children = glade_widget_action_get_children (action);
4535 
4536       if (strcmp (aclass->path, path) == 0)
4537 	return action;
4538 
4539       if (children &&
4540           g_str_has_prefix (path, aclass->path) &&
4541           (action = glade_widget_action_lookup (children, path)))
4542         return action;
4543     }
4544 
4545   return NULL;
4546 }
4547 
4548 /**
4549  * glade_widget_get_action:
4550  * @widget: a #GladeWidget
4551  * @action_path: a full action path including groups
4552  *
4553  * Returns a #GladeWidgetAction object indentified by @action_path.
4554  *
4555  * Returns: the action or NULL if not found.
4556  */
4557 GladeWidgetAction *
glade_widget_get_action(GladeWidget * widget,const gchar * action_path)4558 glade_widget_get_action (GladeWidget *widget, const gchar *action_path)
4559 {
4560   g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
4561   g_return_val_if_fail (action_path != NULL, NULL);
4562 
4563   return glade_widget_action_lookup (widget->priv->actions, action_path);
4564 }
4565 
4566 /**
4567  * glade_widget_get_pack_action:
4568  * @widget: a #GladeWidget
4569  * @action_path: a full action path including groups
4570  *
4571  * Returns a #GladeWidgetAction object indentified by @action_path.
4572  *
4573  * Returns: the action or NULL if not found.
4574  */
4575 GladeWidgetAction *
glade_widget_get_pack_action(GladeWidget * widget,const gchar * action_path)4576 glade_widget_get_pack_action (GladeWidget *widget, const gchar *action_path)
4577 {
4578   g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
4579   g_return_val_if_fail (action_path != NULL, NULL);
4580 
4581   return glade_widget_action_lookup (widget->priv->packing_actions, action_path);
4582 }
4583 
4584 
4585 GList *
glade_widget_get_actions(GladeWidget * widget)4586 glade_widget_get_actions (GladeWidget *widget)
4587 {
4588   g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
4589 
4590   return widget->priv->actions;
4591 }
4592 
4593 GList *
glade_widget_get_pack_actions(GladeWidget * widget)4594 glade_widget_get_pack_actions (GladeWidget *widget)
4595 {
4596   g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
4597 
4598   return widget->priv->packing_actions;
4599 }
4600 
4601 
4602 /**
4603  * glade_widget_set_action_sensitive:
4604  * @widget: a #GladeWidget
4605  * @action_path: a full action path including groups
4606  * @sensitive: setting sensitive or insensitive
4607  *
4608  * Sets the sensitivity of @action_path in @widget
4609  *
4610  * Returns: whether @action_path was found or not.
4611  */
4612 gboolean
glade_widget_set_action_sensitive(GladeWidget * widget,const gchar * action_path,gboolean sensitive)4613 glade_widget_set_action_sensitive (GladeWidget *widget,
4614                                    const gchar *action_path,
4615                                    gboolean     sensitive)
4616 {
4617   GladeWidgetAction *action;
4618 
4619   g_return_val_if_fail (GLADE_IS_WIDGET (widget), FALSE);
4620 
4621   if ((action = glade_widget_get_action (widget, action_path)) != NULL)
4622     {
4623       glade_widget_action_set_sensitive (action, sensitive);
4624       return TRUE;
4625     }
4626   return FALSE;
4627 }
4628 
4629 /**
4630  * glade_widget_set_pack_action_sensitive:
4631  * @widget: a #GladeWidget
4632  * @action_path: a full action path including groups
4633  * @sensitive: setting sensitive or insensitive
4634  *
4635  * Sets the sensitivity of @action_path in @widget
4636  *
4637  * Returns: whether @action_path was found or not.
4638  */
4639 gboolean
glade_widget_set_pack_action_sensitive(GladeWidget * widget,const gchar * action_path,gboolean sensitive)4640 glade_widget_set_pack_action_sensitive (GladeWidget *widget,
4641                                         const gchar *action_path,
4642                                         gboolean     sensitive)
4643 {
4644   GladeWidgetAction *action;
4645 
4646   g_return_val_if_fail (GLADE_IS_WIDGET (widget), FALSE);
4647 
4648   if ((action = glade_widget_get_pack_action (widget, action_path)) != NULL)
4649     {
4650       glade_widget_action_set_sensitive (action, sensitive);
4651       return TRUE;
4652     }
4653   return FALSE;
4654 }
4655 
4656 
4657 /**
4658  * glade_widget_set_action_visible:
4659  * @widget: a #GladeWidget
4660  * @action_path: a full action path including groups
4661  * @visible: setting visible or invisible
4662  *
4663  * Sets the visibility of @action_path in @widget
4664  *
4665  * Returns: whether @action_path was found or not.
4666  */
4667 gboolean
glade_widget_set_action_visible(GladeWidget * widget,const gchar * action_path,gboolean visible)4668 glade_widget_set_action_visible (GladeWidget *widget,
4669 				 const gchar *action_path,
4670 				 gboolean     visible)
4671 {
4672   GladeWidgetAction *action;
4673 
4674   g_return_val_if_fail (GLADE_IS_WIDGET (widget), FALSE);
4675 
4676   if ((action = glade_widget_get_action (widget, action_path)) != NULL)
4677     {
4678       glade_widget_action_set_visible (action, visible);
4679       return TRUE;
4680     }
4681   return FALSE;
4682 }
4683 
4684 /**
4685  * glade_widget_set_pack_action_visible:
4686  * @widget: a #GladeWidget
4687  * @action_path: a full action path including groups
4688  * @visible: setting visible or invisible
4689  *
4690  * Sets the visibility of @action_path in @widget
4691  *
4692  * Returns: whether @action_path was found or not.
4693  */
4694 gboolean
glade_widget_set_pack_action_visible(GladeWidget * widget,const gchar * action_path,gboolean visible)4695 glade_widget_set_pack_action_visible (GladeWidget *widget,
4696 				      const gchar *action_path,
4697 				      gboolean     visible)
4698 {
4699   GladeWidgetAction *action;
4700 
4701   g_return_val_if_fail (GLADE_IS_WIDGET (widget), FALSE);
4702 
4703   if ((action = glade_widget_get_pack_action (widget, action_path)) != NULL)
4704     {
4705       glade_widget_action_set_visible (action, visible);
4706       return TRUE;
4707     }
4708   return FALSE;
4709 }
4710 
4711 
4712 /**
4713  * glade_widget_create_editor_property:
4714  * @widget: A #GladeWidget
4715  * @property: The widget's property
4716  * @packing: whether @property indicates a packing property or not.
4717  * @use_command: Whether the undo/redo stack applies here.
4718  *
4719  * This is a convenience function to create a GladeEditorProperty corresponding
4720  * to @property
4721  *
4722  * Returns: A newly created and connected GladeEditorProperty
4723  */
4724 GladeEditorProperty *
glade_widget_create_editor_property(GladeWidget * widget,const gchar * property,gboolean packing,gboolean use_command)4725 glade_widget_create_editor_property (GladeWidget *widget,
4726                                      const gchar *property,
4727                                      gboolean     packing,
4728                                      gboolean     use_command)
4729 {
4730   GladeEditorProperty *eprop;
4731   GladeProperty       *prop;
4732   GladePropertyClass  *pclass;
4733 
4734   if (packing)
4735     prop = glade_widget_get_pack_property (widget, property);
4736   else
4737     prop = glade_widget_get_property (widget, property);
4738 
4739   g_return_val_if_fail (GLADE_IS_PROPERTY (prop), NULL);
4740   pclass = glade_property_get_class (prop);
4741 
4742   eprop = glade_widget_adaptor_create_eprop (widget->priv->adaptor,
4743                                              pclass, use_command);
4744   glade_editor_property_load (eprop, prop);
4745 
4746   return eprop;
4747 }
4748 
4749 /**
4750  * glade_widget_generate_path_name:
4751  * @widget: A #GladeWidget
4752  *
4753  * Creates a user friendly name to describe project widgets
4754  *
4755  * Returns: A newly allocated string
4756  */
4757 gchar *
glade_widget_generate_path_name(GladeWidget * widget)4758 glade_widget_generate_path_name (GladeWidget *widget)
4759 {
4760   GString *string;
4761   GladeWidget *iter;
4762 
4763   g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
4764 
4765   string = g_string_new (widget->priv->name);
4766 
4767   for (iter = widget->priv->parent; iter; iter = iter->priv->parent)
4768     {
4769       gchar *str = g_strdup_printf ("%s:", iter->priv->name);
4770       g_string_prepend (string, str);
4771       g_free (str);
4772     }
4773 
4774   return g_string_free (string, FALSE);
4775 }
4776 
4777 /**
4778  * glade_widget_verify:
4779  * @widget: A #GladeWidget
4780  *
4781  * Verify this widget for deprecation and versioning warnings.
4782  *
4783  * This function will update the widget's support warning.
4784  */
4785 void
glade_widget_verify(GladeWidget * widget)4786 glade_widget_verify (GladeWidget *widget)
4787 {
4788   GladeWidgetPrivate *priv;
4789   gchar *warning = NULL;
4790 
4791   g_return_if_fail (GLADE_IS_WIDGET (widget));
4792   priv = widget->priv;
4793 
4794   if (priv->project == NULL)
4795     return;
4796 
4797   if (priv->composite)
4798     {
4799       gint major, minor;
4800       glade_project_get_target_version (priv->project, "gtk+", &major, &minor);
4801 
4802       if (major == 3 && minor < 10)
4803         warning = g_strdup_printf (_("Template classes are not supported in gtk+ %d.%d"),
4804                                    major, minor);
4805     }
4806 
4807   if (!warning && GLADE_IS_OBJECT_STUB (priv->object))
4808     {
4809       gchar *type;
4810       g_object_get (priv->object, "object-type", &type, NULL);
4811 
4812       warning = g_strdup_printf (_("Object has unrecognized type %s"), type);
4813       g_free (type);
4814     }
4815 
4816   if (!warning)
4817     warning = glade_project_verify_widget_adaptor (priv->project,
4818                                                    priv->adaptor,
4819 						   NULL);
4820 
4821   /* If there is already support issues with the adaptor, skip signals
4822    * and properties
4823    */
4824   if (!warning)
4825     {
4826       GList *warn_properties = NULL;
4827       GList *warn_signals = NULL;
4828       GString *string = NULL;
4829       GHashTableIter iter;
4830       gpointer key, value;
4831       GList *l;
4832 
4833       /* Collect signals with warnings on them */
4834       g_hash_table_iter_init (&iter, priv->signals);
4835       while (g_hash_table_iter_next (&iter, &key, &value))
4836 	{
4837 	  GPtrArray *signals = (GPtrArray *)value;
4838 	  gint i;
4839 
4840 	  for (i = 0; i < signals->len; i++)
4841 	    {
4842 	      GladeSignal *signal = g_ptr_array_index (signals, i);
4843 
4844 	      if (glade_signal_get_support_warning (signal))
4845 		warn_signals = g_list_prepend (warn_signals, signal);
4846 	    }
4847 	}
4848 
4849       /* Collect properties with warnings on them */
4850       for (l = priv->properties; l; l = g_list_next (l))
4851 	{
4852 	  GladeProperty *property = l->data;
4853 
4854 	  if (glade_property_warn_usage (property))
4855 	    warn_properties = g_list_prepend (warn_properties, property);
4856 	}
4857 
4858       for (l = priv->packing_properties; l; l = g_list_next (l))
4859 	{
4860 	  GladeProperty *property = l->data;
4861 
4862 	  if (glade_property_warn_usage (property))
4863 	    warn_properties = g_list_prepend (warn_properties, property);
4864 	}
4865 
4866       if (warn_signals || warn_properties)
4867 	string = g_string_new (NULL);
4868 
4869       /* Print out property warnings */
4870       for (l = warn_properties; l; l = g_list_next (l))
4871 	{
4872 	  GladeProperty *property = l->data;
4873 	  GladePropertyClass *pclass = glade_property_get_class (property);
4874 
4875 	  if (l->prev == NULL)
4876 	    {
4877 	      if (l->next == NULL)
4878 		g_string_append (string, _("Property has versioning problems: "));
4879 	      else
4880 		g_string_append (string, _("Some properties have versioning problems: "));
4881 	    }
4882 	  else
4883 	    g_string_append (string, ", ");
4884 
4885 	  g_string_append (string, glade_property_class_get_name (pclass));
4886 	}
4887 
4888       /* New line if printing both */
4889       if (warn_signals && warn_properties)
4890 	g_string_append (string, "\n");
4891 
4892       /* Print out signal warnings */
4893       for (l = warn_signals; l; l = g_list_next (l))
4894 	{
4895 	  GladeSignal *signal = l->data;
4896 
4897 	  if (l->prev == NULL)
4898 	    {
4899 	      if (l->next == NULL)
4900 		g_string_append (string, _("Signal has versioning problems: "));
4901 	      else
4902 		g_string_append (string, _("Some signals have versioning problems: "));
4903 	    }
4904 	  else
4905 	    g_string_append (string, ", ");
4906 
4907 	  g_string_append (string, glade_signal_get_name (signal));
4908 	}
4909 
4910       if (string)
4911 	warning = g_string_free (string, FALSE);
4912     }
4913 
4914   glade_widget_set_support_warning (widget, warning);
4915   g_free (warning);
4916 }
4917 
4918 void
glade_widget_set_support_warning(GladeWidget * widget,const gchar * warning)4919 glade_widget_set_support_warning (GladeWidget *widget, const gchar *warning)
4920 {
4921   g_return_if_fail (GLADE_IS_WIDGET (widget));
4922 
4923   if (widget->priv->support_warning)
4924     g_free (widget->priv->support_warning);
4925   widget->priv->support_warning = g_strdup (warning);
4926 
4927   if (widget->priv->project &&
4928       glade_project_has_object (widget->priv->project, widget->priv->object))
4929     glade_project_widget_changed (widget->priv->project, widget);
4930 
4931   g_object_notify_by_pspec (G_OBJECT (widget), properties[PROP_SUPPORT_WARNING]);
4932 }
4933 
4934 G_CONST_RETURN gchar *
glade_widget_support_warning(GladeWidget * widget)4935 glade_widget_support_warning (GladeWidget *widget)
4936 {
4937   g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
4938 
4939   return widget->priv->support_warning;
4940 }
4941 
4942 /**
4943  * glade_widget_lock:
4944  * @widget: A #GladeWidget
4945  * @locked: The #GladeWidget to lock
4946  *
4947  * Sets @locked to be in a locked up state
4948  * spoken for by @widget, locked widgets cannot
4949  * be removed from the project until unlocked.
4950  *
4951  */
4952 void
glade_widget_lock(GladeWidget * widget,GladeWidget * locked)4953 glade_widget_lock (GladeWidget *widget, GladeWidget *locked)
4954 {
4955   g_return_if_fail (GLADE_IS_WIDGET (widget));
4956   g_return_if_fail (GLADE_IS_WIDGET (locked));
4957   g_return_if_fail (locked->priv->lock == NULL);
4958 
4959   locked->priv->lock = widget;
4960   widget->priv->locked_widgets = g_list_prepend (widget->priv->locked_widgets, locked);
4961 }
4962 
4963 /**
4964  * glade_widget_unlock:
4965  * @widget: A #GladeWidget
4966  *
4967  * Unlocks @widget so that it can be removed
4968  * from the project again
4969  *
4970  */
4971 void
glade_widget_unlock(GladeWidget * widget)4972 glade_widget_unlock (GladeWidget *widget)
4973 {
4974   GladeWidget *lock;
4975 
4976   g_return_if_fail (GLADE_IS_WIDGET (widget));
4977   g_return_if_fail (GLADE_IS_WIDGET (widget->priv->lock));
4978 
4979   lock = widget->priv->lock;
4980 
4981   lock->priv->locked_widgets =
4982     g_list_remove (lock->priv->locked_widgets, widget);
4983 
4984   widget->priv->lock = NULL;
4985 }
4986 
4987 
4988 GladeWidget *
glade_widget_get_locker(GladeWidget * widget)4989 glade_widget_get_locker (GladeWidget *widget)
4990 {
4991   g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
4992 
4993   return widget->priv->lock;
4994 }
4995 
4996 GList *
glade_widget_list_locked_widgets(GladeWidget * widget)4997 glade_widget_list_locked_widgets (GladeWidget *widget)
4998 {
4999   g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
5000 
5001   return g_list_copy (widget->priv->locked_widgets);
5002 }
5003 
5004 
5005 /**
5006  * glade_widget_support_changed:
5007  * @widget: A #GladeWidget
5008  *
5009  * Notifies that support metadata has changed on the widget.
5010  *
5011  */
5012 void
glade_widget_support_changed(GladeWidget * widget)5013 glade_widget_support_changed (GladeWidget *widget)
5014 {
5015   g_return_if_fail (GLADE_IS_WIDGET (widget));
5016 
5017   g_signal_emit (widget, glade_widget_signals[SUPPORT_CHANGED], 0);
5018 }
5019 
5020 /**
5021  * glade_widget_get_signal_model:
5022  * @widget: A #GladeWidget
5023  *
5024  * Returns: a GtkTreeModel that can be used to view the widget's signals.
5025  *          The signal model is owned by the #GladeWidget.
5026  */
5027 GtkTreeModel *
glade_widget_get_signal_model(GladeWidget * widget)5028 glade_widget_get_signal_model (GladeWidget *widget)
5029 {
5030 	if (!widget->priv->signal_model)
5031 	{
5032 		widget->priv->signal_model = glade_signal_model_new (widget,
5033                                                          widget->priv->signals);
5034 	}
5035 	return widget->priv->signal_model;
5036 }
5037 
5038 GList *
glade_widget_get_properties(GladeWidget * widget)5039 glade_widget_get_properties (GladeWidget *widget)
5040 {
5041   g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
5042 
5043   return widget->priv->properties;
5044 }
5045 
5046 GList *
glade_widget_get_packing_properties(GladeWidget * widget)5047 glade_widget_get_packing_properties (GladeWidget *widget)
5048 {
5049   g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
5050 
5051   return widget->priv->packing_properties;
5052 }
5053 
5054 void
glade_widget_ensure_name(GladeWidget * widget,GladeProject * project,gboolean use_command)5055 glade_widget_ensure_name (GladeWidget      *widget,
5056 			  GladeProject     *project,
5057 			  gboolean          use_command)
5058 {
5059   if (!glade_widget_has_name (widget))
5060     {
5061       gchar *new_name = glade_project_new_widget_name (project, NULL,
5062 						       glade_widget_adaptor_get_generic_name (widget->priv->adaptor));
5063 
5064       if (use_command)
5065 	glade_command_set_name (widget, new_name);
5066       else
5067 	glade_widget_set_name (widget, new_name);
5068 
5069       g_free (new_name);
5070     }
5071 }
5072