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 (¶meter.value, pspec[i]->value_type);
649 g_value_copy (glade_property_inline_value (glade_property), ¶meter.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