mirror of
https://gitlab.gnome.org/GNOME/glade.git
synced 2025-10-10 00:03:56 -04:00
1505 lines
39 KiB
C
1505 lines
39 KiB
C
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
|
/*
|
|
* Copyright (C) 2001 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:
|
|
* Chema Celorio <chema@celorio.com>
|
|
*/
|
|
|
|
#include <string.h>
|
|
|
|
#include "glade.h"
|
|
#include "glade-widget.h"
|
|
#include "glade-widget-class.h"
|
|
#include "glade-placeholder.h"
|
|
#include "glade-project.h"
|
|
#include "glade-project-window.h"
|
|
#include "glade-parameter.h"
|
|
#include "glade-property.h"
|
|
#include "glade-property-class.h"
|
|
#include "glade-popup.h"
|
|
#include "glade-placeholder.h"
|
|
#include "glade-signal.h"
|
|
#include "glade-gtk.h"
|
|
#include "glade-clipboard.h"
|
|
#include "glade-command.h"
|
|
#include "glade-debug.h"
|
|
#include <gdk/gdkkeysyms.h>
|
|
|
|
/**
|
|
* glade_widget_new_name:
|
|
* @project:
|
|
* @class:
|
|
*
|
|
* Allocates a new name for a specific GladeWidgetClass.
|
|
*
|
|
* Return Value: a newly allocated name for the widget. Caller must g_free it
|
|
**/
|
|
gchar *
|
|
glade_widget_new_name (GladeProject *project, GladeWidgetClass *class)
|
|
{
|
|
return glade_project_new_widget_name (project, class->generic_name);
|
|
}
|
|
|
|
/**
|
|
* Returns a list of GladeProperties from a list of
|
|
* GladePropertyClass.
|
|
*/
|
|
static GList *
|
|
glade_widget_properties_from_list (GList *list, GladeWidget *widget)
|
|
{
|
|
GladePropertyClass *property_class;
|
|
GladeProperty *property;
|
|
GList *new_list = NULL;
|
|
|
|
for (; list; list = list->next) {
|
|
property_class = list->data;
|
|
property = glade_property_new_from_class (property_class, widget);
|
|
if (property == NULL)
|
|
continue;
|
|
|
|
property->widget = widget;
|
|
|
|
new_list = g_list_prepend (new_list, property);
|
|
}
|
|
|
|
new_list = g_list_reverse (new_list);
|
|
|
|
return new_list;
|
|
}
|
|
|
|
/**
|
|
* glade_widget_new:
|
|
* @class: The GladeWidgeClass of the GladeWidget
|
|
*
|
|
* Allocates a new GladeWidget structure and fills in the required memebers.
|
|
*
|
|
* Return Value:
|
|
**/
|
|
static GladeWidget *
|
|
glade_widget_new (GladeWidgetClass *class)
|
|
{
|
|
GladeWidget *widget;
|
|
|
|
widget = g_new0 (GladeWidget, 1);
|
|
widget->name = NULL;
|
|
widget->widget = NULL;
|
|
widget->project = NULL;
|
|
widget->class = class;
|
|
widget->properties = glade_widget_properties_from_list (class->properties, widget);
|
|
/* we don't have packing properties until we container add the widget */
|
|
widget->packing_properties = NULL;
|
|
widget->signals = NULL;
|
|
|
|
return widget;
|
|
}
|
|
|
|
/**
|
|
* glade_widget_get_from_gtk_widget:
|
|
* @widget:
|
|
*
|
|
* Given a GtkWidget, it returns its corresponding GladeWidget
|
|
*
|
|
* Return Value: a GladeWidget pointer for @widget, NULL if the widget does not
|
|
* have a GladeWidget counterpart.
|
|
**/
|
|
GladeWidget *
|
|
glade_widget_get_from_gtk_widget (GtkWidget *widget)
|
|
{
|
|
GladeWidget *glade_widget;
|
|
|
|
glade_widget = g_object_get_data (G_OBJECT (widget), GLADE_WIDGET_DATA_TAG);
|
|
|
|
return glade_widget;
|
|
}
|
|
|
|
/**
|
|
* glade_widget_get_parent:
|
|
* @widget
|
|
*
|
|
* Convenience function to retrieve the GladeWidget associated
|
|
* to the parent of @widget.
|
|
* Returns NULL if it is a toplevel.
|
|
**/
|
|
GladeWidget *
|
|
glade_widget_get_parent (GladeWidget *widget)
|
|
{
|
|
GladeWidget *parent = NULL;
|
|
GtkWidget *parent_widget;
|
|
|
|
g_return_val_if_fail (GLADE_IS_WIDGET (widget), NULL);
|
|
|
|
if (GLADE_WIDGET_IS_TOPLEVEL (widget))
|
|
return NULL;
|
|
|
|
parent_widget = gtk_widget_get_parent (widget->widget);
|
|
g_return_val_if_fail (parent_widget != NULL, NULL);
|
|
|
|
parent = glade_widget_get_from_gtk_widget (parent_widget);
|
|
g_return_val_if_fail (GLADE_IS_WIDGET (parent), NULL);
|
|
|
|
return parent;
|
|
}
|
|
|
|
/* 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_child;
|
|
} GladeFindInContainerData;
|
|
|
|
static void
|
|
glade_widget_find_inside_container (GtkWidget *widget, gpointer data_in)
|
|
{
|
|
GladeFindInContainerData *data = data_in;
|
|
|
|
g_debug(("In find_child_at: %s X:%i Y:%i W:%i H:%i\n"
|
|
" so this means that if we are in the %d-%d , %d-%d range. We are ok\n",
|
|
gtk_widget_get_name (widget),
|
|
widget->allocation.x, widget->allocation.y,
|
|
widget->allocation.width, widget->allocation.height,
|
|
widget->allocation.x, widget->allocation.x + widget->allocation.width,
|
|
widget->allocation.y, widget->allocation.y + widget->allocation.height));
|
|
|
|
/* Notebook pages are visible but not mapped if they are not showing. */
|
|
/* We should not consider objects that doesn't have the GLADE_WIDGET_DATA_TAG,
|
|
that way we would only take in account widgets modifiables by the user
|
|
(for instance, the widgets that are inside a font dialog are not modifiables
|
|
by the user) */
|
|
if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget)
|
|
&& (widget->allocation.x <= data->x)
|
|
&& (widget->allocation.y <= data->y)
|
|
&& (widget->allocation.x + widget->allocation.width >= data->x)
|
|
&& (widget->allocation.y + widget->allocation.height >= data->y)
|
|
&& g_object_get_data(G_OBJECT (widget), GLADE_WIDGET_DATA_TAG))
|
|
{
|
|
g_debug(("Found it!\n"));
|
|
data->found_child = widget;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* glade_widget_get_from_event_widget:
|
|
* @event_widget:
|
|
* @event:
|
|
*
|
|
* 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_get_from_event_widget (GtkWidget *event_widget, GdkEventButton *event)
|
|
{
|
|
GladeFindInContainerData data;
|
|
GladeWidget *found = NULL;
|
|
GtkWidget *temp;
|
|
GdkWindow *window;
|
|
GdkWindow *parent_window;
|
|
gint x, win_x;
|
|
gint y, win_y;
|
|
|
|
window = event->window;
|
|
x = (int) (event->x + 0.5);
|
|
y = (int) (event->y + 0.5);
|
|
gdk_window_get_position (event_widget->window, &win_x, &win_y);
|
|
|
|
/*
|
|
g_debug(("Window [%d,%d]\n", win_x, win_y));
|
|
g_debug(("\n\nWe want to find the real widget that was clicked at %d,%d\n", x, y));
|
|
g_debug(("The widget that received the event was \"%s\" a \"%s\" [%d]\n",
|
|
"",
|
|
gtk_widget_get_name (event_widget),
|
|
GPOINTER_TO_INT (event_widget)));
|
|
*/
|
|
|
|
parent_window = event_widget->parent ? event_widget->parent->window : event_widget->window;
|
|
while (window && window != parent_window) {
|
|
|
|
gdk_window_get_position (window, &win_x, &win_y);
|
|
/* g_debug((" adding X:%d Y:%d - We now have : %d %d\n",
|
|
win_x, win_y, x + win_x, y + win_y)); */
|
|
x += win_x;
|
|
y += win_y;
|
|
window = gdk_window_get_parent (window);
|
|
}
|
|
|
|
temp = event_widget;
|
|
data.found_child = NULL;
|
|
data.x = x;
|
|
data.y = y;
|
|
found = glade_widget_get_from_gtk_widget (event_widget);
|
|
|
|
while (GTK_IS_CONTAINER (temp)) {
|
|
g_debug(("\"%s\" is a container, check inside each child\n",
|
|
gtk_widget_get_name (temp)));
|
|
data.found_child = NULL;
|
|
gtk_container_forall (GTK_CONTAINER (temp),
|
|
(GtkCallback) glade_widget_find_inside_container, &data);
|
|
if (data.found_child) {
|
|
temp = data.found_child;
|
|
if (glade_widget_get_from_gtk_widget (temp)) {
|
|
found = glade_widget_get_from_gtk_widget (temp);
|
|
g_assert (found->widget == data.found_child);
|
|
} else {
|
|
g_debug(("Temp was not a GladeWidget, it was a %s\n",
|
|
gtk_widget_get_name (temp)));
|
|
}
|
|
} else {
|
|
/* The user clicked on the container itself */
|
|
found = glade_widget_get_from_gtk_widget (temp);
|
|
break;
|
|
}
|
|
|
|
}
|
|
#ifdef DEBUG
|
|
if (!found) {
|
|
GladeWidget *gw;
|
|
gw = glade_widget_get_from_gtk_widget (event_widget);
|
|
g_warning ("We could not find the widget %s:%s\n",
|
|
gtk_widget_get_name (event_widget),
|
|
gw ? gw->name : "[null]");
|
|
return NULL;
|
|
}
|
|
#else
|
|
g_return_val_if_fail (found != NULL, NULL);
|
|
#endif
|
|
/*
|
|
g_debug(("We found a \"%s\", child at %d,%d\n",
|
|
gtk_widget_get_name (found->widget), data.x, data.y));
|
|
*/
|
|
return found;
|
|
}
|
|
|
|
/**
|
|
* glade_widget_button_press:
|
|
* @event_widget:
|
|
* @event:
|
|
* @not_used:
|
|
*
|
|
* Handle the button press event for every GladeWidget
|
|
*
|
|
* Return Value:
|
|
**/
|
|
static gboolean
|
|
glade_widget_button_press (GtkWidget *event_widget,
|
|
GdkEventButton *event,
|
|
gpointer not_used)
|
|
{
|
|
GladeWidget *glade_widget;
|
|
|
|
glade_widget = glade_widget_get_from_event_widget (event_widget, event);
|
|
|
|
g_debug(("button press for a %s\n", glade_widget->class->name));
|
|
|
|
if (!glade_widget) {
|
|
g_warning ("Button press event but the gladewidget was not found\n");
|
|
return FALSE;
|
|
}
|
|
|
|
g_debug(("Event button %d\n", event->button));
|
|
|
|
if (event->button == 1) {
|
|
/* If this is a selection set, don't change the state of the widget
|
|
* for example for toggle buttons
|
|
*/
|
|
if (!glade_util_has_nodes (glade_widget->widget))
|
|
g_signal_stop_emission_by_name (G_OBJECT (event_widget),
|
|
"button_press_event");
|
|
glade_project_selection_set (glade_widget->project, glade_widget->widget, TRUE);
|
|
} else if (event->button == 3)
|
|
glade_popup_pop (glade_widget, event);
|
|
else
|
|
g_debug(("Button press not handled yet.\n"));
|
|
|
|
g_debug(("The widget found was a %s\n", glade_widget->class->name));
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
glade_widget_button_release (GtkWidget *widget, GdkEventButton *event, gpointer not_used)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* Set the deafault value to the given list of properties.
|
|
*/
|
|
static void
|
|
glade_widget_set_default_options_real (GList *properties)
|
|
{
|
|
GladeProperty *property;
|
|
GList *list;
|
|
|
|
for (list = properties; list; list = list->next) {
|
|
property = list->data;
|
|
|
|
/* For some properties, we get the value from the GtkWidget, for example the
|
|
* "position" packing property. See g-p-class.h ->get_default. Chema
|
|
*/
|
|
if (property->class->get_default) {
|
|
glade_property_get_from_widget (property);
|
|
continue;
|
|
}
|
|
|
|
property->loading = TRUE;
|
|
glade_property_refresh (property);
|
|
property->loading = FALSE;
|
|
}
|
|
}
|
|
|
|
static void
|
|
glade_widget_set_default_options (GladeWidget *widget)
|
|
{
|
|
glade_widget_set_default_options_real (widget->properties);
|
|
}
|
|
|
|
/**
|
|
* glade_widget_set_default_packing_options:
|
|
* @widget:
|
|
*
|
|
* We need to have a different function for setting packing options
|
|
* because we need to add the widget to the container before we
|
|
* apply the packing options.
|
|
*
|
|
**/
|
|
void
|
|
glade_widget_set_default_packing_options (GladeWidget *widget)
|
|
{
|
|
g_return_if_fail (GLADE_IS_WIDGET (widget));
|
|
|
|
glade_widget_set_default_options_real (widget->packing_properties);
|
|
}
|
|
|
|
static void
|
|
glade_widget_connect_mouse_signals (GladeWidget *glade_widget)
|
|
{
|
|
GtkWidget *widget = glade_widget->widget;
|
|
|
|
if (!GTK_WIDGET_NO_WINDOW (widget)) {
|
|
if (!GTK_WIDGET_REALIZED (widget))
|
|
gtk_widget_set_events (widget, gtk_widget_get_events (widget)
|
|
| GDK_BUTTON_PRESS_MASK
|
|
| GDK_BUTTON_RELEASE_MASK);
|
|
else {
|
|
GdkEventMask event_mask;
|
|
|
|
event_mask = gdk_window_get_events (widget->window);
|
|
gdk_window_set_events (widget->window, event_mask
|
|
| GDK_BUTTON_PRESS_MASK
|
|
| GDK_BUTTON_RELEASE_MASK);
|
|
}
|
|
}
|
|
|
|
g_signal_connect (G_OBJECT (widget), "button_press_event",
|
|
G_CALLBACK (glade_widget_button_press), NULL);
|
|
g_signal_connect (G_OBJECT (widget), "button_release_event",
|
|
G_CALLBACK (glade_widget_button_release), NULL);
|
|
}
|
|
|
|
static gboolean
|
|
glade_widget_key_press (GtkWidget *event_widget,
|
|
GdkEventKey *event,
|
|
gpointer user_data)
|
|
{
|
|
GladeWidget *glade_widget = GLADE_WIDGET (user_data);
|
|
|
|
g_return_val_if_fail (GTK_IS_WIDGET (event_widget), FALSE);
|
|
g_return_val_if_fail (glade_widget->widget == event_widget, FALSE);
|
|
|
|
/* We will delete all the selected items */
|
|
if (event->keyval == GDK_Delete)
|
|
glade_util_delete_selection (glade_widget->project);
|
|
|
|
g_debug(("glade_widget_key_press\n"));
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
glade_widget_connect_keyboard_signals (GladeWidget *glade_widget)
|
|
{
|
|
GtkWidget *widget = glade_widget->widget;
|
|
|
|
if (!GTK_WIDGET_NO_WINDOW(widget)) {
|
|
gtk_widget_set_events (widget, gtk_widget_get_events (widget)
|
|
| GDK_KEY_PRESS_MASK);
|
|
}
|
|
|
|
g_signal_connect (G_OBJECT (widget), "key_press_event",
|
|
G_CALLBACK (glade_widget_key_press), glade_widget);
|
|
}
|
|
|
|
/**
|
|
* glade_widget_set_contents:
|
|
* @widget:
|
|
*
|
|
* Loads the name of the widget. For example a button will have the
|
|
* "button1" text in it, or a label will have "label4". right after
|
|
* it is created.
|
|
**/
|
|
void
|
|
glade_widget_set_contents (GladeWidget *widget)
|
|
{
|
|
GladeProperty *property = NULL;
|
|
GValue *value = g_new0 (GValue, 1);
|
|
GladeWidgetClass *class;
|
|
|
|
class = widget->class;
|
|
|
|
if (glade_widget_class_has_property (class, "label"))
|
|
property = glade_property_get_from_id (widget->properties,
|
|
"label");
|
|
if (glade_widget_class_has_property (class, "title"))
|
|
property = glade_property_get_from_id (widget->properties,
|
|
"title");
|
|
|
|
if (property) {
|
|
g_value_init (value, G_TYPE_STRING);
|
|
g_value_set_string (value, widget->name);
|
|
glade_property_set (property, value);
|
|
}
|
|
}
|
|
|
|
static void
|
|
glade_widget_property_changed_cb (GtkWidget *w)
|
|
{
|
|
GladeProperty *property;
|
|
GladeWidget *widget;
|
|
|
|
widget = glade_widget_get_from_gtk_widget (w);
|
|
g_return_if_fail (GLADE_IS_WIDGET (widget));
|
|
property = g_object_get_data (G_OBJECT (w), GLADE_MODIFY_PROPERTY_DATA);
|
|
g_return_if_fail (GLADE_IS_PROPERTY (property));
|
|
|
|
if (property->loading)
|
|
return;
|
|
|
|
glade_property_get_from_widget (property);
|
|
|
|
glade_property_refresh (property);
|
|
}
|
|
|
|
static void
|
|
glade_widget_connect_edit_signals_with_class (GladeWidget *widget,
|
|
GladePropertyClass *class)
|
|
{
|
|
GladeProperty *property;
|
|
GList *list;
|
|
|
|
property = glade_widget_get_property_from_class (widget, class);
|
|
|
|
g_return_if_fail (GLADE_IS_PROPERTY (property));
|
|
|
|
for (list = class->update_signals; list; list = list->next) {
|
|
g_signal_connect_after (G_OBJECT (widget->widget), list->data,
|
|
G_CALLBACK (glade_widget_property_changed_cb),
|
|
property);
|
|
g_object_set_data (G_OBJECT (widget->widget),
|
|
GLADE_MODIFY_PROPERTY_DATA, property);
|
|
}
|
|
}
|
|
|
|
static void
|
|
glade_widget_connect_edit_signals (GladeWidget *widget)
|
|
{
|
|
GladePropertyClass *class;
|
|
GList *list;
|
|
|
|
for (list = widget->class->properties; list; list = list->next) {
|
|
class = list->data;
|
|
if (class->update_signals)
|
|
glade_widget_connect_edit_signals_with_class (widget,
|
|
class);
|
|
}
|
|
}
|
|
|
|
static void
|
|
glade_widget_connect_other_signals (GladeWidget *widget)
|
|
{
|
|
if (GLADE_WIDGET_IS_TOPLEVEL (widget)) {
|
|
g_signal_connect (G_OBJECT (widget->widget), "delete_event",
|
|
G_CALLBACK (gtk_widget_hide_on_delete), NULL);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Free the GladeWidget associated to a widget. Note that this is
|
|
* connected to the destroy event of the corresponding GtkWidget so
|
|
* it does not need to recurse, since Gtk takes care of destroying
|
|
* all the children.
|
|
* You should not be calling this function explicitely, if needed
|
|
* just destroy widget->widget.
|
|
*/
|
|
static void
|
|
glade_widget_free (GladeWidget *widget)
|
|
{
|
|
widget->class = NULL;
|
|
widget->project = NULL;
|
|
widget->widget = NULL;
|
|
|
|
if (widget->name)
|
|
g_free (widget->name);
|
|
widget->name = NULL;
|
|
|
|
g_list_foreach(widget->properties, (GFunc) glade_property_free, NULL);
|
|
g_list_free (widget->properties);
|
|
g_list_foreach(widget->packing_properties, (GFunc) glade_property_free, NULL);
|
|
g_list_free (widget->packing_properties);
|
|
g_list_foreach(widget->signals, (GFunc) glade_signal_free, NULL);
|
|
g_list_free (widget->signals);
|
|
|
|
g_free (widget);
|
|
}
|
|
|
|
static GtkWidget *
|
|
glade_widget_create_gtk_widget (GladeWidgetClass *class)
|
|
{
|
|
GtkWidget *widget;
|
|
GType type;
|
|
|
|
type = g_type_from_name (class->name);
|
|
|
|
if (!g_type_is_a (type, G_TYPE_OBJECT)) {
|
|
g_warning ("Create GtkWidget for type %s not implemented", class->name);
|
|
return NULL;
|
|
}
|
|
|
|
if (g_type_is_a (type, GTK_TYPE_WIDGET))
|
|
widget = gtk_widget_new (type, NULL);
|
|
else
|
|
widget = g_object_new (type, NULL);
|
|
|
|
/* Ugly ugly hack. Don't even remind me about it. SEND ME PATCH !! and you'll
|
|
* gain 100 love points.
|
|
* 100ms works for me, but since i don't know what the problem is i'll add a couple
|
|
* of more times the call for slower systems or systems under heavy workload, no harm
|
|
* done with an extra queue_resize.
|
|
* This was not needed for gtk 1.3.5 but needed for 1.3.7.
|
|
* To reproduce the problem, remove this timeouts and create a gtkwindow
|
|
* and then a gtkvbox inside it. It will not draw correctly.
|
|
* Chema
|
|
*/
|
|
/* That hack makes glade segfault if you delete glade_widget before 1 sec has ellapsed
|
|
* since its creation (glade_widget will point to garbage). With gtk 1.3.12 everything
|
|
* seems to be ok without the timeouts, so I will remove it by now.
|
|
* Cuenca
|
|
*/
|
|
|
|
/* We need to call the post_create_function after the embed of the widget in
|
|
* its parent. Otherwise, calls to gtk_widget_grab_focus et al. will fail
|
|
*/
|
|
if (class->post_create_function) {
|
|
class->post_create_function (G_OBJECT (widget));
|
|
}
|
|
|
|
return widget;
|
|
}
|
|
|
|
void
|
|
glade_widget_connect_signals (GladeWidget *widget)
|
|
{
|
|
glade_widget_connect_mouse_signals (widget);
|
|
glade_widget_connect_keyboard_signals (widget);
|
|
glade_widget_connect_edit_signals (widget);
|
|
glade_widget_connect_other_signals (widget);
|
|
}
|
|
|
|
/**
|
|
* 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.
|
|
*/
|
|
void
|
|
glade_widget_set_packing_properties (GladeWidget *widget,
|
|
GladeWidgetClass *container_class)
|
|
{
|
|
g_return_if_fail (GLADE_IS_WIDGET (widget));
|
|
g_return_if_fail (GLADE_IS_WIDGET_CLASS (container_class));
|
|
|
|
/*
|
|
* toplevls do not have packing properties, so should not be
|
|
* passed to this function.
|
|
*/
|
|
g_return_if_fail (!GTK_WIDGET_TOPLEVEL (widget->widget));
|
|
|
|
g_list_free (widget->packing_properties);
|
|
widget->packing_properties = glade_widget_properties_from_list (container_class->child_properties, widget);
|
|
}
|
|
|
|
static GladeWidget *
|
|
glade_widget_new_full (GladeWidgetClass *class,
|
|
GladeProject *project,
|
|
GladeWidget *parent)
|
|
{
|
|
GladeWidget *widget;
|
|
|
|
g_return_val_if_fail (GLADE_IS_WIDGET_CLASS (class), NULL);
|
|
|
|
widget = glade_widget_new (class);
|
|
widget->name = glade_widget_new_name (project, class);
|
|
widget->project = project;
|
|
|
|
widget->widget = glade_widget_create_gtk_widget (class);
|
|
|
|
/* associate the GladeWidget to the GtkWidget */
|
|
g_signal_connect_swapped (G_OBJECT (widget->widget), "destroy",
|
|
G_CALLBACK (glade_widget_free), G_OBJECT (widget));
|
|
g_object_set_data (G_OBJECT (widget->widget), GLADE_WIDGET_DATA_TAG, widget);
|
|
|
|
/* We know the parent (if we have one), we can add the packing properties */
|
|
if (parent)
|
|
glade_widget_set_packing_properties (widget, parent->class);
|
|
|
|
glade_widget_set_contents (widget);
|
|
glade_widget_connect_signals (widget);
|
|
|
|
return widget;
|
|
}
|
|
|
|
static void
|
|
glade_widget_fill_empty (GtkWidget *widget)
|
|
{
|
|
GList *children;
|
|
gboolean empty = TRUE;
|
|
|
|
if (!GTK_IS_CONTAINER (widget))
|
|
return;
|
|
|
|
/* fill with placeholders the containers that are inside of this container */
|
|
children = gtk_container_get_children (GTK_CONTAINER (widget));
|
|
|
|
/* loop over the children of this container, and fill them with placeholders */
|
|
while (children != NULL) {
|
|
glade_widget_fill_empty (GTK_WIDGET (children->data));
|
|
children = children->next;
|
|
empty = FALSE;
|
|
}
|
|
|
|
if (empty) {
|
|
/* retrieve the desired number of placeholders that this widget should hold */
|
|
int nb_children = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "glade_nb_placeholders"));
|
|
int i;
|
|
|
|
if (nb_children == 0 && GTK_IS_BIN (widget))
|
|
nb_children = 1;
|
|
|
|
for (i = nb_children; i > 0; i--)
|
|
gtk_container_add (GTK_CONTAINER (widget), glade_placeholder_new ());
|
|
}
|
|
}
|
|
|
|
static GtkWidget *
|
|
glade_widget_append_query (GtkWidget *table,
|
|
GladePropertyClass *property_class,
|
|
gint row)
|
|
{
|
|
GladePropertyQuery *query;
|
|
GtkAdjustment *adjustment;
|
|
GtkWidget *label;
|
|
GtkWidget *spin;
|
|
gchar *text;
|
|
|
|
query = property_class->query;
|
|
|
|
if (property_class->type != GLADE_PROPERTY_TYPE_INTEGER) {
|
|
g_warning ("We can only query integer types for now. Trying to query %d. FIXME please ;-)", property_class->type);
|
|
return NULL;
|
|
}
|
|
|
|
/* Label */
|
|
text = g_strdup_printf ("%s :", query->question);
|
|
label = gtk_label_new (text);
|
|
g_free (text);
|
|
gtk_widget_show (label);
|
|
gtk_table_attach_defaults (GTK_TABLE (table), label,
|
|
0, 1, row, row +1);
|
|
|
|
/* Spin/Entry */
|
|
adjustment = glade_parameter_adjustment_new (property_class);
|
|
spin = gtk_spin_button_new (adjustment, 1, 0);
|
|
gtk_widget_show (spin);
|
|
gtk_table_attach_defaults (GTK_TABLE (table), spin,
|
|
1, 2, row, row +1);
|
|
|
|
return spin;
|
|
}
|
|
|
|
void
|
|
glade_widget_query_properties_set (gpointer key_,
|
|
gpointer value_,
|
|
gpointer user_data)
|
|
{
|
|
GladePropertyQueryResult *result = user_data;
|
|
GtkWidget *spin = value_;
|
|
const gchar *key = key_;
|
|
gint num;
|
|
|
|
num = (gint) gtk_spin_button_get_value (GTK_SPIN_BUTTON (spin));
|
|
glade_property_query_result_set_int (result, key, num);
|
|
}
|
|
|
|
/**
|
|
* glade_widget_query_properties:
|
|
* @class:
|
|
* @result:
|
|
*
|
|
* Queries the user for some property values before a GladeWidget creation
|
|
* for example before creating a GtkVBox we want to ask the user the number
|
|
* of columns he wants.
|
|
*
|
|
* Return Value: FALSE if the query was canceled
|
|
**/
|
|
gboolean
|
|
glade_widget_query_properties (GladeWidgetClass *class,
|
|
GladePropertyQueryResult *result)
|
|
{
|
|
GladePropertyClass *property_class;
|
|
GHashTable *hash;
|
|
GtkWidget *dialog;
|
|
GtkWidget *table;
|
|
GtkWidget *vbox;
|
|
GtkWidget *spin = NULL;
|
|
GList *list;
|
|
gint response;
|
|
gint row = 0;
|
|
|
|
g_return_val_if_fail (class != NULL, FALSE);
|
|
g_return_val_if_fail (result != NULL, FALSE);
|
|
|
|
dialog = gtk_dialog_new_with_buttons (NULL /* name */,
|
|
NULL /* parent, FIXME: parent should be the project window */,
|
|
GTK_DIALOG_MODAL,
|
|
GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
|
|
GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
|
|
NULL);
|
|
gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
|
|
gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
|
|
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
|
|
|
|
vbox = GTK_DIALOG (dialog)->vbox;
|
|
table = gtk_table_new (0, 0, FALSE);
|
|
gtk_widget_show (table);
|
|
gtk_box_pack_start_defaults (GTK_BOX (vbox), table);
|
|
|
|
hash = g_hash_table_new (g_str_hash, g_str_equal);
|
|
|
|
for (list = class->properties; list; list = list->next) {
|
|
property_class = list->data;
|
|
if (property_class->query) {
|
|
spin = glade_widget_append_query (table, property_class, row++);
|
|
g_hash_table_insert (hash, property_class->id, spin);
|
|
}
|
|
}
|
|
if (spin == NULL) {
|
|
g_hash_table_destroy (hash);
|
|
gtk_widget_destroy (GTK_WIDGET (dialog));
|
|
return FALSE;
|
|
}
|
|
|
|
response = gtk_dialog_run (GTK_DIALOG (dialog));
|
|
switch (response) {
|
|
case GTK_RESPONSE_ACCEPT:
|
|
g_hash_table_foreach (hash,
|
|
glade_widget_query_properties_set,
|
|
result);
|
|
break;
|
|
case GTK_RESPONSE_REJECT:
|
|
case GTK_RESPONSE_DELETE_EVENT:
|
|
gtk_widget_destroy (dialog);
|
|
return FALSE;
|
|
default:
|
|
g_assert_not_reached ();
|
|
}
|
|
|
|
g_hash_table_destroy (hash);
|
|
gtk_widget_destroy (dialog);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* glade_widget_apply_queried_properties:
|
|
* @widget: widget that will receive the set of queried properties
|
|
* @result: values of the queried properties
|
|
*
|
|
*/
|
|
static void
|
|
glade_widget_apply_queried_properties (GladeWidget *widget,
|
|
GladePropertyQueryResult *result)
|
|
{
|
|
GList *list;
|
|
GValue *value = g_new0 (GValue, 1);
|
|
|
|
g_value_init (value, G_TYPE_INT);
|
|
|
|
list = widget->class->properties;
|
|
for (; list; list = list->next) {
|
|
GladePropertyClass *pclass = list->data;
|
|
if (pclass->query) {
|
|
GladeProperty *property;
|
|
gint temp;
|
|
glade_property_query_result_get_int (result, pclass->id, &temp);
|
|
property = glade_property_get_from_id (widget->properties, pclass->id);
|
|
|
|
g_value_set_int (value, temp);
|
|
glade_property_set (property, value);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* glade_widget_new_from_class:
|
|
* @class:
|
|
* @project:
|
|
* @parent: the parent of the new widget, should be NULL for toplevel widgets
|
|
*
|
|
* Creates a new GladeWidget from a given class. Takes care of registering
|
|
* the widget in the project, adding it to the views and quering the user
|
|
* if needed.
|
|
*
|
|
* Return Value: A newly creatred GladeWidget, NULL on user cancel or error
|
|
**/
|
|
GladeWidget *
|
|
glade_widget_new_from_class (GladeWidgetClass *class,
|
|
GladeProject *project,
|
|
GladeWidget *parent)
|
|
{
|
|
GladePropertyQueryResult *result = NULL;
|
|
GladeWidget *widget;
|
|
|
|
g_return_val_if_fail (GLADE_IS_WIDGET_CLASS (class), NULL);
|
|
g_return_val_if_fail (GLADE_IS_PROJECT (project), NULL);
|
|
|
|
if (glade_widget_class_has_queries (class)) {
|
|
result = glade_property_query_result_new ();
|
|
if (!glade_widget_query_properties (class, result))
|
|
return NULL;
|
|
}
|
|
|
|
widget = glade_widget_new_full (class, project, parent);
|
|
|
|
glade_widget_apply_queried_properties (widget, result);
|
|
|
|
/* If we are a container, add the placeholders */
|
|
if (g_type_is_a (class->type, GTK_TYPE_CONTAINER))
|
|
glade_widget_fill_empty (widget->widget);
|
|
|
|
if (result)
|
|
glade_property_query_result_destroy (result);
|
|
|
|
glade_widget_set_default_options (widget);
|
|
|
|
return widget;
|
|
}
|
|
|
|
const gchar *
|
|
glade_widget_get_name (GladeWidget *widget)
|
|
{
|
|
return widget->name;
|
|
}
|
|
|
|
GladeWidgetClass *
|
|
glade_widget_get_class (GladeWidget *widget)
|
|
{
|
|
return widget->class;
|
|
}
|
|
|
|
/**
|
|
* glade_widget_get_property_from_list:
|
|
* @list: The list of GladeProperty
|
|
* @class: The Class that we are trying to match with GladeProperty
|
|
* @silent: True if we should warn when a property is not included in the list
|
|
*
|
|
* Give a list of GladeProperties find the one that has ->class = to @class.
|
|
* This function recurses into child objects if needed.
|
|
*
|
|
* Return Value:
|
|
**/
|
|
static GladeProperty *
|
|
glade_widget_get_property_from_list (GList *list,
|
|
GladePropertyClass *class,
|
|
gboolean silent)
|
|
{
|
|
GladeProperty *property = NULL;
|
|
|
|
if (list == NULL)
|
|
return NULL;
|
|
|
|
for (; list; list = list->next) {
|
|
property = list->data;
|
|
if (property->class == class)
|
|
break;
|
|
if (property->child != NULL) {
|
|
property = glade_widget_get_property_from_list (property->child->properties,
|
|
class, TRUE);
|
|
if (property != NULL)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (list == NULL) {
|
|
if (!silent)
|
|
g_warning ("Could not find the GladeProperty %s:%s",
|
|
class->id,
|
|
class->name);
|
|
return NULL;
|
|
}
|
|
|
|
return property;
|
|
}
|
|
|
|
/**
|
|
* glade_widget_get_property_from_class:
|
|
* @widget:
|
|
* @property_class:
|
|
*
|
|
* Given a glade Widget, it returns the property that correspons to @property_class
|
|
*
|
|
* Return Value:
|
|
**/
|
|
GladeProperty *
|
|
glade_widget_get_property_from_class (GladeWidget *widget,
|
|
GladePropertyClass *property_class)
|
|
{
|
|
GladeProperty *property;
|
|
GList *list;
|
|
|
|
if (property_class->packing)
|
|
list = widget->packing_properties;
|
|
else
|
|
list = widget->properties;
|
|
|
|
property = glade_widget_get_property_from_list (list, property_class, FALSE);
|
|
|
|
if (!property)
|
|
g_warning ("Could not get property for widget %s of %s class\n",
|
|
widget->name, widget->class->name);
|
|
|
|
return property;
|
|
}
|
|
|
|
/**
|
|
* glade_widget_set_name:
|
|
* @widget:
|
|
* @name:
|
|
*
|
|
* Sets the name of a widget
|
|
**/
|
|
void
|
|
glade_widget_set_name (GladeWidget *widget, const gchar *name)
|
|
{
|
|
g_return_if_fail (GLADE_IS_WIDGET (widget));
|
|
g_return_if_fail (name != NULL);
|
|
|
|
if (widget->name)
|
|
g_free (widget->name);
|
|
widget->name = g_strdup (name);
|
|
|
|
glade_project_widget_name_changed (widget->project, widget);
|
|
}
|
|
|
|
/**
|
|
* glade_widget_clone:
|
|
* @widget:
|
|
*
|
|
* Make a copy of a #GladeWidget.
|
|
* You have to set name, project and parent when adding the clone
|
|
* to a project.
|
|
*
|
|
* Return Value: the cloned GladeWidget, NULL on error.
|
|
*/
|
|
GladeWidget *
|
|
glade_widget_clone (GladeWidget *widget)
|
|
{
|
|
GladeWidget *clone;
|
|
|
|
g_return_val_if_fail (widget != NULL, NULL);
|
|
|
|
/* This should be enough to clone. */
|
|
clone = glade_widget_new_full (widget->class, widget->project, NULL);
|
|
|
|
return clone;
|
|
}
|
|
|
|
/**
|
|
* glade_widget_replace_with_placeholder:
|
|
* @widget:
|
|
* @placeholder:
|
|
*
|
|
* Replaces @widget with @placeholder.
|
|
*/
|
|
void
|
|
glade_widget_replace_with_placeholder (GladeWidget *widget,
|
|
GladePlaceholder *placeholder)
|
|
{
|
|
GladeWidget *parent;
|
|
|
|
g_return_if_fail (GLADE_IS_WIDGET (widget));
|
|
g_return_if_fail (GLADE_IS_PLACEHOLDER (placeholder));
|
|
|
|
parent = glade_widget_get_parent (widget);
|
|
|
|
if (parent->class->placeholder_replace) {
|
|
parent->class->placeholder_replace (widget->widget,
|
|
GTK_WIDGET (placeholder),
|
|
parent->widget);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* glade_widget_find_signal:
|
|
* @widget
|
|
* @signal
|
|
*
|
|
* Find the element in the signal list of the widget with the same
|
|
* signal as @signal or NULL if not present.
|
|
*/
|
|
GList *
|
|
glade_widget_find_signal (GladeWidget *widget, GladeSignal *signal)
|
|
{
|
|
GList *list;
|
|
|
|
for (list = widget->signals; list; list = list->next) {
|
|
GladeSignal *tmp = GLADE_SIGNAL (list->data);
|
|
if (glade_signal_compare (tmp, signal))
|
|
return list;
|
|
}
|
|
|
|
/* not found... */
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* glade_widget_add_signal:
|
|
* @widget
|
|
* @signal
|
|
*
|
|
* Add @signal to the widget's signal list.
|
|
**/
|
|
void
|
|
glade_widget_add_signal (GladeWidget *widget, GladeSignal *signal)
|
|
{
|
|
GList *found;
|
|
|
|
g_return_if_fail (GLADE_IS_WIDGET (widget));
|
|
g_return_if_fail (GLADE_IS_SIGNAL (signal));
|
|
|
|
found = glade_widget_find_signal (widget, signal);
|
|
if (found) {
|
|
glade_signal_free (signal);
|
|
return;
|
|
}
|
|
|
|
widget->signals = g_list_append (widget->signals, signal);
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* glade_widget_remove_signal:
|
|
* @widget
|
|
* @signal
|
|
*
|
|
* Remove @signal from the widget's signal list.
|
|
**/
|
|
void
|
|
glade_widget_remove_signal (GladeWidget *widget, GladeSignal *signal)
|
|
{
|
|
GList *found;
|
|
|
|
g_return_if_fail (GLADE_IS_WIDGET (widget));
|
|
g_return_if_fail (GLADE_IS_SIGNAL (signal));
|
|
|
|
found = glade_widget_find_signal (widget, signal);
|
|
if (found) {
|
|
g_list_remove_link (widget->signals, found);
|
|
glade_signal_free (GLADE_SIGNAL (found->data));
|
|
g_list_free_1 (found);
|
|
}
|
|
}
|
|
|
|
GladeXmlNode *
|
|
glade_widget_write (GladeXmlContext *context, GladeWidget *widget)
|
|
{
|
|
GladeProperty *property;
|
|
GladeXmlNode *node;
|
|
GladeXmlNode *child; /* This is the <widget name="foo" ..> tag */
|
|
GladeXmlNode *child_tag; /* This is the <child> tag */
|
|
GladeXmlNode *packing;
|
|
GladeWidget *child_widget;
|
|
GladeSignal *signal;
|
|
GtkWidget *gtk_widget;
|
|
GList *list;
|
|
GList *list2;
|
|
|
|
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->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) {
|
|
property = list->data;
|
|
if (property->class->packing)
|
|
continue;
|
|
child = glade_property_write (context, property);
|
|
if (child == NULL)
|
|
continue;
|
|
glade_xml_node_append_child (node, child);
|
|
}
|
|
|
|
/* Signals */
|
|
list = widget->signals;
|
|
for (; list; list = list->next) {
|
|
signal = list->data;
|
|
child = glade_signal_write (context, signal);
|
|
if (child == NULL)
|
|
return NULL;
|
|
glade_xml_node_append_child (node, child);
|
|
}
|
|
|
|
/* Children */
|
|
if (GTK_IS_CONTAINER (widget->widget))
|
|
list = gtk_container_get_children (GTK_CONTAINER (widget->widget));
|
|
else
|
|
list = NULL;
|
|
|
|
for (; list; list = list->next) {
|
|
gtk_widget = GTK_WIDGET (list->data);
|
|
child_widget = glade_widget_get_from_gtk_widget (gtk_widget);
|
|
if (!child_widget && !GLADE_IS_PLACEHOLDER (gtk_widget))
|
|
continue;
|
|
|
|
child_tag = glade_xml_node_new (context, GLADE_XML_TAG_CHILD);
|
|
glade_xml_node_append_child (node, child_tag);
|
|
|
|
if (child_widget) {
|
|
/* write the widget */
|
|
child = glade_widget_write (context, child_widget);
|
|
if (child == NULL)
|
|
return NULL;
|
|
|
|
glade_xml_node_append_child (child_tag, child);
|
|
|
|
/* Append the packing properties */
|
|
packing = glade_xml_node_new (context, GLADE_XML_TAG_PACKING);
|
|
list2 = child_widget->packing_properties;
|
|
for (; list2; list2 = list2->next) {
|
|
GladeXmlNode *packing_property;
|
|
property = list2->data;
|
|
g_assert (property->class->packing == TRUE);
|
|
packing_property = glade_property_write (context, property);
|
|
if (packing_property == NULL)
|
|
continue;
|
|
glade_xml_node_append_child (packing, packing_property);
|
|
glade_xml_node_append_child (child_tag, packing);
|
|
}
|
|
}
|
|
else {
|
|
/* a placeholder */
|
|
child = glade_xml_node_new (context, GLADE_XML_TAG_PLACEHOLDER);
|
|
glade_xml_node_append_child (child_tag, child);
|
|
}
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
static gboolean
|
|
glade_widget_apply_property_from_node (GladeXmlNode *node, GladeWidget *widget)
|
|
{
|
|
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_property_get_from_id (widget->properties, id);
|
|
|
|
if (property == NULL) {
|
|
g_warning ("Could not apply property from node. Id :%s\n",
|
|
id);
|
|
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_free (gvalue);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
glade_widget_new_child_from_node (GladeXmlNode *node,
|
|
GladeProject *project,
|
|
GladeWidget *parent);
|
|
|
|
static GladeWidget *
|
|
glade_widget_new_from_node_real (GladeXmlNode *node,
|
|
GladeProject *project,
|
|
GladeWidget *parent)
|
|
{
|
|
GladeWidgetClass *class;
|
|
GladeXmlNode *child;
|
|
GladeWidget *widget;
|
|
GladeSignal *signal;
|
|
const gchar *class_name;
|
|
const gchar *widget_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);
|
|
widget_name = glade_xml_get_property_string_required (node, GLADE_XML_TAG_ID, NULL);
|
|
|
|
if (!class_name || !widget_name)
|
|
return NULL;
|
|
class = glade_widget_class_get_by_name (class_name);
|
|
if (!class)
|
|
return NULL;
|
|
widget = glade_widget_new_full (class, project, parent);
|
|
if (!widget)
|
|
return NULL;
|
|
glade_widget_set_name (widget, widget_name);
|
|
|
|
/* Signals */
|
|
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_SIGNAL))
|
|
continue;
|
|
|
|
signal = glade_signal_new_from_node (child);
|
|
if (signal) {
|
|
glade_widget_add_signal (widget, signal);
|
|
}
|
|
}
|
|
|
|
/* 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, project, widget)) {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/* 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)) {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
gtk_widget_show_all (widget->widget);
|
|
|
|
return widget;
|
|
}
|
|
|
|
#if 0 /* do we still need these 3 functions ? */
|
|
|
|
static GHashTable *
|
|
glade_widget_properties_hash_from_node (GladeXmlNode *node)
|
|
{
|
|
GladeXmlNode *child;
|
|
GHashTable *hash;
|
|
gchar *id;
|
|
gchar *value;
|
|
|
|
if (!glade_xml_node_verify (node, GLADE_XML_TAG_PACKING))
|
|
return NULL;
|
|
|
|
hash = g_hash_table_new_full (g_str_hash,
|
|
g_str_equal,
|
|
g_free,
|
|
g_free);
|
|
|
|
child = glade_xml_node_get_children (node);
|
|
for (; child != NULL; child = glade_xml_node_next (child)) {
|
|
if (!glade_xml_node_verify (child, GLADE_XML_TAG_PROPERTY)) {
|
|
g_hash_table_destroy (hash);
|
|
return NULL;
|
|
}
|
|
|
|
id = glade_xml_get_property_string_required (child, GLADE_XML_TAG_NAME, NULL);
|
|
value = glade_xml_get_content (child);
|
|
|
|
if (!value || !id) {
|
|
g_warning ("Invalid property %s:%s\n", value, id);
|
|
g_hash_table_destroy (hash);
|
|
g_free (value);
|
|
g_free (id);
|
|
return NULL;
|
|
}
|
|
|
|
glade_util_replace (id, '_', '-');
|
|
g_hash_table_insert (hash, id, value);
|
|
}
|
|
|
|
return hash;
|
|
}
|
|
|
|
static void
|
|
glade_widget_apply_property_from_hash_item (gpointer key, gpointer val, gpointer data)
|
|
{
|
|
GladeProperty *property;
|
|
GladeWidget *widget = data;
|
|
GValue *gvalue;
|
|
const gchar *id = key;
|
|
const gchar *value = val;
|
|
|
|
property = glade_property_get_from_id (widget->properties, id);
|
|
g_assert (property);
|
|
|
|
gvalue = glade_property_class_make_gvalue_from_string (property->class,
|
|
value);
|
|
|
|
glade_property_set (property, gvalue);
|
|
}
|
|
|
|
static void
|
|
glade_widget_apply_properties_from_hash (GladeWidget *widget, GHashTable *properties)
|
|
{
|
|
g_hash_table_foreach (properties, glade_widget_apply_property_from_hash_item, widget);
|
|
}
|
|
|
|
#endif
|
|
|
|
static gboolean
|
|
glade_widget_new_child_from_node (GladeXmlNode *node,
|
|
GladeProject *project,
|
|
GladeWidget *parent)
|
|
{
|
|
GladeXmlNode *child_node;
|
|
GladeXmlNode *child_properties;
|
|
GladeWidget *child;
|
|
GtkWidget *child_widget;
|
|
|
|
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) {
|
|
child_widget = glade_placeholder_new ();
|
|
gtk_container_add (GTK_CONTAINER (parent->widget), child_widget);
|
|
return TRUE;
|
|
}
|
|
|
|
/* Get and create the widget */
|
|
child_node = glade_xml_search_child_required (node, GLADE_XML_TAG_WIDGET);
|
|
if (!child_node)
|
|
return FALSE;
|
|
|
|
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;
|
|
|
|
child_widget = child->widget;
|
|
|
|
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) {
|
|
child_properties = glade_xml_node_get_children (child_node);
|
|
|
|
for (; child_properties; child_properties = glade_xml_node_next (child_properties)) {
|
|
GladeProperty *property;
|
|
char *id;
|
|
char *value;
|
|
GValue *gvalue;
|
|
|
|
/* we should be on a <property ...> tag */
|
|
if (!glade_xml_node_verify (child_properties, GLADE_XML_TAG_PROPERTY))
|
|
continue;
|
|
|
|
/* the tag should have the form <property name="...id...">...value...</property>*/
|
|
id = glade_xml_get_property_string_required (child_properties, GLADE_XML_TAG_NAME, NULL);
|
|
value = glade_xml_get_content (child_properties);
|
|
|
|
if (!value || !id) {
|
|
g_warning ("Invalid property %s:%s\n", value, id);
|
|
g_free (value);
|
|
g_free (id);
|
|
continue;
|
|
}
|
|
|
|
glade_util_replace (id, '_', '-');
|
|
property = glade_property_get_from_id (child->packing_properties, id);
|
|
|
|
if (property == NULL) {
|
|
g_warning ("Could not apply property from node. Id :%s\n",
|
|
id);
|
|
continue;
|
|
}
|
|
|
|
gvalue = glade_property_class_make_gvalue_from_string (property->class,
|
|
value);
|
|
|
|
glade_property_set (property, gvalue);
|
|
|
|
g_free (value);
|
|
g_free (id);
|
|
g_free (gvalue);
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
GladeWidget *
|
|
glade_widget_new_from_node (GladeXmlNode *node, GladeProject *project)
|
|
{
|
|
return glade_widget_new_from_node_real (node, project, NULL);
|
|
}
|
|
|