mirror of
https://gitlab.gnome.org/GNOME/glade.git
synced 2025-10-04 00:03:06 -04:00
2004-04-21 Joaquin Cuenca Abela <e98cuenc@yahoo.com> * pixmaps/fontselectiondialog.png, [vh]paned.png, messagedialog.png: fix 3 bad pixels in the shadow of these icons. * src/glade-clipboard-view.c, glade-editor.c, glade-project-view.c, glade-widget-class.h: account for changes on GladeWidget. * src/glade-command.[ch]: account for changes on GladeWidget, and add a new command for add/remove signal handlers. * src/glade-signal.[ch]: rename glade_signal_compare by glade_signal_equal and glade_signal_copy by glade_signal_clone. * src/glade-utils.[ch]: move glade_util_replace_placeholder in a generalized form to glade-widget.c. Make glade_util_get_parent work even for toplevels. New glade_util_object_set_property function to set a property on a GladeWidget using the set_property specified in GladeWidgetClass if any (or g_object_set_property otherwise). * src/glade-widget.[ch]: rewritten from scratch as a GObject. It exposes a new API. It also fixes several bugs. * src/glade-property.[ch]: account for changes on GladeWidget, and assure that we don't assing a widget with an ID higher than needed. * src/glade-signal-editor.[ch]: account for changes on glade-widget.c. The API for adding/changing/removing signals handlers has changed, so this file is quite affected. Chop the biggests functions for clarity. Account for the new command add/remove signal handler (to get TODO/REDO functionality). * src/glade-placeholder.c: fix the destruction of placeholders that don't reach the realized stage. * src/glade-gtk.c: move much of the fill empty functions to post create, querying for properties as size, nb-rows, etc. when needed. Add some placeholders to the action area of a dialog box. * src/glade-clipboard.[ch]: As glade-widget now has a reference count, remove glade_clipboard_add_copy, and use only glade_clipboard_add. * src/glade-popup.c, glade-project-window.c: Account for changes on glade-clipboard.c. * widgets/gtk-base.xml: Add a file for GtkLabel and GtkFrame. * widgets/gtk-box.xml: remove the fill empty function and add a post create function (post create will query the number of items in the box and add the placeholders). * widgets/gtkbutton.xml, gtklabel.xml, gtktogglebutton.xml, gtkcheckbutton.xml, gtkradiobutton.xml: Add a default label. * widgets/gtktable.xml: simplify and remove fill empty (post create will do the work, querying for the number of rows and columns). * widgets/gtkframe.xml: simplify and set a default label.
1323 lines
36 KiB
C
1323 lines
36 KiB
C
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
|
/*
|
|
* Copyright (C) 2004 Joaquin Cuenca Abela
|
|
* Copyright (C) 2001, 2002, 2003 Ximian, Inc.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
* Authors:
|
|
* Joaquin Cuenca Abela <e98cuenc@yahoo.com>
|
|
* Chema Celorio <chema@celorio.com>
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <glib-object.h>
|
|
#include "glade.h"
|
|
#include "glade-project.h"
|
|
#include "glade-widget-class.h"
|
|
#include "glade-widget.h"
|
|
#include "glade-marshallers.h"
|
|
#include "glade-property.h"
|
|
#include "glade-property-class.h"
|
|
#include "glade-placeholder.h"
|
|
#include "glade-signal.h"
|
|
#include "glade-popup.h"
|
|
#include <glib.h>
|
|
#include <gdk/gdkkeysyms.h>
|
|
|
|
static void glade_widget_class_init (GladeWidgetKlass *klass);
|
|
static void glade_widget_init (GladeWidget *widget);
|
|
static void glade_widget_finalize (GObject *object);
|
|
static void glade_widget_dispose (GObject *object);
|
|
static void glade_widget_set_real_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
|
|
static void glade_widget_get_real_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
|
|
static void glade_widget_set_class (GladeWidget *widget, GladeWidgetClass *klass);
|
|
static void glade_widget_real_add_signal_handler (GladeWidget *widget, GladeSignal *signal_handler);
|
|
static void glade_widget_real_remove_signal_handler (GladeWidget *widget, GladeSignal *signal_handler);
|
|
static void glade_widget_real_change_signal_handler (GladeWidget *widget, GladeSignal *old_signal_handler, GladeSignal *new_signal_handler);
|
|
static void glade_widget_set_packing_properties (GladeWidget *widget, GladeWidget *container);
|
|
|
|
enum
|
|
{
|
|
ADD_SIGNAL_HANDLER,
|
|
REMOVE_SIGNAL_HANDLER,
|
|
CHANGE_SIGNAL_HANDLER,
|
|
LAST_SIGNAL
|
|
};
|
|
|
|
enum
|
|
{
|
|
PROP_0,
|
|
PROP_NAME,
|
|
PROP_INTERNAL,
|
|
PROP_WIDGET,
|
|
PROP_CLASS,
|
|
PROP_PROJECT
|
|
};
|
|
|
|
static guint glade_widget_signals[LAST_SIGNAL] = {0};
|
|
static GObjectClass *parent_class = NULL;
|
|
|
|
GType
|
|
glade_widget_get_type (void)
|
|
{
|
|
static GType widget_type = 0;
|
|
|
|
if (!widget_type)
|
|
{
|
|
static const GTypeInfo widget_info =
|
|
{
|
|
sizeof (GladeWidgetKlass),
|
|
NULL, /* base_init */
|
|
NULL, /* base_finalize */
|
|
(GClassInitFunc) glade_widget_class_init,
|
|
NULL, /* class_finalize */
|
|
NULL, /* class_data */
|
|
sizeof (GladeWidget),
|
|
0, /* n_preallocs */
|
|
(GInstanceInitFunc) glade_widget_init,
|
|
};
|
|
|
|
widget_type = g_type_register_static (G_TYPE_OBJECT, "Gladewidget",
|
|
&widget_info, 0);
|
|
}
|
|
|
|
return widget_type;
|
|
}
|
|
|
|
static void
|
|
glade_widget_class_init (GladeWidgetKlass *klass)
|
|
{
|
|
GObjectClass *object_class;
|
|
|
|
object_class = G_OBJECT_CLASS (klass);
|
|
parent_class = g_type_class_peek_parent (klass);
|
|
|
|
object_class->finalize = glade_widget_finalize;
|
|
object_class->dispose = glade_widget_dispose;
|
|
object_class->set_property = glade_widget_set_real_property;
|
|
object_class->get_property = glade_widget_get_real_property;
|
|
|
|
klass->add_signal_handler = glade_widget_real_add_signal_handler;
|
|
klass->remove_signal_handler = glade_widget_real_remove_signal_handler;
|
|
klass->change_signal_handler = glade_widget_real_change_signal_handler;
|
|
|
|
g_object_class_install_property (object_class, PROP_NAME,
|
|
g_param_spec_string ("name", _("Name"), _("The name of the widget"),
|
|
NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
|
g_object_class_install_property (object_class, PROP_INTERNAL,
|
|
g_param_spec_string ("internal", _("Internal name"), _("The internal name of the widget"),
|
|
NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
|
g_object_class_install_property (object_class, PROP_WIDGET,
|
|
g_param_spec_object ("widget", _("Widget"), _("The gtk+ widget associated"),
|
|
GTK_TYPE_WIDGET, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
|
g_object_class_install_property (object_class, PROP_CLASS,
|
|
g_param_spec_pointer ("class", _("Class"), _("The class of the associated gtk+ widget"),
|
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
|
|
g_object_class_install_property (object_class, PROP_PROJECT,
|
|
g_param_spec_object ("project", _("Project"), _("The glade project that this widget belongs to"),
|
|
GLADE_TYPE_PROJECT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
|
glade_widget_signals[ADD_SIGNAL_HANDLER] =
|
|
g_signal_new ("add_signal_handler",
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (GladeWidgetKlass, add_signal_handler),
|
|
NULL, NULL,
|
|
g_cclosure_marshal_VOID__POINTER,
|
|
G_TYPE_NONE,
|
|
1,
|
|
G_TYPE_POINTER);
|
|
glade_widget_signals[REMOVE_SIGNAL_HANDLER] =
|
|
g_signal_new ("remove_signal_handler",
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (GladeWidgetKlass, remove_signal_handler),
|
|
NULL, NULL,
|
|
g_cclosure_marshal_VOID__POINTER,
|
|
G_TYPE_NONE,
|
|
1,
|
|
G_TYPE_POINTER);
|
|
glade_widget_signals[CHANGE_SIGNAL_HANDLER] =
|
|
g_signal_new ("change_signal_handler",
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (GladeWidgetKlass, change_signal_handler),
|
|
NULL, NULL,
|
|
glade_cclosure_marshal_VOID__POINTER_POINTER,
|
|
G_TYPE_NONE,
|
|
2,
|
|
G_TYPE_POINTER, G_TYPE_POINTER);
|
|
}
|
|
|
|
static void
|
|
free_signals (gpointer value)
|
|
{
|
|
GPtrArray *signals = (GPtrArray*) value;
|
|
guint i;
|
|
guint nb_signals;
|
|
|
|
if (signals == NULL)
|
|
return;
|
|
|
|
/* g_ptr_array_foreach (signals, (GFunc) glade_signal_free, NULL); only available in modern versions of Gtk+ */
|
|
nb_signals = signals->len;
|
|
for (i = 0; i < nb_signals; i++)
|
|
glade_signal_free (g_ptr_array_index (signals, i));
|
|
|
|
g_ptr_array_free (signals, TRUE);
|
|
}
|
|
|
|
static void
|
|
glade_widget_init (GladeWidget *widget)
|
|
{
|
|
widget->widget_class = NULL;
|
|
widget->project = NULL;
|
|
widget->name = NULL;
|
|
widget->internal = NULL;
|
|
widget->widget = NULL;
|
|
widget->properties = NULL;
|
|
widget->packing_properties = NULL;
|
|
widget->signals = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) free_signals);
|
|
}
|
|
|
|
GladeWidget *
|
|
glade_widget_new (GladeWidgetClass *klass, GladeProject *project)
|
|
{
|
|
GObject *widget = g_object_new (klass->type, NULL);
|
|
|
|
return (GladeWidget *) g_object_new (GLADE_TYPE_WIDGET,
|
|
"class", klass,
|
|
"project", project,
|
|
"name", glade_project_new_widget_name (project, klass->generic_name),
|
|
"widget", widget,
|
|
NULL);
|
|
}
|
|
|
|
GladeWidget *
|
|
glade_widget_new_for_internal_child (GladeWidgetClass *klass, GladeWidget *parent, GtkWidget *internal_widget, const char *internal_name)
|
|
{
|
|
GladeProject *project = glade_widget_get_project (parent);
|
|
return (GladeWidget *) g_object_new (GLADE_TYPE_WIDGET,
|
|
"class", klass,
|
|
"project", project,
|
|
"name", glade_project_new_widget_name (project, klass->generic_name),
|
|
"internal", internal_name,
|
|
"widget", internal_widget, NULL);
|
|
}
|
|
|
|
static void
|
|
glade_widget_finalize (GObject *object)
|
|
{
|
|
GladeWidget *widget = GLADE_WIDGET (object);
|
|
|
|
g_return_if_fail (GLADE_IS_WIDGET (object));
|
|
|
|
glade_widget_class_free (widget->widget_class);
|
|
g_free (widget->name);
|
|
g_free (widget->internal);
|
|
g_object_unref (widget->signals);
|
|
}
|
|
|
|
static void
|
|
glade_widget_dispose (GObject *object)
|
|
{
|
|
GladeWidget *widget = GLADE_WIDGET (object);
|
|
|
|
g_return_if_fail (GLADE_IS_WIDGET (object));
|
|
|
|
if (widget->project)
|
|
g_object_unref (widget->project);
|
|
|
|
if (widget->widget)
|
|
g_object_unref (widget->widget);
|
|
|
|
if (widget->properties)
|
|
g_list_foreach (widget->properties, (GFunc) g_object_unref, NULL);
|
|
g_list_free (widget->properties);
|
|
|
|
if (widget->packing_properties)
|
|
g_list_foreach (widget->packing_properties, (GFunc) g_object_unref, NULL);
|
|
g_list_free (widget->packing_properties);
|
|
|
|
widget->project = NULL;
|
|
widget->widget = NULL;
|
|
widget->properties = NULL;
|
|
widget->packing_properties = NULL;
|
|
}
|
|
|
|
void
|
|
glade_widget_add_signal_handler (GladeWidget *widget, GladeSignal *signal_handler)
|
|
{
|
|
g_return_if_fail (GLADE_IS_WIDGET (widget));
|
|
|
|
g_signal_emit (widget, glade_widget_signals[ADD_SIGNAL_HANDLER], 0, signal_handler);
|
|
}
|
|
|
|
void
|
|
glade_widget_remove_signal_handler (GladeWidget *widget, GladeSignal *signal_handler)
|
|
{
|
|
g_return_if_fail (GLADE_IS_WIDGET (widget));
|
|
|
|
g_signal_emit (widget, glade_widget_signals[REMOVE_SIGNAL_HANDLER], 0, signal_handler);
|
|
}
|
|
|
|
void
|
|
glade_widget_change_signal_handler (GladeWidget *widget, GladeSignal *old_signal_handler, GladeSignal *new_signal_handler)
|
|
{
|
|
g_return_if_fail (GLADE_IS_WIDGET (widget));
|
|
|
|
g_signal_emit (widget, glade_widget_signals[CHANGE_SIGNAL_HANDLER], 0, old_signal_handler, new_signal_handler);
|
|
}
|
|
|
|
static void
|
|
glade_widget_set_real_property (GObject *object,
|
|
guint prop_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GladeWidget *widget;
|
|
|
|
widget = GLADE_WIDGET (object);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_NAME:
|
|
glade_widget_set_name (widget, g_value_get_string (value));
|
|
break;
|
|
case PROP_INTERNAL:
|
|
glade_widget_set_internal (widget, g_value_get_string (value));
|
|
break;
|
|
case PROP_WIDGET:
|
|
glade_widget_set_widget (widget, GTK_WIDGET (g_value_get_object (value)));
|
|
break;
|
|
case PROP_PROJECT:
|
|
glade_widget_set_project (widget, GLADE_PROJECT (g_value_get_object (value)));
|
|
break;
|
|
case PROP_CLASS:
|
|
glade_widget_set_class (widget, GLADE_WIDGET_CLASS (g_value_get_pointer (value)));
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
glade_widget_get_real_property (GObject *object,
|
|
guint prop_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GladeWidget *widget;
|
|
|
|
widget = GLADE_WIDGET (object);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_NAME:
|
|
g_value_set_string (value, widget->name);
|
|
break;
|
|
case PROP_INTERNAL:
|
|
g_value_set_string (value, widget->internal);
|
|
break;
|
|
case PROP_CLASS:
|
|
g_value_set_pointer (value, widget->widget_class);
|
|
break;
|
|
case PROP_PROJECT:
|
|
g_value_set_object (value, widget->project);
|
|
break;
|
|
case PROP_WIDGET:
|
|
g_value_set_object (value, widget->widget);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
glade_widget_set_name (GladeWidget *widget, const char *name)
|
|
{
|
|
if (widget->name)
|
|
g_free (widget->name);
|
|
|
|
widget->name = g_strdup (name);
|
|
g_object_notify (G_OBJECT (widget), "name");
|
|
}
|
|
|
|
const char *
|
|
glade_widget_get_name (GladeWidget *widget)
|
|
{
|
|
g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
|
|
return widget->name;
|
|
}
|
|
|
|
void
|
|
glade_widget_set_internal (GladeWidget *widget, const char *internal)
|
|
{
|
|
if (widget->internal)
|
|
g_free (widget->internal);
|
|
|
|
widget->internal = g_strdup (internal);
|
|
g_object_notify (G_OBJECT (widget), "internal");
|
|
}
|
|
|
|
const char *
|
|
glade_widget_get_internal (GladeWidget *widget)
|
|
{
|
|
g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
|
|
return widget->internal;
|
|
}
|
|
|
|
static void
|
|
glade_widget_set_class (GladeWidget *widget, GladeWidgetClass *klass)
|
|
{
|
|
GladePropertyClass *property_class;
|
|
GladeProperty *property;
|
|
GList *list = klass->properties;
|
|
|
|
g_return_if_fail (GLADE_IS_WIDGET (widget));
|
|
g_return_if_fail (GLADE_IS_WIDGET_CLASS (klass));
|
|
/* calling set_class out of the constructor? */
|
|
g_return_if_fail (widget->widget_class == NULL);
|
|
|
|
// g_object_ref (klass); TODO, GladeWidgetClass is not a GObject
|
|
widget->widget_class = klass;
|
|
|
|
for (; list; list = list->next)
|
|
{
|
|
property_class = list->data;
|
|
property = glade_property_new (property_class, widget);
|
|
if (!property)
|
|
continue;
|
|
|
|
widget->properties = g_list_prepend (widget->properties, property);
|
|
}
|
|
|
|
widget->properties = g_list_reverse (widget->properties);
|
|
}
|
|
|
|
GladeWidgetClass *
|
|
glade_widget_get_class (GladeWidget *widget)
|
|
{
|
|
g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
|
|
return widget->widget_class;
|
|
}
|
|
|
|
void
|
|
glade_widget_set_project (GladeWidget *widget, GladeProject *project)
|
|
{
|
|
if (widget->project)
|
|
g_object_unref (widget->project);
|
|
|
|
g_object_ref (project);
|
|
widget->project = project;
|
|
g_object_notify (G_OBJECT (widget), "project");
|
|
}
|
|
|
|
GladeProject *
|
|
glade_widget_get_project (GladeWidget *widget)
|
|
{
|
|
g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
|
|
return widget->project;
|
|
}
|
|
|
|
GladeProperty *
|
|
glade_widget_get_property (GladeWidget *widget, const char *id_property)
|
|
{
|
|
GList *list;
|
|
GladeProperty *property;
|
|
|
|
g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
|
|
g_return_val_if_fail (id_property != NULL, NULL);
|
|
|
|
list = widget->properties;
|
|
for (; list; list = list->next)
|
|
{
|
|
property = list->data;
|
|
if (strcmp (property->class->id, id_property) == 0)
|
|
return property;
|
|
}
|
|
|
|
list = widget->packing_properties;
|
|
for (; list; list = list->next)
|
|
{
|
|
property = list->data;
|
|
if (strcmp (property->class->id, id_property) == 0)
|
|
return property;
|
|
}
|
|
|
|
g_warning ("Could not get property %s for widget %s\n",
|
|
id_property, widget->name);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static gboolean
|
|
glade_widget_popup_menu (GtkWidget *widget, gpointer unused_data)
|
|
{
|
|
GladeWidget *glade_widget;
|
|
|
|
g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
|
|
|
|
glade_widget = glade_widget_get_from_gtk_widget (widget);
|
|
glade_popup_widget_pop (glade_widget, NULL);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* A temp data struct that we use when looking for a widget inside a container
|
|
* we need a struct, because the forall can only pass one pointer
|
|
*/
|
|
typedef struct {
|
|
gint x;
|
|
gint y;
|
|
GtkWidget *found;
|
|
GtkWidget *toplevel;
|
|
} GladeFindInContainerData;
|
|
|
|
static void
|
|
glade_widget_find_inside_container (GtkWidget *widget, GladeFindInContainerData *data)
|
|
{
|
|
int x;
|
|
int y;
|
|
|
|
gtk_widget_translate_coordinates (data->toplevel, widget, data->x, data->y, &x, &y);
|
|
if (x >= 0 && x < widget->allocation.width && y >= 0 && y < widget->allocation.height &&
|
|
(glade_widget_get_from_gtk_widget (widget) || GLADE_IS_PLACEHOLDER (widget)))
|
|
data->found = widget;
|
|
}
|
|
|
|
static GladeWidget *
|
|
glade_widget_find_deepest_child_at_position (GtkContainer *toplevel, GtkContainer *container, int top_x, int top_y)
|
|
{
|
|
GladeFindInContainerData data;
|
|
data.x = top_x;
|
|
data.y = top_y;
|
|
data.toplevel = GTK_WIDGET (toplevel);
|
|
data.found = NULL;
|
|
|
|
gtk_container_forall (container, (GtkCallback) glade_widget_find_inside_container, &data);
|
|
|
|
if (data.found && GTK_IS_CONTAINER (data.found))
|
|
return glade_widget_find_deepest_child_at_position (toplevel, GTK_CONTAINER (data.found), top_x, top_y);
|
|
else
|
|
return glade_widget_get_from_gtk_widget (container);
|
|
}
|
|
|
|
/**
|
|
* glade_widget_retrieve_from_position:
|
|
* @base:
|
|
* @x:
|
|
* @y:
|
|
*
|
|
* Returns the real widget that was "clicked over" for a given event (coordinates) and a widget
|
|
* For example, when a label is clicked the button press event is triggered for its parent, this
|
|
* function takes the event and the widget that got the event and returns the real GladeWidget that was
|
|
* clicked
|
|
*
|
|
* Return Value:
|
|
**/
|
|
static GladeWidget *
|
|
glade_widget_retrieve_from_position (GtkWidget *base, int x, int y)
|
|
{
|
|
GtkWidget *toplevel_widget;
|
|
gint top_x;
|
|
gint top_y;
|
|
|
|
toplevel_widget = gtk_widget_get_toplevel (base);
|
|
if (!GTK_WIDGET_TOPLEVEL (toplevel_widget))
|
|
return NULL;
|
|
|
|
gtk_widget_translate_coordinates (base, toplevel_widget, x, y, &top_x, &top_y);
|
|
return glade_widget_find_deepest_child_at_position (GTK_CONTAINER (toplevel_widget), GTK_CONTAINER (toplevel_widget), top_x, top_y);
|
|
}
|
|
|
|
static gboolean
|
|
glade_widget_button_press (GtkWidget *widget,
|
|
GdkEventButton *event,
|
|
gpointer unused_data)
|
|
{
|
|
double x = event->x;
|
|
double y = event->y;
|
|
GladeWidget *glade_widget;
|
|
|
|
glade_widget = glade_widget_retrieve_from_position (widget, (int) (x + 0.5), (int) (y + 0.5));
|
|
widget = glade_widget_get_widget (glade_widget);
|
|
|
|
/* make sure to grab focus, since we may stop default handlers */
|
|
if (GTK_WIDGET_CAN_FOCUS (widget) && !GTK_WIDGET_HAS_FOCUS (widget))
|
|
gtk_widget_grab_focus (widget);
|
|
|
|
if (event->type != GDK_BUTTON_PRESS)
|
|
return FALSE;
|
|
|
|
if (event->button == 1)
|
|
{
|
|
/* if it's already selected don't stop default handlers, e.g. toggle button */
|
|
if (glade_util_has_nodes (widget))
|
|
return FALSE;
|
|
|
|
glade_project_selection_set (glade_widget->project, widget, TRUE);
|
|
return TRUE;
|
|
}
|
|
else if (event->button == 3)
|
|
{
|
|
glade_popup_widget_pop (glade_widget, event);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
glade_widget_key_press (GtkWidget *event_widget,
|
|
GdkEventKey *event,
|
|
gpointer unused_data)
|
|
{
|
|
GladeWidget *glade_widget;
|
|
|
|
g_return_val_if_fail (GTK_IS_WIDGET (event_widget), FALSE);
|
|
|
|
glade_widget = glade_widget_get_from_gtk_widget (event_widget);
|
|
|
|
/* We will delete all the selected items */
|
|
if (event->keyval == GDK_Delete)
|
|
{
|
|
glade_util_delete_selection (glade_widget_get_project (glade_widget));
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
glade_widget_apply_properties (GladeWidget *glade_widget)
|
|
{
|
|
GList *properties;
|
|
GtkWidget *widget;
|
|
GObject *object;
|
|
|
|
g_return_if_fail (GLADE_IS_WIDGET (glade_widget));
|
|
g_return_if_fail (glade_widget->properties != NULL);
|
|
|
|
properties = glade_widget->properties;
|
|
widget = glade_widget->widget;
|
|
object = G_OBJECT (widget);
|
|
g_object_freeze_notify (object);
|
|
|
|
while (properties != NULL)
|
|
{
|
|
glade_util_object_set_property (object, GLADE_PROPERTY (properties->data));
|
|
properties = properties->next;
|
|
}
|
|
|
|
g_object_thaw_notify (G_OBJECT (widget));
|
|
}
|
|
|
|
static void
|
|
glade_widget_retrieve_properties (GladeWidget *glade_widget)
|
|
{
|
|
GList *properties;
|
|
GtkWidget *widget;
|
|
GObject *object;
|
|
|
|
g_return_if_fail (GLADE_IS_WIDGET (glade_widget));
|
|
g_return_if_fail (glade_widget->properties != NULL);
|
|
|
|
properties = glade_widget->properties;
|
|
widget = glade_widget->widget;
|
|
object = G_OBJECT (widget);
|
|
|
|
while (properties != NULL)
|
|
{
|
|
GladeProperty *property = GLADE_PROPERTY (properties->data);
|
|
GladePropertyClass *property_class = property->class;
|
|
|
|
g_value_reset (property->value);
|
|
g_object_get_property (object, property_class->id, property->value);
|
|
|
|
properties = properties->next;
|
|
}
|
|
|
|
g_object_thaw_notify (G_OBJECT (widget));
|
|
}
|
|
|
|
void
|
|
glade_widget_set_widget (GladeWidget *glade_widget, GtkWidget *widget_gtk)
|
|
{
|
|
GladeWidgetClass *klass;
|
|
|
|
g_return_if_fail (GLADE_IS_WIDGET (glade_widget));
|
|
g_return_if_fail (GTK_IS_WIDGET (widget_gtk));
|
|
g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (widget_gtk), glade_widget->widget_class->type));
|
|
|
|
if (glade_widget->widget)
|
|
{
|
|
g_object_set_data (G_OBJECT (glade_widget->widget), "GladeWidgetDataTag", NULL);
|
|
g_object_unref (glade_widget->widget);
|
|
}
|
|
|
|
g_object_ref (widget_gtk);
|
|
glade_widget->widget = widget_gtk;
|
|
g_object_set_data (G_OBJECT (widget_gtk), "GladeWidgetDataTag", glade_widget);
|
|
|
|
gtk_widget_add_events (widget_gtk, GDK_BUTTON_PRESS_MASK |
|
|
GDK_BUTTON_RELEASE_MASK |
|
|
GDK_KEY_PRESS_MASK);
|
|
|
|
if (GTK_WIDGET_TOPLEVEL (widget_gtk))
|
|
g_signal_connect (G_OBJECT (widget_gtk), "delete_event",
|
|
G_CALLBACK (gtk_widget_hide_on_delete), NULL);
|
|
|
|
g_signal_connect (G_OBJECT (widget_gtk), "popup_menu",
|
|
G_CALLBACK (glade_widget_popup_menu), NULL);
|
|
g_signal_connect (G_OBJECT (widget_gtk), "button_press_event",
|
|
G_CALLBACK (glade_widget_button_press), NULL);
|
|
g_signal_connect (G_OBJECT (widget_gtk), "key_press_event",
|
|
G_CALLBACK (glade_widget_key_press), NULL);
|
|
|
|
if (glade_widget->internal == NULL)
|
|
{
|
|
/* we should set the values of the properties of this widget from the
|
|
* default values that we gather from the class of this widget, and
|
|
* apply the post_create_function and fill_empty functions */
|
|
glade_widget_apply_properties (glade_widget);
|
|
|
|
klass = glade_widget->widget_class;
|
|
g_assert (klass != NULL);
|
|
if (klass->post_create_function)
|
|
klass->post_create_function (G_OBJECT (widget_gtk));
|
|
if (klass->fill_empty)
|
|
klass->fill_empty (GTK_WIDGET (widget_gtk));
|
|
}
|
|
else
|
|
{
|
|
GladeWidget *parent = glade_widget_get_parent (glade_widget);
|
|
|
|
/* set packing properties */
|
|
glade_widget_set_packing_properties (glade_widget, parent);
|
|
|
|
}
|
|
|
|
g_object_notify (G_OBJECT (glade_widget), "widget");
|
|
}
|
|
|
|
GtkWidget *
|
|
glade_widget_get_widget (GladeWidget *widget)
|
|
{
|
|
g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
|
|
return widget->widget;
|
|
}
|
|
|
|
static void
|
|
glade_widget_real_add_signal_handler (GladeWidget *widget, GladeSignal *signal_handler)
|
|
{
|
|
GPtrArray *signals;
|
|
GladeSignal *new_signal_handler;
|
|
|
|
g_return_if_fail (GLADE_IS_WIDGET (widget));
|
|
g_return_if_fail (GLADE_IS_SIGNAL (signal_handler));
|
|
|
|
signals = glade_widget_list_signal_handlers (widget, signal_handler->name);
|
|
if (!signals)
|
|
{
|
|
signals = g_ptr_array_new ();
|
|
g_hash_table_insert (widget->signals, g_strdup (signal_handler->name), signals);
|
|
}
|
|
|
|
new_signal_handler = glade_signal_clone (signal_handler);
|
|
g_ptr_array_add (signals, new_signal_handler);
|
|
}
|
|
|
|
static void
|
|
glade_widget_real_remove_signal_handler (GladeWidget *widget, GladeSignal *signal_handler)
|
|
{
|
|
GPtrArray *signals;
|
|
GladeSignal *tmp_signal_handler;
|
|
size_t i;
|
|
|
|
g_return_if_fail (GLADE_IS_WIDGET (widget));
|
|
g_return_if_fail (GLADE_IS_SIGNAL (signal_handler));
|
|
|
|
signals = glade_widget_list_signal_handlers (widget, signal_handler->name);
|
|
|
|
/* trying to remove an inexistent signal? */
|
|
g_assert (signals);
|
|
|
|
for (i = 0; i < signals->len; i++)
|
|
{
|
|
tmp_signal_handler = g_ptr_array_index (signals, i);
|
|
if (glade_signal_equal (tmp_signal_handler, signal_handler))
|
|
break;
|
|
}
|
|
|
|
/* trying to remove an inexistent signal? */
|
|
g_assert(i != signals->len);
|
|
|
|
glade_signal_free (tmp_signal_handler);
|
|
g_ptr_array_remove_index (signals, i);
|
|
}
|
|
|
|
static void
|
|
glade_widget_real_change_signal_handler (GladeWidget *widget, GladeSignal *old_signal_handler, GladeSignal *new_signal_handler)
|
|
{
|
|
GPtrArray *signals;
|
|
GladeSignal *tmp_signal_handler;
|
|
size_t i;
|
|
|
|
g_return_if_fail (GLADE_IS_WIDGET (widget));
|
|
g_return_if_fail (GLADE_IS_SIGNAL (old_signal_handler));
|
|
g_return_if_fail (GLADE_IS_SIGNAL (new_signal_handler));
|
|
g_return_if_fail (strcmp (old_signal_handler->name, new_signal_handler->name) == 0);
|
|
|
|
signals = glade_widget_list_signal_handlers (widget, old_signal_handler->name);
|
|
/* trying to remove an inexistent signal? */
|
|
g_assert (signals);
|
|
|
|
for (i = 0; i < signals->len; i++)
|
|
{
|
|
tmp_signal_handler = g_ptr_array_index (signals, i);
|
|
if (glade_signal_equal (tmp_signal_handler, old_signal_handler))
|
|
break;
|
|
}
|
|
|
|
/* trying to remove an inexistent signal? */
|
|
g_assert (i != signals->len);
|
|
|
|
if (strcmp (old_signal_handler->handler, new_signal_handler->handler) != 0)
|
|
{
|
|
g_free (tmp_signal_handler->handler);
|
|
tmp_signal_handler->handler = g_strdup (new_signal_handler->handler);
|
|
}
|
|
|
|
tmp_signal_handler->after = new_signal_handler->after;
|
|
}
|
|
|
|
GPtrArray *
|
|
glade_widget_list_signal_handlers (GladeWidget *widget, const char *signal_name) /* array of GladeSignal* */
|
|
{
|
|
return g_hash_table_lookup (widget->signals, signal_name);
|
|
}
|
|
|
|
GladeWidget *
|
|
glade_widget_get_parent (GladeWidget *glade_widget)
|
|
{
|
|
GladeWidget *parent = NULL;
|
|
GtkWidget *parent_widget;
|
|
|
|
g_return_val_if_fail (GLADE_IS_WIDGET (glade_widget), NULL);
|
|
|
|
if (GTK_WIDGET_TOPLEVEL (glade_widget_get_widget (glade_widget)))
|
|
return NULL;
|
|
|
|
parent_widget = gtk_widget_get_parent (glade_widget_get_widget (glade_widget));
|
|
parent = glade_widget_get_from_gtk_widget (parent_widget);
|
|
|
|
return parent;
|
|
}
|
|
|
|
/**
|
|
* Returns a list of GladeProperties from a list of
|
|
* GladePropertyClass.
|
|
*/
|
|
static GList *
|
|
glade_widget_create_packing_properties (GladeWidget *container, GladeWidget *widget)
|
|
{
|
|
GladePropertyClass *property_class;
|
|
GladeProperty *property;
|
|
GladeWidgetClass *container_class = glade_widget_get_class (container);
|
|
GladeWidget *parent;
|
|
GList *list = container_class->child_properties;
|
|
GList *new_list = NULL;
|
|
GList *ancestor_list;
|
|
|
|
for (; list; list = list->next)
|
|
{
|
|
property_class = list->data;
|
|
|
|
if (!container_class->child_property_applies (container->widget, widget->widget, property_class->id))
|
|
continue;
|
|
|
|
property = glade_property_new (property_class, widget);
|
|
if (!property)
|
|
continue;
|
|
|
|
new_list = g_list_prepend (new_list, property);
|
|
}
|
|
|
|
new_list = g_list_reverse (new_list);
|
|
parent = glade_widget_get_parent (container);
|
|
if (parent != NULL)
|
|
{
|
|
ancestor_list = glade_widget_create_packing_properties (parent, widget);
|
|
new_list = g_list_concat (new_list, ancestor_list);
|
|
}
|
|
|
|
return new_list;
|
|
}
|
|
|
|
/**
|
|
* glade_widget_set_packing_properties:
|
|
* @widget:
|
|
* @container_class:
|
|
*
|
|
* Generates the packing_properties list of the widget, given
|
|
* the class of the container we are adding the widget to.
|
|
* If the widget already has packing_properties, but the container
|
|
* has changed, the current list is freed and replaced.
|
|
*/
|
|
static void
|
|
glade_widget_set_packing_properties (GladeWidget *widget,
|
|
GladeWidget *container)
|
|
{
|
|
GList *list;
|
|
|
|
g_return_if_fail (GLADE_IS_WIDGET (widget));
|
|
g_return_if_fail (GLADE_IS_WIDGET (container));
|
|
|
|
/* toplevels do not have packing properties, so should not be
|
|
* passed to this function.
|
|
*/
|
|
g_return_if_fail (!GTK_WIDGET_TOPLEVEL (widget->widget));
|
|
|
|
g_list_foreach (widget->packing_properties, (GFunc) glade_property_free, NULL);
|
|
g_list_free (widget->packing_properties);
|
|
widget->packing_properties = glade_widget_create_packing_properties (container, widget);
|
|
|
|
/* update the values of the properties to the ones we get from gtk */
|
|
for (list = widget->packing_properties; list; list = list->next)
|
|
{
|
|
GladeProperty *property = list->data;
|
|
|
|
g_value_reset (property->value);
|
|
if (gtk_container_class_find_child_property (G_OBJECT_GET_CLASS (container->widget), property->class->id))
|
|
gtk_container_child_get_property (GTK_CONTAINER (container->widget),
|
|
widget->widget,
|
|
property->class->id,
|
|
property->value);
|
|
}
|
|
}
|
|
|
|
void
|
|
glade_widget_replace (GtkWidget *old_widget, GtkWidget *new_widget)
|
|
{
|
|
GladeWidget *parent = NULL;
|
|
GladeWidget *gnew_widget = NULL;
|
|
GladeWidget *gold_widget = NULL;
|
|
GtkWidget *real_new_widget = new_widget;
|
|
GtkWidget *real_old_widget = old_widget;
|
|
|
|
g_return_if_fail (GTK_IS_WIDGET (old_widget));
|
|
g_return_if_fail (GTK_IS_WIDGET (new_widget));
|
|
|
|
gnew_widget = glade_widget_get_from_gtk_widget (new_widget);
|
|
gold_widget = glade_widget_get_from_gtk_widget (old_widget);
|
|
|
|
if (gnew_widget)
|
|
real_new_widget = glade_widget_get_widget (gnew_widget);
|
|
if (gold_widget)
|
|
real_old_widget = glade_widget_get_widget (gold_widget);
|
|
|
|
parent = glade_util_get_parent (old_widget);
|
|
g_assert (parent);
|
|
|
|
if (parent->widget_class->replace_child)
|
|
{
|
|
parent->widget_class->replace_child (real_old_widget, real_new_widget, glade_widget_get_widget (parent));
|
|
if (gnew_widget)
|
|
glade_widget_set_packing_properties (gnew_widget, parent);
|
|
}
|
|
else
|
|
g_warning ("Could not replace a placeholder because a replace "
|
|
" function has not been implemented for \"%s\"\n",
|
|
parent->widget_class->name);
|
|
}
|
|
|
|
/* XML Serialization */
|
|
static GladeXmlNode *
|
|
glade_widget_write_child (GladeXmlContext *context, GtkWidget *gtk_widget);
|
|
|
|
typedef struct _WriteSignalsContext
|
|
{
|
|
GladeXmlContext *context;
|
|
GladeXmlNode *node;
|
|
} WriteSignalsContext;
|
|
|
|
static void
|
|
glade_widget_write_signals (gpointer key, gpointer value, gpointer user_data)
|
|
{
|
|
WriteSignalsContext *write_signals_context = (WriteSignalsContext *) user_data;
|
|
GladeXmlNode *child;
|
|
size_t i;
|
|
|
|
GPtrArray *signals = (GPtrArray *) value;
|
|
for (i = 0; i < signals->len; i++)
|
|
{
|
|
GladeSignal *signal = g_ptr_array_index (signals, i);
|
|
child = glade_signal_write (write_signals_context->context, signal);
|
|
if (!child)
|
|
continue;
|
|
|
|
glade_xml_node_append_child (write_signals_context->node, child);
|
|
}
|
|
}
|
|
|
|
GladeXmlNode *
|
|
glade_widget_write (GladeWidget *widget, GladeXmlContext *context)
|
|
{
|
|
GladeXmlNode *node;
|
|
GladeXmlNode *child;
|
|
WriteSignalsContext write_signals_context;
|
|
GList *list;
|
|
|
|
g_return_val_if_fail (GLADE_XML_IS_CONTEXT (context), NULL);
|
|
g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
|
|
|
|
node = glade_xml_node_new (context, GLADE_XML_TAG_WIDGET);
|
|
|
|
glade_xml_node_set_property_string (node, GLADE_XML_TAG_CLASS, widget->widget_class->name);
|
|
glade_xml_node_set_property_string (node, GLADE_XML_TAG_ID, widget->name);
|
|
|
|
/* Write the properties */
|
|
list = widget->properties;
|
|
for (; list; list = list->next) {
|
|
GladeProperty *property = list->data;
|
|
if (property->class->packing)
|
|
continue;
|
|
|
|
child = glade_property_write (context, property);
|
|
if (!child)
|
|
continue;
|
|
|
|
glade_xml_node_append_child (node, child);
|
|
}
|
|
|
|
/* Signals */
|
|
write_signals_context.node = node;
|
|
write_signals_context.context = context;
|
|
g_hash_table_foreach (widget->signals, glade_widget_write_signals, &write_signals_context);
|
|
|
|
/* Children */
|
|
if (GTK_IS_CONTAINER (widget->widget)) {
|
|
list = glade_util_container_get_all_children (GTK_CONTAINER (widget->widget));
|
|
for (; list; list = list->next) {
|
|
GtkWidget *child_widget;
|
|
child_widget = GTK_WIDGET (list->data);
|
|
child = glade_widget_write_child (context, child_widget);
|
|
if (!child) {
|
|
continue;
|
|
}
|
|
glade_xml_node_append_child (node, child);
|
|
}
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
static GladeXmlNode *
|
|
glade_widget_write_child (GladeXmlContext *context, GtkWidget *gtk_widget)
|
|
{
|
|
GladeWidget *child_widget;
|
|
GladeXmlNode *child_tag; /* this is the <child> tag */
|
|
GladeXmlNode *child; /* this is the <widget> under <child> */
|
|
GladeXmlNode *packing;
|
|
GList *list;
|
|
|
|
child_tag = glade_xml_node_new (context, GLADE_XML_TAG_CHILD);
|
|
|
|
if (GLADE_IS_PLACEHOLDER (gtk_widget)) {
|
|
child = glade_xml_node_new (context, GLADE_XML_TAG_PLACEHOLDER);
|
|
glade_xml_node_append_child (child_tag, child);
|
|
|
|
return child_tag;
|
|
}
|
|
|
|
child_widget = glade_widget_get_from_gtk_widget (gtk_widget);
|
|
if (!child_widget)
|
|
return NULL;
|
|
|
|
if (child_widget->internal)
|
|
glade_xml_node_set_property_string (child_tag, GLADE_XML_TAG_INTERNAL_CHILD, child_widget->internal);
|
|
|
|
child = glade_widget_write (child_widget, context);
|
|
if (!child)
|
|
{
|
|
g_warning ("Failed to write child widget");
|
|
return NULL;
|
|
}
|
|
glade_xml_node_append_child (child_tag, child);
|
|
|
|
/* Append the packing properties */
|
|
packing = glade_xml_node_new (context, GLADE_XML_TAG_PACKING);
|
|
glade_xml_node_append_child (child_tag, packing);
|
|
list = child_widget->packing_properties;
|
|
for (; list; list = list->next) {
|
|
GladeProperty *property;
|
|
GladeXmlNode *packing_property;
|
|
property = list->data;
|
|
g_assert (property->class->packing == TRUE);
|
|
packing_property = glade_property_write (context, property);
|
|
if (!packing_property)
|
|
continue;
|
|
glade_xml_node_append_child (packing, packing_property);
|
|
}
|
|
|
|
return child_tag;
|
|
}
|
|
|
|
static gboolean
|
|
glade_widget_apply_property_from_node (GladeXmlNode *node,
|
|
GladeWidget *widget,
|
|
gboolean packing)
|
|
{
|
|
GladeProperty *property;
|
|
GValue *gvalue;
|
|
gchar *value;
|
|
gchar *id;
|
|
|
|
id = glade_xml_get_property_string_required (node, GLADE_XML_TAG_NAME, NULL);
|
|
value = glade_xml_get_content (node);
|
|
if (!value || !id)
|
|
return FALSE;
|
|
|
|
glade_util_replace (id, '_', '-');
|
|
property = glade_widget_get_property (widget, id);
|
|
if (!property)
|
|
return FALSE;
|
|
|
|
gvalue = glade_property_class_make_gvalue_from_string (property->class,
|
|
value);
|
|
glade_property_set (property, gvalue);
|
|
|
|
g_free (id);
|
|
g_free (value);
|
|
g_value_unset (gvalue);
|
|
g_free (gvalue);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
glade_widget_new_child_from_node (GladeXmlNode *node,
|
|
GladeProject *project,
|
|
GladeWidget *parent);
|
|
|
|
static void
|
|
glade_widget_fill_from_node (GladeXmlNode *node, GladeWidget *widget)
|
|
{
|
|
GladeXmlNode *child;
|
|
const gchar *class_name;
|
|
const gchar *widget_name;
|
|
|
|
g_return_if_fail (GLADE_IS_WIDGET (widget));
|
|
|
|
if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
|
|
return;
|
|
|
|
class_name = glade_xml_get_property_string_required (node, GLADE_XML_TAG_CLASS, NULL);
|
|
widget_name = glade_xml_get_property_string_required (node, GLADE_XML_TAG_ID, NULL);
|
|
if (!class_name || !widget_name)
|
|
return;
|
|
|
|
g_assert (strcmp (class_name, widget->widget_class->name) == 0);
|
|
glade_widget_set_name (widget, widget_name);
|
|
|
|
/* Children */
|
|
child = glade_xml_node_get_children (node);
|
|
for (; child; child = glade_xml_node_next (child)) {
|
|
if (!glade_xml_node_verify_silent (child, GLADE_XML_TAG_CHILD))
|
|
continue;
|
|
|
|
if (!glade_widget_new_child_from_node (child, widget->project, widget)) {
|
|
g_warning ("Failed to read child");
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/* Signals */
|
|
child = glade_xml_node_get_children (node);
|
|
for (; child; child = glade_xml_node_next (child)) {
|
|
GladeSignal *signal;
|
|
|
|
if (!glade_xml_node_verify_silent (child, GLADE_XML_TAG_SIGNAL))
|
|
continue;
|
|
|
|
signal = glade_signal_new_from_node (child);
|
|
if (!signal) {
|
|
g_warning ("Failed to read signal");
|
|
continue;
|
|
}
|
|
glade_widget_add_signal_handler (widget, signal);
|
|
}
|
|
|
|
/* Properties */
|
|
child = glade_xml_node_get_children (node);
|
|
for (; child; child = glade_xml_node_next (child)) {
|
|
if (!glade_xml_node_verify_silent (child, GLADE_XML_TAG_PROPERTY))
|
|
continue;
|
|
|
|
if (!glade_widget_apply_property_from_node (child, widget, FALSE)) {
|
|
g_warning ("Failed to apply property");
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
static GladeWidget *
|
|
glade_widget_new_from_node_real (GladeXmlNode *node,
|
|
GladeProject *project,
|
|
GladeWidget *parent)
|
|
{
|
|
GladeWidgetClass *class;
|
|
GladeWidget *widget;
|
|
const gchar *class_name;
|
|
|
|
if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
|
|
return NULL;
|
|
|
|
class_name = glade_xml_get_property_string_required (node, GLADE_XML_TAG_CLASS, NULL);
|
|
if (!class_name)
|
|
return NULL;
|
|
|
|
class = glade_widget_class_get_by_name (class_name);
|
|
if (!class)
|
|
return NULL;
|
|
|
|
widget = glade_widget_new (class, project);
|
|
if (!widget)
|
|
return NULL;
|
|
|
|
/* create the packing_properties list, without setting them */
|
|
if (parent)
|
|
widget->packing_properties = glade_widget_create_packing_properties (parent, widget);
|
|
|
|
glade_widget_fill_from_node (node, widget);
|
|
|
|
gtk_widget_show_all (widget->widget);
|
|
|
|
return widget;
|
|
}
|
|
|
|
/**
|
|
* When looking for an internal child we have to walk up the hierarchy...
|
|
*/
|
|
static GladeWidget *
|
|
glade_widget_get_internal_child (GladeWidget *parent,
|
|
const gchar *internal)
|
|
{
|
|
GladeWidget *ancestor;
|
|
GladeWidget *child = NULL;
|
|
|
|
ancestor = parent;
|
|
while (ancestor)
|
|
{
|
|
if (ancestor->widget_class->get_internal_child)
|
|
{
|
|
GtkWidget *widget;
|
|
ancestor->widget_class->get_internal_child (ancestor->widget, internal, &widget);
|
|
if (widget)
|
|
{
|
|
child = glade_widget_get_from_gtk_widget (widget);
|
|
if (child)
|
|
break;
|
|
}
|
|
}
|
|
ancestor = glade_widget_get_parent (ancestor);
|
|
}
|
|
|
|
return child;
|
|
}
|
|
|
|
static gboolean
|
|
glade_widget_new_child_from_node (GladeXmlNode *node,
|
|
GladeProject *project,
|
|
GladeWidget *parent)
|
|
{
|
|
gchar *internalchild;
|
|
GladeXmlNode *child_node;
|
|
GladeWidget *child;
|
|
|
|
if (!glade_xml_node_verify (node, GLADE_XML_TAG_CHILD))
|
|
return FALSE;
|
|
|
|
/* is it a placeholder? */
|
|
child_node = glade_xml_search_child (node, GLADE_XML_TAG_PLACEHOLDER);
|
|
if (child_node)
|
|
{
|
|
gtk_container_add (GTK_CONTAINER (parent->widget), glade_placeholder_new ());
|
|
return TRUE;
|
|
}
|
|
|
|
/* then it must be a widget */
|
|
child_node = glade_xml_search_child_required (node, GLADE_XML_TAG_WIDGET);
|
|
if (!child_node)
|
|
return FALSE;
|
|
|
|
/* is it an internal child? */
|
|
internalchild = glade_xml_get_property_string (node, GLADE_XML_TAG_INTERNAL_CHILD);
|
|
if (internalchild)
|
|
{
|
|
child = glade_widget_get_internal_child (parent, internalchild);
|
|
if (!child)
|
|
{
|
|
g_warning ("Failed to get internal child %s", internalchild);
|
|
g_free (internalchild);
|
|
return FALSE;
|
|
}
|
|
glade_widget_fill_from_node (child_node, child);
|
|
}
|
|
else
|
|
{
|
|
child = glade_widget_new_from_node_real (child_node, project, parent);
|
|
if (!child)
|
|
/* not enough memory... and now, how can I signal it
|
|
* and not make the caller believe that it was a parsing
|
|
* problem?
|
|
*/
|
|
return FALSE;
|
|
|
|
gtk_container_add (GTK_CONTAINER (parent->widget), child->widget);
|
|
}
|
|
|
|
/* Get the packing properties */
|
|
child_node = glade_xml_search_child (node, GLADE_XML_TAG_PACKING);
|
|
if (child_node)
|
|
{
|
|
GladeXmlNode *property_node;
|
|
|
|
property_node = glade_xml_node_get_children (child_node);
|
|
for (; property_node; property_node = glade_xml_node_next (property_node))
|
|
{
|
|
/* we should be on a <property ...> tag */
|
|
if (!glade_xml_node_verify (property_node, GLADE_XML_TAG_PROPERTY))
|
|
continue;
|
|
|
|
if (!glade_widget_apply_property_from_node (property_node, child, TRUE)) {
|
|
g_warning ("Failed to apply packing property");
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
GladeWidget *
|
|
glade_widget_read (GladeProject *project, GladeXmlNode *node)
|
|
{
|
|
return glade_widget_new_from_node_real (node, project, NULL);
|
|
}
|