glade/plugins/gtk+/glade-gtk.c
2010-12-30 01:15:19 +09:00

10988 lines
308 KiB
C

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* Copyright (C) 2001 Ximian, Inc.
* Copyright (C) 2004 - 2008 Tristan Van Berkom, Juan Pablo Ugarte et al.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Authors:
* Chema Celorio <chema@celorio.com>
* Tristan Van Berkom <tvb@gnome.org>
* Juan Pablo Ugarte <juanpablougarte@gmail.com>
*/
#include <config.h>
#include "glade-gtk.h"
#include "fixed-bg.xpm"
#include "glade-accels.h"
#include "glade-attributes.h"
#include "glade-column-types.h"
#include "glade-model-data.h"
#include "glade-icon-sources.h"
#include "glade-button-editor.h"
#include "glade-tool-button-editor.h"
#include "glade-image-editor.h"
#include "glade-image-item-editor.h"
#include "glade-icon-factory-editor.h"
#include "glade-store-editor.h"
#include "glade-label-editor.h"
#include "glade-cell-renderer-editor.h"
#include "glade-treeview-editor.h"
#include "glade-entry-editor.h"
#include "glade-activatable-editor.h"
#include <gladeui/glade-editor-property.h>
#include <gladeui/glade-base-editor.h>
#include <gladeui/glade-xml-utils.h>
#include <gtk/gtk.h>
#include <glib/gi18n-lib.h>
#include <string.h>
#include <stdlib.h>
/* --------------------------------- Constants ------------------------------ */
#define FIXED_DEFAULT_CHILD_WIDTH 100
#define FIXED_DEFAULT_CHILD_HEIGHT 60
#define MNEMONIC_INSENSITIVE_MSG _("This property does not apply unless Use Underline is set.")
#define NOT_SELECTED_MSG _("Property not selected")
#define RESPID_INSENSITIVE_MSG _("This property is only for use in dialog action buttons")
#define ACTION_APPEARANCE_MSG _("This property is set to be controlled by an Action")
/* -------------------------------- ParamSpecs ------------------------------ */
/* Fake GtkImage::icon-size since its an int pspec in the image */
GParamSpec *
gladegtk_icon_size_spec (void)
{
return g_param_spec_enum ("icon-size", _("Icon Size"),
_("Symbolic size to use for stock icon, icon set or named icon"),
GTK_TYPE_ICON_SIZE,
GTK_ICON_SIZE_BUTTON,
G_PARAM_READWRITE);
}
/* This function does absolutely nothing
* (and is for use in overriding post_create functions).
*/
void
empty (GObject *container, GladeCreateReason reason)
{
}
/* This function is used to stop default handlers */
static void
glade_gtk_stop_emission_POINTER (gpointer instance, gpointer dummy, gpointer data)
{
g_signal_stop_emission (instance, GPOINTER_TO_UINT (data) , 0);
}
/* Initialize needed pspec types from here */
void
glade_gtk_init (const gchar *name)
{
}
/* ----------------------------- GtkWidget ------------------------------ */
gboolean
glade_gtk_widget_depends (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeWidget *another)
{
if (GTK_IS_ICON_FACTORY (another->object) ||
GTK_IS_ACTION (another->object) ||
GTK_IS_ACTION_GROUP (another->object))
return TRUE;
return GWA_GET_CLASS (G_TYPE_OBJECT)->depends (adaptor, widget, another);
}
#define GLADE_TAG_A11Y_A11Y "accessibility"
#define GLADE_TAG_A11Y_ACTION_NAME "action_name" /* We should make -/_ synonymous */
#define GLADE_TAG_A11Y_DESC "description"
#define GLADE_TAG_A11Y_TARGET "target"
#define GLADE_TAG_A11Y_TYPE "type"
#define GLADE_TAG_A11Y_INTERNAL_NAME "accessible"
#define GLADE_TAG_ATTRIBUTES "attributes"
#define GLADE_TAG_ATTRIBUTE "attribute"
#define GLADE_TAG_A11Y_RELATION "relation"
#define GLADE_TAG_A11Y_ACTION "action"
#define GLADE_TAG_A11Y_PROPERTY "property"
static const gchar *atk_relations_list[] = {
"controlled-by",
"controller-for",
"labelled-by",
"label-for",
"member-of",
"node-child-of",
"flows-to",
"flows-from",
"subwindow-of",
"embeds",
"embedded-by",
"popup-for",
"parent-window-of",
"described-by",
"description-for",
NULL
};
static void
glade_gtk_read_accels (GladeWidget *widget,
GladeXmlNode *node,
gboolean require_signal)
{
GladeProperty *property;
GladeXmlNode *prop;
GladeAccelInfo *ainfo;
GValue *value = NULL;
GList *accels = NULL;
for (prop = glade_xml_node_get_children (node);
prop; prop = glade_xml_node_next (prop))
{
if (!glade_xml_node_verify_silent (prop, GLADE_TAG_ACCEL))
continue;
if ((ainfo = glade_accel_read (prop, require_signal)) != NULL)
accels = g_list_prepend (accels, ainfo);
}
if (accels)
{
value = g_new0 (GValue, 1);
g_value_init (value, GLADE_TYPE_ACCEL_GLIST);
g_value_take_boxed (value, accels);
property = glade_widget_get_property (widget, "accelerator");
glade_property_set_value (property, value);
g_value_unset (value);
g_free (value);
}
}
static void
glade_gtk_parse_atk_props (GladeWidget *widget,
GladeXmlNode *node)
{
GladeXmlNode *prop;
GladeProperty *property;
GValue *gvalue;
gchar *value, *name, *id, *comment;
gint translatable;
gboolean is_action;
for (prop = glade_xml_node_get_children (node);
prop; prop = glade_xml_node_next (prop))
{
if (glade_xml_node_verify_silent (prop, GLADE_TAG_A11Y_PROPERTY))
is_action = FALSE;
else if (glade_xml_node_verify_silent (prop, GLADE_TAG_A11Y_ACTION))
is_action = TRUE;
else
continue;
if (!is_action &&
!(name = glade_xml_get_property_string_required
(prop, GLADE_XML_TAG_NAME, NULL)))
continue;
else if (is_action &&
!(name = glade_xml_get_property_string_required
(prop, GLADE_TAG_A11Y_ACTION_NAME, NULL)))
continue;
/* Make sure we are working with dashes and
* not underscores ...
*/
id = glade_util_read_prop_name (name);
g_free (name);
/* We are namespacing the action properties internally
* just incase they clash (all property names must be
* unique...)
*/
if (is_action)
{
name = g_strdup_printf ("atk-%s", id);
g_free (id);
id = name;
}
if ((property = glade_widget_get_property (widget, id)) != NULL)
{
/* Complex statement just getting the value here... */
if ((!is_action &&
!(value = glade_xml_get_content (prop))) ||
(is_action &&
!(value = glade_xml_get_property_string_required
(prop, GLADE_TAG_A11Y_DESC, NULL))))
{
/* XXX should be a glade_xml_get_content_required()... */
g_free (id);
continue;
}
/* Set the parsed value on the property ... */
gvalue = glade_property_class_make_gvalue_from_string
(property->klass, value, widget->project, widget);
glade_property_set_value (property, gvalue);
g_value_unset (gvalue);
g_free (gvalue);
/* Deal with i18n... ... XXX Do i18n context !!! */
translatable = glade_xml_get_property_boolean
(prop, GLADE_TAG_TRANSLATABLE, FALSE);
comment = glade_xml_get_property_string
(prop, GLADE_TAG_COMMENT);
glade_property_i18n_set_translatable
(property, translatable);
glade_property_i18n_set_comment
(property, comment);
g_free (comment);
g_free (value);
}
g_free (id);
}
}
static void
glade_gtk_parse_atk_props_gtkbuilder (GladeWidget *widget,
GladeXmlNode *node)
{
GladeXmlNode *child, *object_node;
gchar *internal;
/* Search for internal "accessible" child and redirect parse from there */
for (child = glade_xml_node_get_children (node);
child; child = glade_xml_node_next (child))
{
if (glade_xml_node_verify_silent (child, GLADE_XML_TAG_CHILD))
{
if ((internal =
glade_xml_get_property_string (child, GLADE_XML_TAG_INTERNAL_CHILD)))
{
if (!strcmp (internal, GLADE_TAG_A11Y_INTERNAL_NAME) &&
(object_node =
glade_xml_search_child_required (child, GLADE_XML_TAG_WIDGET)))
glade_gtk_parse_atk_props (widget, object_node);
g_free (internal);
}
}
}
}
static void
glade_gtk_parse_atk_relation (GladeProperty *property,
GladeXmlNode *node)
{
GladeXmlNode *prop;
gchar *type, *target, *id, *tmp;
gchar *string = NULL;
for (prop = glade_xml_node_get_children (node);
prop; prop = glade_xml_node_next (prop))
{
if (!glade_xml_node_verify_silent (prop, GLADE_TAG_A11Y_RELATION))
continue;
if (!(type =
glade_xml_get_property_string_required
(prop, GLADE_TAG_A11Y_TYPE, NULL)))
continue;
if (!(target =
glade_xml_get_property_string_required
(prop, GLADE_TAG_A11Y_TARGET, NULL)))
{
g_free (type);
continue;
}
id = glade_util_read_prop_name (type);
if (!strcmp (id, property->klass->id))
{
if (string == NULL)
string = g_strdup (target);
else
{
tmp = g_strdup_printf ("%s%s%s", string,
GPC_OBJECT_DELIMITER, target);
string = (g_free (string), tmp);
}
}
g_free (id);
g_free (type);
g_free (target);
}
/* we must synchronize this directly after loading this project
* (i.e. lookup the actual objects after they've been parsed and
* are present). this is a feature of object and object list properties
* that needs a better api.
*/
if (string)
{
g_object_set_data_full (G_OBJECT (property), "glade-loaded-object",
g_strdup (string), g_free);
}
}
static void
glade_gtk_widget_read_atk_props (GladeWidget *widget,
GladeXmlNode *node)
{
GladeXmlNode *atk_node;
GladeProperty *property;
gint i;
glade_gtk_parse_atk_props_gtkbuilder (widget, node);
if ((atk_node =
glade_xml_search_child (node, GLADE_TAG_A11Y_A11Y)) != NULL)
{
/* Properties & actions */
glade_gtk_parse_atk_props (widget, atk_node);
/* Relations */
for (i = 0; atk_relations_list[i]; i++)
{
if ((property =
glade_widget_get_property (widget,
atk_relations_list[i])))
glade_gtk_parse_atk_relation (property, atk_node);
else
g_warning ("Couldnt find atk relation %s",
atk_relations_list[i]);
}
}
}
void
glade_gtk_widget_read_widget (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlNode *node)
{
if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
return;
/* First chain up and read in all the normal properties.. */
GWA_GET_CLASS (G_TYPE_OBJECT)->read_widget (adaptor, widget, node);
/* Read in accelerators */
glade_gtk_read_accels (widget, node, TRUE);
/* Read in atk props */
glade_gtk_widget_read_atk_props (widget, node);
}
static void
glade_gtk_widget_write_atk_property (GladeProperty *property,
GladeXmlContext *context,
GladeXmlNode *node)
{
GladeXmlNode *prop_node;
gchar *value;
glade_property_get (property, &value);
if (value && value[0])
{
prop_node = glade_xml_node_new (context, GLADE_TAG_A11Y_PROPERTY);
glade_xml_node_append_child (node, prop_node);
glade_xml_node_set_property_string (prop_node,
GLADE_TAG_NAME,
property->klass->id);
glade_xml_set_content (prop_node, value);
/* XXX Do context !!! */
if (property->i18n_translatable)
glade_xml_node_set_property_string (prop_node,
GLADE_TAG_TRANSLATABLE,
GLADE_XML_TAG_I18N_TRUE);
if (property->i18n_comment)
glade_xml_node_set_property_string (prop_node,
GLADE_TAG_COMMENT,
property->i18n_comment);
}
}
static void
glade_gtk_widget_write_atk_properties (GladeWidget *widget,
GladeXmlContext *context,
GladeXmlNode *node)
{
GladeXmlNode *child_node, *object_node;
GladeProperty *name_prop, *desc_prop;
name_prop = glade_widget_get_property (widget, "AtkObject::accessible-name");
desc_prop = glade_widget_get_property (widget, "AtkObject::accessible-description");
/* Create internal child here if any of these properties are non-null */
if (!glade_property_default (name_prop) ||
!glade_property_default (desc_prop))
{
gchar *atkname = g_strdup_printf ("%s-atkobject", widget->name);
child_node = glade_xml_node_new (context, GLADE_XML_TAG_CHILD);
glade_xml_node_append_child (node, child_node);
glade_xml_node_set_property_string (child_node,
GLADE_XML_TAG_INTERNAL_CHILD,
GLADE_TAG_A11Y_INTERNAL_NAME);
object_node = glade_xml_node_new (context, GLADE_XML_TAG_WIDGET);
glade_xml_node_append_child (child_node, object_node);
glade_xml_node_set_property_string (object_node,
GLADE_XML_TAG_CLASS,
"AtkObject");
glade_xml_node_set_property_string (object_node,
GLADE_XML_TAG_ID,
atkname);
if (!glade_property_default (name_prop))
glade_gtk_widget_write_atk_property (name_prop, context, object_node);
if (!glade_property_default (desc_prop))
glade_gtk_widget_write_atk_property (desc_prop, context, object_node);
g_free (atkname);
}
}
static void
glade_gtk_widget_write_atk_relation (GladeProperty *property,
GladeXmlContext *context,
GladeXmlNode *node)
{
GladeXmlNode *prop_node;
gchar *value, **split;
gint i;
if ((value = glade_widget_adaptor_string_from_value
(GLADE_WIDGET_ADAPTOR (property->klass->handle),
property->klass, property->value)) != NULL)
{
if ((split = g_strsplit (value, GPC_OBJECT_DELIMITER, 0)) != NULL)
{
for (i = 0; split[i] != NULL; i++)
{
prop_node = glade_xml_node_new (context,
GLADE_TAG_A11Y_RELATION);
glade_xml_node_append_child (node, prop_node);
glade_xml_node_set_property_string (prop_node,
GLADE_TAG_A11Y_TYPE,
property->klass->id);
glade_xml_node_set_property_string (prop_node,
GLADE_TAG_A11Y_TARGET,
split[i]);
}
g_strfreev (split);
}
}
}
static void
glade_gtk_widget_write_atk_relations (GladeWidget *widget,
GladeXmlContext *context,
GladeXmlNode *node)
{
GladeProperty *property;
gint i;
for (i = 0; atk_relations_list[i]; i++)
{
if ((property =
glade_widget_get_property (widget,
atk_relations_list[i])))
glade_gtk_widget_write_atk_relation (property, context, node);
else
g_warning ("Couldnt find atk relation %s on widget %s",
atk_relations_list[i], widget->name);
}
}
static void
glade_gtk_widget_write_atk_action (GladeProperty *property,
GladeXmlContext *context,
GladeXmlNode *node)
{
GladeXmlNode *prop_node;
gchar *value = NULL;
glade_property_get (property, &value);
if (value && value[0])
{
prop_node = glade_xml_node_new (context, GLADE_TAG_A11Y_ACTION);
glade_xml_node_append_child (node, prop_node);
glade_xml_node_set_property_string (prop_node,
GLADE_TAG_A11Y_ACTION_NAME,
&property->klass->id[4]);
glade_xml_node_set_property_string (prop_node,
GLADE_TAG_A11Y_DESC,
value);
}
}
static void
glade_gtk_widget_write_atk_actions (GladeWidget *widget,
GladeXmlContext *context,
GladeXmlNode *node)
{
GladeProperty *property;
if ((property = glade_widget_get_property (widget, "atk-click")) != NULL)
glade_gtk_widget_write_atk_action (property, context, node);
if ((property = glade_widget_get_property (widget, "atk-activate")) != NULL)
glade_gtk_widget_write_atk_action (property, context, node);
if ((property = glade_widget_get_property (widget, "atk-press")) != NULL)
glade_gtk_widget_write_atk_action (property, context, node);
if ((property = glade_widget_get_property (widget, "atk-release")) != NULL)
glade_gtk_widget_write_atk_action (property, context, node);
}
static void
glade_gtk_widget_write_atk_props (GladeWidget *widget,
GladeXmlContext *context,
GladeXmlNode *node)
{
GladeXmlNode *atk_node;
atk_node = glade_xml_node_new (context, GLADE_TAG_A11Y_A11Y);
glade_gtk_widget_write_atk_relations (widget, context, atk_node);
glade_gtk_widget_write_atk_actions (widget, context, atk_node);
if (!glade_xml_node_get_children (atk_node))
glade_xml_node_delete (atk_node);
else
glade_xml_node_append_child (node, atk_node);
glade_gtk_widget_write_atk_properties (widget, context, node);
}
static void
glade_gtk_write_accels (GladeWidget *widget,
GladeXmlContext *context,
GladeXmlNode *node,
gboolean write_signal)
{
GladeXmlNode *accel_node;
GladeProperty *property;
GList *list;
/* Some child widgets may have disabled the property */
if (!(property = glade_widget_get_property (widget, "accelerator")))
return;
for (list = g_value_get_boxed (property->value);
list; list = list->next)
{
GladeAccelInfo *accel = list->data;
accel_node = glade_accel_write (accel, context, write_signal);
glade_xml_node_append_child (node, accel_node);
}
}
void
glade_gtk_widget_write_widget (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlContext *context,
GladeXmlNode *node)
{
if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
return;
/* First chain up and read in all the normal properties.. */
GWA_GET_CLASS (G_TYPE_OBJECT)->write_widget (adaptor, widget, context, node);
/* The core takes care of signals */
glade_gtk_write_accels (widget, context, node, TRUE);
glade_gtk_widget_write_atk_props (widget, context, node);
}
GladeEditorProperty *
glade_gtk_widget_create_eprop (GladeWidgetAdaptor *adaptor,
GladePropertyClass *klass,
gboolean use_command)
{
GladeEditorProperty *eprop;
/* chain up.. */
if (klass->pspec->value_type == GLADE_TYPE_ACCEL_GLIST)
eprop = g_object_new (GLADE_TYPE_EPROP_ACCEL,
"property-class", klass,
"use-command", use_command,
NULL);
else
eprop = GWA_GET_CLASS
(G_TYPE_OBJECT)->create_eprop (adaptor,
klass,
use_command);
return eprop;
}
gchar *
glade_gtk_widget_string_from_value (GladeWidgetAdaptor *adaptor,
GladePropertyClass *klass,
const GValue *value)
{
if (klass->pspec->value_type == GLADE_TYPE_ACCEL_GLIST)
return glade_accels_make_string (g_value_get_boxed (value));
else
return GWA_GET_CLASS
(G_TYPE_OBJECT)->string_from_value (adaptor,
klass,
value);
}
static void
widget_parent_changed (GtkWidget *widget,
GParamSpec *pspec,
GladeWidgetAdaptor *adaptor)
{
GladeWidget *gwidget = glade_widget_get_from_gobject (widget);
/* this could get called for a stale instance of an object
* being rebuilt for a contruct-only property. */
if (!gwidget)
return;
if (gwidget->parent && gwidget->parent->internal == NULL)
glade_widget_set_action_sensitive (gwidget, "remove_parent", TRUE);
else
glade_widget_set_action_sensitive (gwidget, "remove_parent", FALSE);
}
void
glade_gtk_widget_deep_post_create (GladeWidgetAdaptor *adaptor,
GObject *widget,
GladeCreateReason reason)
{
GladeWidget *gwidget = glade_widget_get_from_gobject (widget);
/* Work around bug 472555 by resetting the default event mask,
* this way only user edits will be saved to the glade file. */
if (reason == GLADE_CREATE_USER)
glade_widget_property_reset (gwidget, "events");
glade_widget_set_action_sensitive (gwidget, "remove_parent", FALSE);
if (GWA_IS_TOPLEVEL (adaptor) || gwidget->internal)
glade_widget_set_action_sensitive (gwidget, "add_parent", FALSE);
/* Watch parents/projects and set actions sensitive/insensitive */
if (gwidget->internal == NULL)
g_signal_connect (G_OBJECT (widget), "notify::parent",
G_CALLBACK (widget_parent_changed), adaptor);
}
void
glade_gtk_widget_set_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *id,
const GValue *value)
{
/* FIXME: is this still needed with the new gtk+ tooltips? */
if (!strcmp (id, "tooltip"))
{
id = "tooltip-text";
}
GWA_GET_CLASS (G_TYPE_OBJECT)->set_property (adaptor, object, id, value);
}
void
glade_gtk_widget_get_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *id,
GValue *value)
{
if (!strcmp (id, "tooltip"))
{
id = "tooltip-text";
}
GWA_GET_CLASS (G_TYPE_OBJECT)->get_property (adaptor, object, id, value);
}
static GList *
create_command_property_list (GladeWidget *gnew, GList *saved_props)
{
GList *l, *command_properties = NULL;
for (l = saved_props; l; l = l->next)
{
GladeProperty *property = l->data;
GladeProperty *orig_prop = glade_widget_get_pack_property (gnew, property->klass->id);
GCSetPropData *pdata = g_new0 (GCSetPropData, 1);
pdata->property = orig_prop;
pdata->old_value = g_new0 (GValue, 1);
pdata->new_value = g_new0 (GValue, 1);
glade_property_get_value (orig_prop, pdata->old_value);
glade_property_get_value (property, pdata->new_value);
command_properties = g_list_prepend (command_properties, pdata);
}
return g_list_reverse (command_properties);
}
void
glade_gtk_widget_action_activate (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *action_path)
{
GladeWidget *gwidget = glade_widget_get_from_gobject (object), *gparent;
GList this_widget = { 0, }, that_widget = { 0, };
GtkWidget *parent = gtk_widget_get_parent (GTK_WIDGET (object));
GladeProject *project;
if (parent)
gparent = glade_widget_get_from_gobject (parent);
else
gparent = NULL;
if (strcmp (action_path, "preview") == 0)
{
project = glade_widget_get_project (gwidget);
glade_project_preview (project,
glade_widget_get_from_gobject((gpointer)object)
);
}
else if (strcmp (action_path, "edit_separate") == 0)
{
GtkWidget *dialog =
glade_editor_dialog_for_widget (gwidget);
gtk_widget_show_all (dialog);
}
else if (strcmp (action_path, "remove_parent") == 0)
{
GladeWidget *new_gparent;
g_return_if_fail (gparent);
new_gparent = gparent->parent;
glade_command_push_group (_("Removing parent of %s"),
gwidget->name);
/* Remove "this" widget */
this_widget.data = gwidget;
glade_command_cut (&this_widget);
/* Delete the parent */
that_widget.data = gparent;
glade_command_delete (&that_widget);
/* Add "this" widget to the new parent */
glade_command_paste(&this_widget, new_gparent, NULL);
glade_command_pop_group ();
}
else if (strncmp (action_path, "add_parent/", 11) == 0)
{
GType new_type = 0;
if (strcmp (action_path + 11, "alignment") == 0)
new_type = GTK_TYPE_ALIGNMENT;
else if (strcmp (action_path + 11, "viewport") == 0)
new_type = GTK_TYPE_VIEWPORT;
else if (strcmp (action_path + 11, "eventbox") == 0)
new_type = GTK_TYPE_EVENT_BOX;
else if (strcmp (action_path + 11, "frame") == 0)
new_type = GTK_TYPE_FRAME;
else if (strcmp (action_path + 11, "aspect_frame") == 0)
new_type = GTK_TYPE_ASPECT_FRAME;
else if (strcmp (action_path + 11, "scrolled_window") == 0)
new_type = GTK_TYPE_SCROLLED_WINDOW;
else if (strcmp (action_path + 11, "expander") == 0)
new_type = GTK_TYPE_EXPANDER;
else if (strcmp (action_path + 11, "table") == 0)
new_type = GTK_TYPE_TABLE;
else if (strcmp (action_path + 11, "hbox") == 0)
new_type = GTK_TYPE_HBOX;
else if (strcmp (action_path + 11, "vbox") == 0)
new_type = GTK_TYPE_VBOX;
else if (strcmp (action_path + 11, "hpaned") == 0)
new_type = GTK_TYPE_HPANED;
else if (strcmp (action_path + 11, "vpaned") == 0)
new_type = GTK_TYPE_VPANED;
if (new_type)
{
GladeWidgetAdaptor *adaptor = glade_widget_adaptor_get_by_type (new_type);
GList *saved_props, *prop_cmds;
GladeProject *project;
/* Dont add non-scrollable widgets to scrolled windows... */
if (gparent &&
glade_util_check_and_warn_scrollable (gparent, adaptor, glade_app_get_window()))
return;
glade_command_push_group (_("Adding parent %s for %s"),
adaptor->title, gwidget->name);
/* Record packing properties */
saved_props = glade_widget_dup_properties (gwidget, gwidget->packing_properties, FALSE, FALSE, FALSE);
/* Remove "this" widget */
this_widget.data = gwidget;
glade_command_cut (&this_widget);
if (gparent)
project = glade_widget_get_project (gparent);
else
project = glade_app_get_project ();
/* Create new widget and put it where the placeholder was */
if ((that_widget.data =
glade_command_create (adaptor, gparent, NULL, project)) != NULL)
{
/* Remove the alignment that we added in the frame's post_create... */
if (new_type == GTK_TYPE_FRAME)
{
GObject *frame = glade_widget_get_object (that_widget.data);
GladeWidget *galign = glade_widget_get_from_gobject (gtk_bin_get_child (GTK_BIN (frame)));
GList to_delete = { 0, };
to_delete.data = galign;
glade_command_delete (&to_delete);
}
/* Create heavy-duty glade-command properties stuff */
prop_cmds = create_command_property_list (that_widget.data, saved_props);
g_list_foreach (saved_props, (GFunc)g_object_unref, NULL);
g_list_free (saved_props);
/* Apply the properties in an undoable way */
if (prop_cmds)
glade_command_set_properties_list (glade_widget_get_project (gparent), prop_cmds);
/* Add "this" widget to the new parent */
glade_command_paste(&this_widget, GLADE_WIDGET (that_widget.data), NULL);
}
else
/* Create parent was cancelled, paste back to parent */
glade_command_paste(&this_widget, gparent, NULL);
glade_command_pop_group ();
}
}
else if (strcmp (action_path, "sizegroup_add") == 0)
{
/* Ignore dummy */
}
else
GWA_GET_CLASS (G_TYPE_OBJECT)->action_activate (adaptor,
object,
action_path);
}
static GList *list_sizegroups (GladeWidget *gwidget)
{
GladeProject *project = glade_widget_get_project (gwidget);
GList *groups = NULL;
const GList *list;
for (list = glade_project_get_objects (project); list; list = list->next)
{
GladeWidget *iter = glade_widget_get_from_gobject (list->data);
if (GTK_IS_SIZE_GROUP (iter->object))
groups = g_list_prepend (groups, iter);
}
return g_list_reverse (groups);
}
static void
glade_gtk_widget_add2group_cb (GtkMenuItem *item, GladeWidget *gwidget)
{
GladeWidget *group = g_object_get_data (G_OBJECT (item), "glade-group-widget");
GladeWidgetAdaptor *adaptor = glade_widget_adaptor_get_by_type (GTK_TYPE_SIZE_GROUP);
GList *widget_list = NULL, *new_list;
GladeProperty *property;
if (group)
glade_command_push_group (_("Adding %s to Size Group %s"), gwidget->name, group->name);
else
glade_command_push_group (_("Adding %s to a new Size Group"), gwidget->name);
if (!group)
/* Cant cancel a size group */
group = glade_command_create (adaptor, NULL, NULL, glade_widget_get_project (gwidget));
property = glade_widget_get_property (group, "widgets");
glade_property_get (property, &widget_list);
new_list = g_list_copy (widget_list);
if (!g_list_find (widget_list, gwidget->object))
new_list = g_list_append (new_list, gwidget->object);
glade_command_set_property (property, new_list);
g_list_free (new_list);
glade_command_pop_group ();
}
GtkWidget *
glade_gtk_widget_action_submenu (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *action_path)
{
GladeWidget *gwidget = glade_widget_get_from_gobject (object);
GList *groups, *list;
if (strcmp (action_path, "sizegroup_add") == 0)
{
GtkWidget *menu = gtk_menu_new ();
GtkWidget *separator, *item;
GladeWidget *group;
if ((groups = list_sizegroups (gwidget)) != NULL)
{
for (list = groups; list; list = list->next)
{
group = list->data;
item = gtk_menu_item_new_with_label (group->name);
g_object_set_data (G_OBJECT (item), "glade-group-widget", group);
g_signal_connect (G_OBJECT (item), "activate",
G_CALLBACK (glade_gtk_widget_add2group_cb), gwidget);
gtk_widget_show (item);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
}
g_list_free (groups);
separator = gtk_menu_item_new ();
gtk_menu_shell_append (GTK_MENU_SHELL (menu), separator);
gtk_widget_show (separator);
}
/* Add trailing new... item */
item = gtk_menu_item_new_with_label (_("New Size Group"));
g_signal_connect (G_OBJECT (item), "activate",
G_CALLBACK (glade_gtk_widget_add2group_cb), gwidget);
gtk_widget_show (item);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
return menu;
}
else if (GWA_GET_CLASS (G_TYPE_OBJECT)->action_submenu)
return GWA_GET_CLASS (G_TYPE_OBJECT)->action_submenu (adaptor,
object,
action_path);
return NULL;
}
/* ----------------------------- GtkContainer ------------------------------ */
void
glade_gtk_container_post_create (GladeWidgetAdaptor *adaptor,
GObject *container,
GladeCreateReason reason)
{
GList *children;
g_return_if_fail (GTK_IS_CONTAINER (container));
if (reason == GLADE_CREATE_USER)
{
if ((children = gtk_container_get_children (GTK_CONTAINER (container))) == NULL)
gtk_container_add (GTK_CONTAINER (container), glade_placeholder_new ());
else
g_list_free (children);
}
}
void
glade_gtk_container_replace_child (GladeWidgetAdaptor *adaptor,
GtkWidget *container,
GtkWidget *current,
GtkWidget *new_widget)
{
GParamSpec **param_spec;
GladePropertyClass *pclass;
GValue *value;
guint nproperties;
guint i;
if (gtk_widget_get_parent (current) != container)
return;
param_spec = gtk_container_class_list_child_properties
(G_OBJECT_GET_CLASS (container), &nproperties);
value = g_malloc0 (sizeof(GValue) * nproperties);
for (i = 0; i < nproperties; i++)
{
g_value_init (&value[i], param_spec[i]->value_type);
gtk_container_child_get_property
(GTK_CONTAINER (container), current, param_spec[i]->name, &value[i]);
}
gtk_container_remove (GTK_CONTAINER (container), current);
gtk_container_add (GTK_CONTAINER (container), new_widget);
for (i = 0; i < nproperties; i++)
{
/* If the added widget is a placeholder then we
* want to keep all the "tranfer-on-paste" properties
* as default so that it looks fresh (transfer-on-paste
* properties dont effect the position/slot inside a
* contianer)
*/
if (GLADE_IS_PLACEHOLDER (new_widget))
{
pclass = glade_widget_adaptor_get_pack_property_class
(adaptor, param_spec[i]->name);
if (pclass && pclass->transfer_on_paste)
continue;
}
gtk_container_child_set_property
(GTK_CONTAINER (container), new_widget, param_spec[i]->name, &value[i]);
}
for (i = 0; i < nproperties; i++)
g_value_unset (&value[i]);
g_free (param_spec);
g_free (value);
}
void
glade_gtk_container_add_child (GladeWidgetAdaptor *adaptor,
GtkWidget *container,
GtkWidget *child)
{
GtkWidget *container_child = NULL;
if (GTK_IS_BIN (container))
container_child = gtk_bin_get_child (GTK_BIN (container));
/* Get a placeholder out of the way before adding the child if its a GtkBin
*/
if (GTK_IS_BIN (container) && container_child != NULL &&
GLADE_IS_PLACEHOLDER (container_child))
gtk_container_remove (GTK_CONTAINER (container), container_child);
gtk_container_add (GTK_CONTAINER (container), child);
}
void
glade_gtk_container_remove_child (GladeWidgetAdaptor *adaptor,
GtkWidget *container,
GtkWidget *child)
{
GList *children;
gtk_container_remove (GTK_CONTAINER (container), child);
/* If this is the last one, add a placeholder by default.
*/
if ((children = gtk_container_get_children (GTK_CONTAINER (container))) == NULL)
{
gtk_container_add (GTK_CONTAINER (container), glade_placeholder_new ());
}
else
g_list_free (children);
}
void
glade_gtk_container_set_child_property (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *child,
const gchar *property_name,
const GValue *value)
{
if (gtk_widget_get_parent (GTK_WIDGET (child)) == GTK_WIDGET (container))
gtk_container_child_set_property (GTK_CONTAINER (container),
GTK_WIDGET (child),
property_name, value);
}
void
glade_gtk_container_get_child_property (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *child,
const gchar *property_name,
GValue *value)
{
if (gtk_widget_get_parent (GTK_WIDGET (child)) == GTK_WIDGET (container))
gtk_container_child_get_property (GTK_CONTAINER (container),
GTK_WIDGET (child),
property_name, value);
}
GList *
glade_gtk_container_get_children (GladeWidgetAdaptor *adaptor,
GtkContainer *container)
{
return glade_util_container_get_all_children (container);
}
GladeEditable *
glade_gtk_container_create_editable (GladeWidgetAdaptor *adaptor,
GladeEditorPageType type)
{
return GWA_GET_CLASS (GTK_TYPE_CONTAINER)->create_editable (adaptor, type);;
}
/* ----------------------------- GtkBox ------------------------------ */
typedef struct {
GtkWidget *widget;
gint position;
} GladeGtkBoxChild;
static GList *glade_gtk_box_original_positions = NULL;
static gboolean
glade_gtk_box_configure_child (GladeFixed *fixed,
GladeWidget *child,
GdkRectangle *rect,
GtkWidget *box)
{
GList *list, *children;
GtkWidget *bchild;
GtkAllocation allocation, bchild_allocation;
gint point, trans_point, span,
iter_span, position, old_position,
offset, orig_offset;
gboolean found = FALSE;
gtk_widget_get_allocation (GTK_WIDGET (child->object), &allocation);
if (GTK_IS_HBOX (box) || GTK_IS_HBUTTON_BOX (box))
{
point = fixed->mouse_x;
span = allocation.width;
offset = rect->x;
orig_offset = fixed->child_x_origin;
}
else
{
point = fixed->mouse_y;
span = allocation.height;
offset = rect->y;
orig_offset = fixed->child_y_origin;
}
glade_widget_pack_property_get
(child, "position", &old_position);
children = gtk_container_get_children (GTK_CONTAINER (box));
for (list = children; list; list = list->next)
{
bchild = list->data;
if (bchild == GTK_WIDGET (child->object))
continue;
/* Find the widget in the box where the center of
* this rectangle fits... and set the position to that
* position.
*/
gtk_widget_get_allocation (GTK_WIDGET (bchild), &bchild_allocation);
if (GTK_IS_HBOX (box) || GTK_IS_HBUTTON_BOX (box))
{
gtk_widget_translate_coordinates
(GTK_WIDGET (box), bchild,
point, 0, &trans_point, NULL);
iter_span = bchild_allocation.width;
}
else
{
gtk_widget_translate_coordinates
(GTK_WIDGET (box), bchild,
0, point, NULL, &trans_point);
iter_span = bchild_allocation.height;
}
#if 0
gtk_container_child_get (GTK_CONTAINER (box),
bchild,
"position", &position, NULL);
g_print ("widget: %p pos %d, point %d, trans_point %d, iter_span %d\n",
bchild, position, point, trans_point, iter_span);
#endif
if (iter_span <= span)
{
found = trans_point >= 0 && trans_point < iter_span;
}
else
{
if (offset > orig_offset)
found = trans_point >= iter_span - span &&
trans_point < iter_span;
else if (offset < orig_offset)
found = trans_point >= 0 &&
trans_point < span;
}
if (found)
{
gtk_container_child_get (GTK_CONTAINER (box),
bchild,
"position", &position, NULL);
#if 0
g_print ("setting position of %s from %d to %d, "
"(point %d iter_span %d)\n",
child->name, old_position, position, trans_point, iter_span);
#endif
glade_widget_pack_property_set
(child, "position", position);
break;
}
}
g_list_free (children);
return TRUE;
}
static gboolean
glade_gtk_box_configure_begin (GladeFixed *fixed,
GladeWidget *child,
GtkWidget *box)
{
GList *list, *children;
GtkWidget *bchild;
g_assert (glade_gtk_box_original_positions == NULL);
children = gtk_container_get_children (GTK_CONTAINER (box));
for (list = children; list; list = list->next)
{
GladeGtkBoxChild *gbchild;
GladeWidget *gchild;
bchild = list->data;
if ((gchild = glade_widget_get_from_gobject (bchild)) == NULL)
continue;
gbchild = g_new0 (GladeGtkBoxChild, 1);
gbchild->widget = bchild;
glade_widget_pack_property_get (gchild, "position",
&gbchild->position);
glade_gtk_box_original_positions =
g_list_prepend (glade_gtk_box_original_positions, gbchild);
}
g_list_free (children);
return TRUE;
}
static gboolean
glade_gtk_box_configure_end (GladeFixed *fixed,
GladeWidget *child,
GtkWidget *box)
{
GList *list, *l, *children;
GList *prop_list = NULL;
children = gtk_container_get_children (GTK_CONTAINER (box));
for (list = children; list; list = list->next)
{
GtkWidget *bchild = list->data;
for (l = glade_gtk_box_original_positions; l; l = l->next)
{
GladeGtkBoxChild *gbchild = l->data;
GladeWidget *gchild =
glade_widget_get_from_gobject (gbchild->widget);
if (bchild == gbchild->widget)
{
GCSetPropData *prop_data = g_new0 (GCSetPropData, 1);
prop_data->property =
glade_widget_get_pack_property
(gchild, "position");
prop_data->old_value = g_new0 (GValue, 1);
prop_data->new_value = g_new0 (GValue, 1);
glade_property_get_value (prop_data->property,
prop_data->new_value);
g_value_init (prop_data->old_value, G_TYPE_INT);
g_value_set_int (prop_data->old_value, gbchild->position);
prop_list = g_list_prepend (prop_list, prop_data);
break;
}
}
}
g_list_free (children);
glade_command_push_group (_("Ordering children of %s"),
GLADE_WIDGET (fixed)->name);
glade_property_push_superuser ();
if (prop_list)
glade_command_set_properties_list (GLADE_WIDGET (fixed)->project,
prop_list);
glade_property_pop_superuser ();
glade_command_pop_group ();
for (l = glade_gtk_box_original_positions; l; l = l->next)
g_free (l->data);
glade_gtk_box_original_positions =
(g_list_free (glade_gtk_box_original_positions), NULL);
return TRUE;
}
void
glade_gtk_box_post_create (GladeWidgetAdaptor *adaptor,
GObject *container,
GladeCreateReason reason)
{
GladeWidget *gwidget =
glade_widget_get_from_gobject (container);
/* Implement drag in GtkBox but not resize.
*/
g_object_set (gwidget,
"can-resize", FALSE,
NULL);
g_signal_connect (G_OBJECT (gwidget), "configure-child",
G_CALLBACK (glade_gtk_box_configure_child), container);
g_signal_connect (G_OBJECT (gwidget), "configure-begin",
G_CALLBACK (glade_gtk_box_configure_begin), container);
g_signal_connect (G_OBJECT (gwidget), "configure-end",
G_CALLBACK (glade_gtk_box_configure_end), container);
}
static gint
sort_box_children (GtkWidget *widget_a, GtkWidget *widget_b)
{
GtkWidget *box;
GladeWidget *gwidget_a, *gwidget_b;
gint position_a, position_b;
gwidget_a = glade_widget_get_from_gobject (widget_a);
gwidget_b = glade_widget_get_from_gobject (widget_b);
box = gtk_widget_get_parent (widget_a);
if (gwidget_a)
glade_widget_pack_property_get
(gwidget_a, "position", &position_a);
else
gtk_container_child_get (GTK_CONTAINER (box),
widget_a,
"position", &position_a,
NULL);
if (gwidget_b)
glade_widget_pack_property_get
(gwidget_b, "position", &position_b);
else
gtk_container_child_get (GTK_CONTAINER (box),
widget_b,
"position", &position_b,
NULL);
return position_a - position_b;
}
GList *
glade_gtk_box_get_children (GladeWidgetAdaptor *adaptor,
GtkContainer *container)
{
GList *children = glade_util_container_get_all_children (container);
return g_list_sort (children, (GCompareFunc)sort_box_children);
}
void
glade_gtk_box_set_child_property (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *child,
const gchar *property_name,
GValue *value)
{
GladeWidget *gbox, *gchild, *gchild_iter;
GList *children, *list;
gboolean is_position;
gint old_position, iter_position, new_position;
static gboolean recursion = FALSE;
g_return_if_fail (GTK_IS_BOX (container));
g_return_if_fail (GTK_IS_WIDGET (child));
g_return_if_fail (property_name != NULL || value != NULL);
gbox = glade_widget_get_from_gobject (container);
gchild = glade_widget_get_from_gobject (child);
g_return_if_fail (GLADE_IS_WIDGET (gbox));
if (gtk_widget_get_parent (GTK_WIDGET (child)) != GTK_WIDGET (container))
return;
/* Get old position */
if ((is_position = (strcmp (property_name, "position") == 0)) != FALSE)
{
gtk_container_child_get (GTK_CONTAINER (container),
GTK_WIDGET (child),
property_name, &old_position, NULL);
/* Get the real value */
new_position = g_value_get_int (value);
}
if (is_position && recursion == FALSE)
{
children = glade_widget_adaptor_get_children
(gbox->adaptor, container);
children = g_list_sort (children, (GCompareFunc)sort_box_children);
for (list = children; list; list = list->next)
{
if ((gchild_iter =
glade_widget_get_from_gobject (list->data)) == NULL)
continue;
if (gchild_iter == gchild)
{
gtk_box_reorder_child (GTK_BOX (container),
GTK_WIDGET (child),
new_position);
continue;
}
/* Get the old value from glade */
glade_widget_pack_property_get
(gchild_iter, "position", &iter_position);
/* Search for the child at the old position and update it */
if (iter_position == new_position &&
glade_property_superuser () == FALSE)
{
/* Update glade with the real value */
recursion = TRUE;
glade_widget_pack_property_set
(gchild_iter, "position", old_position);
recursion = FALSE;
continue;
}
else
{
gtk_box_reorder_child (GTK_BOX (container),
GTK_WIDGET (list->data),
iter_position);
}
}
for (list = children; list; list = list->next)
{
if ((gchild_iter =
glade_widget_get_from_gobject (list->data)) == NULL)
continue;
/* Refresh values yet again */
glade_widget_pack_property_get
(gchild_iter, "position", &iter_position);
gtk_box_reorder_child (GTK_BOX (container),
GTK_WIDGET (list->data),
iter_position);
}
if (children)
g_list_free (children);
}
/* Chain Up */
if (!is_position)
GWA_GET_CLASS
(GTK_TYPE_CONTAINER)->child_set_property (adaptor,
container,
child,
property_name,
value);
gtk_container_check_resize (GTK_CONTAINER (container));
}
void
glade_gtk_box_get_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *id,
GValue *value)
{
if (!strcmp (id, "size"))
{
GtkBox *box = GTK_BOX (object);
GList *children = gtk_container_get_children (GTK_CONTAINER (box));
g_value_reset (value);
g_value_set_int (value, g_list_length (children));
g_list_free (children);
}
else
GWA_GET_CLASS (GTK_TYPE_CONTAINER)->get_property (adaptor, object, id, value);
}
static gint
glade_gtk_box_get_first_blank (GtkBox *box)
{
GList *child, *children;
GladeWidget *gwidget;
gint position;
children = gtk_container_get_children (GTK_CONTAINER (box));
for (child = children, position = 0;
child && child->data;
child = child->next, position++)
{
GtkWidget *widget = child->data;
if ((gwidget = glade_widget_get_from_gobject (widget)) != NULL)
{
gint gwidget_position;
GladeProperty *property =
glade_widget_get_pack_property (gwidget, "position");
gwidget_position = g_value_get_int (property->value);
if (gwidget_position > position)
break;
}
}
g_list_free (children);
return position;
}
static void
glade_gtk_box_set_size (GObject *object, const GValue *value)
{
GtkBox *box;
GList *child, *children;
guint new_size, old_size, i;
box = GTK_BOX (object);
g_return_if_fail (GTK_IS_BOX (box));
if (glade_util_object_is_loading (object))
return;
children = gtk_container_get_children (GTK_CONTAINER (box));
old_size = g_list_length (children);
new_size = g_value_get_int (value);
if (old_size == new_size)
{
g_list_free (children);
return;
}
/* Ensure placeholders first...
*/
for (i = 0; i < new_size; i++)
{
if (g_list_length(children) < (i + 1))
{
GtkWidget *placeholder = glade_placeholder_new ();
gint blank = glade_gtk_box_get_first_blank (box);
gtk_container_add (GTK_CONTAINER (box), placeholder);
gtk_box_reorder_child (box, placeholder, blank);
}
}
/* The box has shrunk. Remove the widgets that are on those slots */
for (child = g_list_last (children);
child && old_size > new_size;
child = g_list_last (children), old_size--)
{
GtkWidget *child_widget = child->data;
/* Refuse to remove any widgets that are either GladeWidget objects
* or internal to the hierarchic entity (may be a composite widget,
* not all internal widgets have GladeWidgets).
*/
if (glade_widget_get_from_gobject (child_widget) ||
GLADE_IS_PLACEHOLDER (child_widget) == FALSE)
break;
g_object_ref (G_OBJECT (child_widget));
gtk_container_remove (GTK_CONTAINER (box), child_widget);
gtk_widget_destroy (child_widget);
}
g_list_free (children);
}
void
glade_gtk_box_set_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *id,
const GValue *value)
{
if (!strcmp (id, "size"))
glade_gtk_box_set_size (object, value);
else
GWA_GET_CLASS (GTK_TYPE_CONTAINER)->set_property (adaptor, object, id, value);
}
static gboolean
glade_gtk_box_verify_size (GObject *object, const GValue *value)
{
GtkBox *box = GTK_BOX(object);
GList *child, *children;
gboolean will_orphan = FALSE;
gint old_size;
gint new_size = g_value_get_int (value);
children = gtk_container_get_children (GTK_CONTAINER (box));
old_size = g_list_length (children);
for (child = g_list_last (children);
child && old_size > new_size;
child = g_list_previous (child), old_size--)
{
GtkWidget *widget = child->data;
if (glade_widget_get_from_gobject (widget) != NULL)
{
/* In this case, refuse to shrink */
will_orphan = TRUE;
break;
}
}
g_list_free (children);
return will_orphan ? FALSE : new_size >= 0;
}
gboolean
glade_gtk_box_verify_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *id,
const GValue *value)
{
if (!strcmp (id, "size"))
return glade_gtk_box_verify_size (object, value);
else if (GWA_GET_CLASS (GTK_TYPE_CONTAINER)->verify_property)
return GWA_GET_CLASS (GTK_TYPE_CONTAINER)->verify_property (adaptor, object,
id, value);
return TRUE;
}
static void
fix_response_id_on_child (GladeWidget *gbox,
GObject *child,
gboolean add)
{
GladeWidget *gchild;
const gchar *internal_name;
gchild = glade_widget_get_from_gobject (child);
/* Fix response id property on child buttons */
if (gchild && GTK_IS_BUTTON (child))
{
if (add && (internal_name = glade_widget_get_internal (gbox)) &&
!strcmp (internal_name, "action_area"))
{
glade_widget_property_set_sensitive (gchild, "response-id", TRUE, NULL);
glade_widget_property_set_enabled (gchild, "response-id", TRUE);
}
else
{
glade_widget_property_set_sensitive (gchild, "response-id", FALSE,
RESPID_INSENSITIVE_MSG);
glade_widget_property_set_enabled (gchild, "response-id", FALSE);
}
}
}
void
glade_gtk_box_add_child (GladeWidgetAdaptor *adaptor,
GObject *object,
GObject *child)
{
GladeWidget *gbox, *gchild;
GladeProject *project;
GList *children;
gint num_children;
g_return_if_fail (GTK_IS_BOX (object));
g_return_if_fail (GTK_IS_WIDGET (child));
gbox = glade_widget_get_from_gobject (object);
project = glade_widget_get_project (gbox);
/*
Try to remove the last placeholder if any, this way GtkBox`s size
will not be changed.
*/
if (glade_widget_superuser () == FALSE &&
!GLADE_IS_PLACEHOLDER (child))
{
GList *l, *children;
GtkBox *box = GTK_BOX (object);
children = gtk_container_get_children (GTK_CONTAINER (box));
for (l = g_list_last (children); l; l = g_list_previous (l))
{
GtkWidget *child_widget = l->data;
if (GLADE_IS_PLACEHOLDER (child_widget))
{
gtk_container_remove (GTK_CONTAINER (box), child_widget);
break;
}
}
g_list_free (children);
}
gtk_container_add (GTK_CONTAINER (object), GTK_WIDGET (child));
children = gtk_container_get_children (GTK_CONTAINER (object));
num_children = g_list_length (children);
g_list_free (children);
glade_widget_property_set (gbox, "size", num_children);
gchild = glade_widget_get_from_gobject (child);
/* The "Remove Slot" operation only makes sence on placeholders,
* otherwise its a "Delete" operation on the child widget.
*/
if (gchild)
glade_widget_remove_pack_action (gchild, "remove_slot");
/* Packing props arent around when parenting during a glade_widget_dup() */
if (gchild && gchild->packing_properties)
glade_widget_pack_property_set (gchild, "position", num_children - 1);
fix_response_id_on_child (gbox, child, TRUE);
}
void
glade_gtk_box_remove_child (GladeWidgetAdaptor *adaptor,
GObject *object,
GObject *child)
{
GladeWidget *gbox;
gint size;
g_return_if_fail (GTK_IS_BOX (object));
g_return_if_fail (GTK_IS_WIDGET (child));
gbox = glade_widget_get_from_gobject (object);
gtk_container_remove (GTK_CONTAINER (object), GTK_WIDGET (child));
if (glade_widget_superuser () == FALSE)
{
glade_widget_property_get (gbox, "size", &size);
glade_widget_property_set (gbox, "size", size);
}
fix_response_id_on_child (gbox, child, FALSE);
}
void
glade_gtk_box_replace_child (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *current,
GObject *new_widget)
{
GladeWidget *gchild;
GladeWidget *gbox;
g_object_ref (G_OBJECT (current));
GWA_GET_CLASS (GTK_TYPE_CONTAINER)->replace_child (adaptor,
container,
current,
new_widget);
if ((gchild = glade_widget_get_from_gobject (new_widget)) != NULL)
/* The "Remove Slot" operation only makes sence on placeholders,
* otherwise its a "Delete" operation on the child widget.
*/
glade_widget_remove_pack_action (gchild, "remove_slot");
gbox = glade_widget_get_from_gobject (container);
fix_response_id_on_child (gbox, current, FALSE);
fix_response_id_on_child (gbox, new_widget, TRUE);
g_object_unref (G_OBJECT (current));
}
GObject *
glade_gtk_box_get_internal_child (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *name)
{
GList *children, *l;
GObject *child = NULL;
g_return_val_if_fail (GTK_IS_BOX (object), NULL);
children = l = gtk_container_get_children (GTK_CONTAINER (object));
while (l)
{
GladeWidget *gw = glade_widget_get_from_gobject (l->data);
if (gw && gw->internal && strcmp (gw->internal, name) == 0)
{
child = G_OBJECT (l->data);
break;
}
l= l->next;
}
g_list_free (children);
return child;
}
static void
glade_gtk_box_notebook_child_insert_remove_action (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *object,
const gchar *size_prop,
const gchar *group_format,
gboolean remove,
gboolean after);
void
glade_gtk_box_child_action_activate (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *object,
const gchar *action_path)
{
if (strcmp (action_path, "insert_after") == 0)
{
glade_gtk_box_notebook_child_insert_remove_action (adaptor, container,
object, "size",
_("Insert placeholder to %s"),
FALSE, TRUE);
}
else if (strcmp (action_path, "insert_before") == 0)
{
glade_gtk_box_notebook_child_insert_remove_action (adaptor, container,
object, "size",
_("Insert placeholder to %s"),
FALSE, FALSE);
}
else if (strcmp (action_path, "remove_slot") == 0)
{
glade_gtk_box_notebook_child_insert_remove_action (adaptor, container,
object, "size",
_("Remove placeholder from %s"),
TRUE, FALSE);
}
else
GWA_GET_CLASS (GTK_TYPE_CONTAINER)->child_action_activate (adaptor,
container,
object,
action_path);
}
/* ----------------------------- GtkTable ------------------------------ */
typedef struct {
/* comparable part: */
GladeWidget *widget;
gint left_attach;
gint right_attach;
gint top_attach;
gint bottom_attach;
} GladeGtkTableChild;
typedef enum {
DIR_UP,
DIR_DOWN,
DIR_LEFT,
DIR_RIGHT
} GladeTableDir;
#define TABLE_CHILD_CMP_SIZE (sizeof (GladeWidget *) + (sizeof (gint) * 4))
static GladeGtkTableChild table_edit = { 0, };
static GladeGtkTableChild table_cur_attach = { 0, };
static void
glade_gtk_table_get_child_attachments (GtkWidget *table,
GtkWidget *child,
GtkTableChild *tchild)
{
guint left, right, top, bottom;
gtk_container_child_get (GTK_CONTAINER (table), child,
"left-attach", (guint *)&left,
"right-attach", (guint *)&right,
"bottom-attach", (guint *)&bottom,
"top-attach", (guint *)&top,
NULL);
tchild->widget = child;
tchild->left_attach = left;
tchild->right_attach = right;
tchild->top_attach = top;
tchild->bottom_attach = bottom;
}
/* Takes a point (x or y depending on 'row') relative to
* table, and returns the row or column in which the point
* was found.
*/
static gint
glade_gtk_table_get_row_col_from_point (GtkTable *table,
gboolean row,
gint point)
{
GtkTableChild tchild;
GtkAllocation allocation;
GList *list, *children;
gint span, trans_point, size, base, end;
children = gtk_container_get_children (GTK_CONTAINER (table));
for (list = children;
list;
list = list->next)
{
glade_gtk_table_get_child_attachments (GTK_WIDGET (table),
GTK_WIDGET (list->data), &tchild);
if (row)
gtk_widget_translate_coordinates
(GTK_WIDGET (table), tchild.widget,
0, point, NULL, &trans_point);
else
gtk_widget_translate_coordinates
(GTK_WIDGET (table), tchild.widget,
point, 0, &trans_point, NULL);
gtk_widget_get_allocation (tchild.widget, &allocation);
/* Find any widget in our row/column
*/
end = row ? allocation.height : allocation.width;
if (trans_point >= 0 &&
/* should be trans_point < end ... test FIXME ! */
trans_point < end)
{
base = row ? tchild.top_attach : tchild.left_attach;
size = row ? allocation.height : allocation.width;
span = row ? (tchild.bottom_attach - tchild.top_attach) :
(tchild.right_attach - tchild.left_attach);
return base + (trans_point * span / size);
}
}
g_list_free (children);
return -1;
}
static gboolean
glade_gtk_table_point_crosses_threshold (GtkTable *table,
gboolean row,
gint num,
GladeTableDir dir,
gint point)
{
GtkTableChild tchild;
GtkAllocation allocation;
GList *list, *children;
gint span, trans_point, size, rowcol_size, base;
children = gtk_container_get_children (GTK_CONTAINER (table));
for (list = children; list; list = list->next)
{
glade_gtk_table_get_child_attachments (GTK_WIDGET (table),
GTK_WIDGET (list->data), &tchild);
/* Find any widget in our row/column
*/
if ((row && num >= tchild.top_attach && num < tchild.bottom_attach) ||
(!row && num >= tchild.left_attach && num < tchild.right_attach))
{
if (row)
gtk_widget_translate_coordinates
(GTK_WIDGET (table), tchild.widget,
0, point, NULL, &trans_point);
else
gtk_widget_translate_coordinates
(GTK_WIDGET (table), tchild.widget,
point, 0, &trans_point, NULL);
span = row ? (tchild.bottom_attach - tchild.top_attach) :
(tchild.right_attach - tchild.left_attach);
gtk_widget_get_allocation (tchild.widget, &allocation);
size = row ? allocation.height : allocation.width;
base = row ? tchild.top_attach : tchild.left_attach;
rowcol_size = size / span;
trans_point -= (num - base) * rowcol_size;
#if 0
g_print ("dir: %s, widget size: %d, rowcol size: %d, "
"requested rowcol: %d, widget base rowcol: %d, trim: %d, "
"widget point: %d, thresh: %d\n",
dir == DIR_UP ? "up" : dir == DIR_DOWN ? "down" :
dir == DIR_LEFT ? "left" : "right",
size, rowcol_size, num, base, (num - base) * rowcol_size,
trans_point,
dir == DIR_UP || dir == DIR_LEFT ?
(rowcol_size / 2) :
(rowcol_size / 2));
#endif
switch (dir)
{
case DIR_UP:
case DIR_LEFT:
return trans_point <= (rowcol_size / 2);
case DIR_DOWN:
case DIR_RIGHT:
return trans_point >= (rowcol_size / 2);
default:
break;
}
}
}
g_list_free (children);
return FALSE;
}
static gboolean
glade_gtk_table_get_attachments (GladeFixed *fixed,
GtkTable *table,
GdkRectangle *rect,
GladeGtkTableChild *configure)
{
gint center_x, center_y, row, column;
guint n_columns, n_rows;
center_x = rect->x + (rect->width / 2);
center_y = rect->y + (rect->height / 2);
column = glade_gtk_table_get_row_col_from_point
(table, FALSE, center_x);
row = glade_gtk_table_get_row_col_from_point
(table, TRUE, center_y);
/* its a start, now try to grow when the rect extents
* reach at least half way into the next row/column
*/
configure->left_attach = column;
configure->right_attach = column + 1;
configure->top_attach = row;
configure->bottom_attach = row +1;
if (column >= 0 && row >= 0)
{
g_object_get (table,
"n-columns", &n_columns,
"n-rows", &n_rows,
NULL);
/* Check and expand left
*/
while (configure->left_attach > 0)
{
if (rect->x < fixed->child_x_origin &&
fixed->operation != GLADE_CURSOR_DRAG &&
GLADE_FIXED_CURSOR_LEFT (fixed->operation) == FALSE)
break;
if (glade_gtk_table_point_crosses_threshold
(table, FALSE, configure->left_attach -1,
DIR_LEFT, rect->x) == FALSE)
break;
configure->left_attach--;
}
/* Check and expand right
*/
while (configure->right_attach < n_columns)
{
if (rect->x + rect->width >
fixed->child_x_origin + fixed->child_width_origin &&
fixed->operation != GLADE_CURSOR_DRAG &&
GLADE_FIXED_CURSOR_RIGHT (fixed->operation) == FALSE)
break;
if (glade_gtk_table_point_crosses_threshold
(table, FALSE, configure->right_attach,
DIR_RIGHT, rect->x + rect->width) == FALSE)
break;
configure->right_attach++;
}
/* Check and expand top
*/
while (configure->top_attach > 0)
{
if (rect->y < fixed->child_y_origin &&
fixed->operation != GLADE_CURSOR_DRAG &&
GLADE_FIXED_CURSOR_TOP (fixed->operation) == FALSE)
break;
if (glade_gtk_table_point_crosses_threshold
(table, TRUE, configure->top_attach -1,
DIR_UP, rect->y) == FALSE)
break;
configure->top_attach--;
}
/* Check and expand bottom
*/
while (configure->bottom_attach < n_rows)
{
if (rect->y + rect->height >
fixed->child_y_origin + fixed->child_height_origin &&
fixed->operation != GLADE_CURSOR_DRAG &&
GLADE_FIXED_CURSOR_BOTTOM (fixed->operation) == FALSE)
break;
if (glade_gtk_table_point_crosses_threshold
(table, TRUE, configure->bottom_attach,
DIR_DOWN, rect->y + rect->height) == FALSE)
break;
configure->bottom_attach++;
}
}
/* Keep the same row/col span when performing a drag
*/
if (fixed->operation == GLADE_CURSOR_DRAG)
{
gint col_span = table_edit.right_attach - table_edit.left_attach;
gint row_span = table_edit.bottom_attach - table_edit.top_attach;
if (rect->x < fixed->child_x_origin)
configure->right_attach = configure->left_attach + col_span;
else
configure->left_attach = configure->right_attach - col_span;
if (rect->y < fixed->child_y_origin)
configure->bottom_attach = configure->top_attach + row_span;
else
configure->top_attach = configure->bottom_attach - row_span;
} else if (fixed->operation == GLADE_CURSOR_RESIZE_RIGHT) {
configure->left_attach = table_edit.left_attach;
configure->top_attach = table_edit.top_attach;
configure->bottom_attach = table_edit.bottom_attach;
} else if (fixed->operation == GLADE_CURSOR_RESIZE_LEFT) {
configure->right_attach = table_edit.right_attach;
configure->top_attach = table_edit.top_attach;
configure->bottom_attach = table_edit.bottom_attach;
} else if (fixed->operation == GLADE_CURSOR_RESIZE_TOP) {
configure->left_attach = table_edit.left_attach;
configure->right_attach = table_edit.right_attach;
configure->bottom_attach = table_edit.bottom_attach;
} else if (fixed->operation == GLADE_CURSOR_RESIZE_BOTTOM) {
configure->left_attach = table_edit.left_attach;
configure->right_attach = table_edit.right_attach;
configure->top_attach = table_edit.top_attach;
}
return column >= 0 && row >= 0;
}
static gboolean
glade_gtk_table_configure_child (GladeFixed *fixed,
GladeWidget *child,
GdkRectangle *rect,
GtkWidget *table)
{
GladeGtkTableChild configure = { child, };
/* Sometimes we are unable to find a widget in the appropriate column,
* usually because a placeholder hasnt had its size allocation yet.
*/
if (glade_gtk_table_get_attachments (fixed, GTK_TABLE (table), rect, &configure))
{
if (memcmp (&configure, &table_cur_attach, TABLE_CHILD_CMP_SIZE) != 0)
{
glade_property_push_superuser ();
glade_widget_pack_property_set (child, "left-attach",
configure.left_attach);
glade_widget_pack_property_set (child, "right-attach",
configure.right_attach);
glade_widget_pack_property_set (child, "top-attach",
configure.top_attach);
glade_widget_pack_property_set (child, "bottom-attach",
configure.bottom_attach);
glade_property_pop_superuser ();
memcpy (&table_cur_attach, &configure, TABLE_CHILD_CMP_SIZE);
}
}
return TRUE;
}
static gboolean
glade_gtk_table_configure_begin (GladeFixed *fixed,
GladeWidget *child,
GtkWidget *table)
{
table_edit.widget = child;
glade_widget_pack_property_get (child, "left-attach",
&table_edit.left_attach);
glade_widget_pack_property_get (child, "right-attach",
&table_edit.right_attach);
glade_widget_pack_property_get (child, "top-attach",
&table_edit.top_attach);
glade_widget_pack_property_get (child, "bottom-attach",
&table_edit.bottom_attach);
memcpy (&table_cur_attach, &table_edit, TABLE_CHILD_CMP_SIZE);
return TRUE;
}
static gboolean
glade_gtk_table_configure_end (GladeFixed *fixed,
GladeWidget *child,
GtkWidget *table)
{
GladeGtkTableChild new_child = { child, };
glade_widget_pack_property_get (child, "left-attach",
&new_child.left_attach);
glade_widget_pack_property_get (child, "right-attach",
&new_child.right_attach);
glade_widget_pack_property_get (child, "top-attach",
&new_child.top_attach);
glade_widget_pack_property_get (child, "bottom-attach",
&new_child.bottom_attach);
/* Compare the meaningfull part of the current edit. */
if (memcmp (&new_child, &table_edit, TABLE_CHILD_CMP_SIZE) != 0)
{
GValue left_attach_value = { 0, };
GValue right_attach_value = { 0, };
GValue top_attach_value = { 0, };
GValue bottom_attach_value = { 0, };
GValue new_left_attach_value = { 0, };
GValue new_right_attach_value = { 0, };
GValue new_top_attach_value = { 0, };
GValue new_bottom_attach_value = { 0, };
GladeProperty *left_attach_prop, *right_attach_prop,
*top_attach_prop, *bottom_attach_prop;
left_attach_prop = glade_widget_get_pack_property (child, "left-attach");
right_attach_prop = glade_widget_get_pack_property (child, "right-attach");
top_attach_prop = glade_widget_get_pack_property (child, "top-attach");
bottom_attach_prop = glade_widget_get_pack_property (child, "bottom-attach");
g_return_val_if_fail (GLADE_IS_PROPERTY (left_attach_prop), FALSE);
g_return_val_if_fail (GLADE_IS_PROPERTY (right_attach_prop), FALSE);
g_return_val_if_fail (GLADE_IS_PROPERTY (top_attach_prop), FALSE);
g_return_val_if_fail (GLADE_IS_PROPERTY (bottom_attach_prop), FALSE);
glade_property_get_value (left_attach_prop, &new_left_attach_value);
glade_property_get_value (right_attach_prop, &new_right_attach_value);
glade_property_get_value (top_attach_prop, &new_top_attach_value);
glade_property_get_value (bottom_attach_prop, &new_bottom_attach_value);
g_value_init (&left_attach_value, G_TYPE_UINT);
g_value_init (&right_attach_value, G_TYPE_UINT);
g_value_init (&top_attach_value, G_TYPE_UINT);
g_value_init (&bottom_attach_value, G_TYPE_UINT);
g_value_set_uint (&left_attach_value, table_edit.left_attach);
g_value_set_uint (&right_attach_value, table_edit.right_attach);
g_value_set_uint (&top_attach_value, table_edit.top_attach);
g_value_set_uint (&bottom_attach_value, table_edit.bottom_attach);
glade_command_push_group (_("Placing %s inside %s"),
child->name,
GLADE_WIDGET (fixed)->name);
glade_command_set_properties
(left_attach_prop, &left_attach_value, &new_left_attach_value,
right_attach_prop, &right_attach_value, &new_right_attach_value,
top_attach_prop, &top_attach_value, &new_top_attach_value,
bottom_attach_prop, &bottom_attach_value, &new_bottom_attach_value,
NULL);
glade_command_pop_group ();
g_value_unset (&left_attach_value);
g_value_unset (&right_attach_value);
g_value_unset (&top_attach_value);
g_value_unset (&bottom_attach_value);
g_value_unset (&new_left_attach_value);
g_value_unset (&new_right_attach_value);
g_value_unset (&new_top_attach_value);
g_value_unset (&new_bottom_attach_value);
}
return TRUE;
}
void
glade_gtk_table_post_create (GladeWidgetAdaptor *adaptor,
GObject *container,
GladeCreateReason reason)
{
GladeWidget *gwidget =
glade_widget_get_from_gobject (container);
g_signal_connect (G_OBJECT (gwidget), "configure-child",
G_CALLBACK (glade_gtk_table_configure_child), container);
g_signal_connect (G_OBJECT (gwidget), "configure-begin",
G_CALLBACK (glade_gtk_table_configure_begin), container);
g_signal_connect (G_OBJECT (gwidget), "configure-end",
G_CALLBACK (glade_gtk_table_configure_end), container);
}
static gboolean
glade_gtk_table_has_child (GtkTable *table, guint left_attach, guint top_attach)
{
GList *list, *children;
gboolean ret = FALSE;
children = gtk_container_get_children (GTK_CONTAINER (table));
for (list = children;
list && list->data;
list = list->next)
{
GtkTableChild child;
glade_gtk_table_get_child_attachments (GTK_WIDGET (table),
GTK_WIDGET (list->data), &child);
if (left_attach >= child.left_attach && left_attach < child.right_attach &&
top_attach >= child.top_attach && top_attach < child.bottom_attach)
{
ret = TRUE;
break;
}
}
g_list_free (children);
return ret;
}
static gboolean
glade_gtk_table_widget_exceeds_bounds (GtkTable *table, gint n_rows, gint n_cols)
{
GList *list, *children;
gboolean ret = FALSE;
children = gtk_container_get_children (GTK_CONTAINER (table));
for (list = children;
list && list->data;
list = list->next)
{
GtkTableChild child;
glade_gtk_table_get_child_attachments (GTK_WIDGET (table),
GTK_WIDGET (list->data), &child);
if (GLADE_IS_PLACEHOLDER(child.widget) == FALSE &&
(child.right_attach > n_cols ||
child.bottom_attach > n_rows))
{
ret = TRUE;
break;
}
}
return ret;
}
static void
glade_gtk_table_refresh_placeholders (GtkTable *table)
{
GList *list, *children;
guint n_columns, n_rows;
gint i, j;
g_object_get (table,
"n-columns", &n_columns,
"n-rows", &n_rows,
NULL);
children = gtk_container_get_children (GTK_CONTAINER (table));
for (list = children; list && list->data; list = list->next)
{
if (GLADE_IS_PLACEHOLDER (list->data))
gtk_container_remove (GTK_CONTAINER (table),
GTK_WIDGET (list->data));
}
g_list_free (children);
for (i = 0; i < n_columns; i++)
for (j = 0; j < n_rows; j++)
if (glade_gtk_table_has_child (table, i, j) == FALSE)
{
gtk_table_attach_defaults (table,
glade_placeholder_new (),
i, i + 1, j, j + 1);
}
gtk_container_check_resize (GTK_CONTAINER (table));
}
static void
gtk_table_children_callback (GtkWidget *widget,
gpointer client_data)
{
GList **children;
children = (GList**) client_data;
*children = g_list_prepend (*children, widget);
}
GList *
glade_gtk_table_get_children (GladeWidgetAdaptor *adaptor,
GtkContainer *container)
{
GList *children = NULL;
g_return_val_if_fail (GTK_IS_TABLE (container), NULL);
gtk_container_forall (container,
gtk_table_children_callback,
&children);
/* GtkTable has the children list already reversed */
return children;
}
void
glade_gtk_table_add_child (GladeWidgetAdaptor *adaptor,
GObject *object,
GObject *child)
{
g_return_if_fail (GTK_IS_TABLE (object));
g_return_if_fail (GTK_IS_WIDGET (child));
gtk_container_add (GTK_CONTAINER (object), GTK_WIDGET (child));
glade_gtk_table_refresh_placeholders (GTK_TABLE (object));
}
void
glade_gtk_table_remove_child (GladeWidgetAdaptor *adaptor,
GObject *object,
GObject *child)
{
g_return_if_fail (GTK_IS_TABLE (object));
g_return_if_fail (GTK_IS_WIDGET (child));
gtk_container_remove (GTK_CONTAINER (object), GTK_WIDGET (child));
glade_gtk_table_refresh_placeholders (GTK_TABLE (object));
}
void
glade_gtk_table_replace_child (GladeWidgetAdaptor *adaptor,
GtkWidget *container,
GtkWidget *current,
GtkWidget *new_widget)
{
g_return_if_fail (GTK_IS_TABLE (container));
g_return_if_fail (GTK_IS_WIDGET (current));
g_return_if_fail (GTK_IS_WIDGET (new_widget));
/* Chain Up */
GWA_GET_CLASS
(GTK_TYPE_CONTAINER)->replace_child (adaptor,
G_OBJECT (container),
G_OBJECT (current),
G_OBJECT (new_widget));
/* If we are replacing a GladeWidget, we must refresh placeholders
* because the widget may have spanned multiple rows/columns, we must
* not do so in the case we are pasting multiple widgets into a table,
* where destroying placeholders results in default packing properties
* (since the remaining placeholder templates no longer exist, only the
* first pasted widget would have proper packing properties).
*/
if (glade_widget_get_from_gobject (new_widget) == NULL)
glade_gtk_table_refresh_placeholders (GTK_TABLE (container));
}
static void
glade_gtk_table_set_n_common (GObject *object, const GValue *value, gboolean for_rows)
{
GladeWidget *widget;
GtkTable *table;
guint new_size, old_size, n_columns, n_rows;
table = GTK_TABLE (object);
g_return_if_fail (GTK_IS_TABLE (table));
g_object_get (table,
"n-columns", &n_columns,
"n-rows", &n_rows,
NULL);
new_size = g_value_get_uint (value);
old_size = for_rows ? n_rows : n_columns;
if (new_size < 1)
return;
if (glade_gtk_table_widget_exceeds_bounds
(table,
for_rows ? new_size : n_rows,
for_rows ? n_columns : new_size))
/* Refuse to shrink if it means orphaning widgets */
return;
widget = glade_widget_get_from_gobject (GTK_WIDGET (table));
g_return_if_fail (widget != NULL);
if (for_rows)
gtk_table_resize (table, new_size, n_columns);
else
gtk_table_resize (table, n_rows, new_size);
/* Fill table with placeholders */
glade_gtk_table_refresh_placeholders (table);
if (new_size < old_size)
{
/* Remove from the bottom up */
GList *list, *children;
GList *list_to_free = NULL;
children = gtk_container_get_children (GTK_CONTAINER (table));
for (list = children;
list && list->data;
list = list->next)
{
GtkTableChild child;
guint start, end;
glade_gtk_table_get_child_attachments (GTK_WIDGET (table),
GTK_WIDGET (list->data), &child);
start = for_rows ? child.top_attach : child.left_attach;
end = for_rows ? child.bottom_attach : child.right_attach;
/* We need to completely remove it */
if (start >= new_size)
{
list_to_free = g_list_prepend (list_to_free, child.widget);
continue;
}
/* If the widget spans beyond the new border,
* we should resize it to fit on the new table */
if (end > new_size)
gtk_container_child_set
(GTK_CONTAINER (table), GTK_WIDGET (child.widget),
for_rows ? "bottom_attach" : "right_attach",
new_size, NULL);
}
g_list_free (children);
if (list_to_free)
{
for (list = g_list_first(list_to_free);
list && list->data;
list = list->next)
{
g_object_ref (G_OBJECT (list->data));
gtk_container_remove (GTK_CONTAINER (table),
GTK_WIDGET(list->data));
/* This placeholder is no longer valid, force destroy */
gtk_widget_destroy (GTK_WIDGET(list->data));
}
g_list_free (list_to_free);
}
gtk_table_resize (table,
for_rows ? new_size : n_rows,
for_rows ? n_columns : new_size);
}
}
void
glade_gtk_table_set_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *id,
const GValue *value)
{
if (!strcmp (id, "n-rows"))
glade_gtk_table_set_n_common (object, value, TRUE);
else if (!strcmp (id, "n-columns"))
glade_gtk_table_set_n_common (object, value, FALSE);
else
GWA_GET_CLASS (GTK_TYPE_CONTAINER)->set_property (adaptor, object,
id, value);
}
static gboolean
glade_gtk_table_verify_n_common (GObject *object, const GValue *value, gboolean for_rows)
{
GtkTable *table = GTK_TABLE(object);
guint n_columns, n_rows, new_size = g_value_get_uint (value);
g_object_get (table,
"n-columns", &n_columns,
"n-rows", &n_rows,
NULL);
if (glade_gtk_table_widget_exceeds_bounds
(table,
for_rows ? new_size : n_rows,
for_rows ? n_columns : new_size))
/* Refuse to shrink if it means orphaning widgets */
return FALSE;
return TRUE;
}
gboolean
glade_gtk_table_verify_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *id,
const GValue *value)
{
if (!strcmp (id, "n-rows"))
return glade_gtk_table_verify_n_common (object, value, TRUE);
else if (!strcmp (id, "n-columns"))
return glade_gtk_table_verify_n_common (object, value, FALSE);
else if (GWA_GET_CLASS (GTK_TYPE_CONTAINER)->verify_property)
GWA_GET_CLASS (GTK_TYPE_CONTAINER)->verify_property (adaptor, object,
id, value);
return TRUE;
}
void
glade_gtk_table_set_child_property (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *child,
const gchar *property_name,
GValue *value)
{
g_return_if_fail (GTK_IS_TABLE (container));
g_return_if_fail (GTK_IS_WIDGET (child));
g_return_if_fail (property_name != NULL && value != NULL);
GWA_GET_CLASS
(GTK_TYPE_CONTAINER)->child_set_property (adaptor,
container, child,
property_name, value);
if (strcmp (property_name, "bottom-attach") == 0 ||
strcmp (property_name, "left-attach") == 0 ||
strcmp (property_name, "right-attach") == 0 ||
strcmp (property_name, "top-attach") == 0)
{
/* Refresh placeholders */
glade_gtk_table_refresh_placeholders (GTK_TABLE (container));
}
}
static gboolean
glade_gtk_table_verify_attach_common (GObject *object,
GValue *value,
guint *val,
const gchar *prop,
guint *prop_val,
const gchar *parent_prop,
guint *parent_val)
{
GladeWidget *widget, *parent;
widget = glade_widget_get_from_gobject (object);
g_return_val_if_fail (GLADE_IS_WIDGET (widget), TRUE);
parent = glade_widget_get_parent (widget);
g_return_val_if_fail (GLADE_IS_WIDGET (parent), TRUE);
*val = g_value_get_uint (value);
glade_widget_property_get (widget, prop, prop_val);
glade_widget_property_get (parent, parent_prop, parent_val);
return FALSE;
}
static gboolean
glade_gtk_table_verify_left_top_attach (GObject *object,
GValue *value,
const gchar *prop,
const gchar *parent_prop)
{
guint val, prop_val, parent_val;
if (glade_gtk_table_verify_attach_common (object, value, &val,
prop, &prop_val,
parent_prop, &parent_val))
return FALSE;
if (val >= parent_val || val >= prop_val)
return FALSE;
return TRUE;
}
static gboolean
glade_gtk_table_verify_right_bottom_attach (GObject *object,
GValue *value,
const gchar *prop,
const gchar *parent_prop)
{
guint val, prop_val, parent_val;
if (glade_gtk_table_verify_attach_common (object, value, &val,
prop, &prop_val,
parent_prop, &parent_val))
return FALSE;
if (val <= prop_val || val > parent_val)
return FALSE;
return TRUE;
}
gboolean
glade_gtk_table_child_verify_property (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *child,
const gchar *id,
GValue *value)
{
if (!strcmp (id, "left-attach"))
return glade_gtk_table_verify_left_top_attach (child,
value,
"right-attach",
"n-columns");
else if (!strcmp (id, "right-attach"))
return glade_gtk_table_verify_right_bottom_attach (child,
value,
"left-attach",
"n-columns");
else if (!strcmp (id, "top-attach"))
return glade_gtk_table_verify_left_top_attach (child,
value,
"bottom-attach",
"n-rows");
else if (!strcmp (id, "bottom-attach"))
return glade_gtk_table_verify_right_bottom_attach (child,
value,
"top-attach",
"n-rows");
else if (GWA_GET_CLASS (GTK_TYPE_CONTAINER)->child_verify_property)
GWA_GET_CLASS
(GTK_TYPE_CONTAINER)->child_verify_property (adaptor,
container, child,
id, value);
return TRUE;
}
static void
glade_gtk_table_child_insert_remove_action (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *object,
const gchar *group_format,
const gchar *n_row_col,
const gchar *attach1, /* should be smaller (top/left) attachment */
const gchar *attach2, /* should be larger (bot/right) attachment */
gboolean remove,
gboolean after)
{
GladeWidget *parent;
GList *children, *l;
gint child_pos, size, offset;
gtk_container_child_get (GTK_CONTAINER (container),
GTK_WIDGET (object),
after ? attach2 : attach1, &child_pos, NULL);
parent = glade_widget_get_from_gobject (container);
glade_command_push_group (group_format, glade_widget_get_name (parent));
children = glade_widget_adaptor_get_children (adaptor, container);
/* Make sure widgets does not get destroyed */
g_list_foreach (children, (GFunc) g_object_ref, NULL);
glade_widget_property_get (parent, n_row_col, &size);
if (remove)
{
GList *del = NULL;
/* Remove children first */
for (l = children; l; l = g_list_next (l))
{
GladeWidget *gchild = glade_widget_get_from_gobject (l->data);
gint pos1, pos2;
/* Skip placeholders */
if (gchild == NULL) continue;
glade_widget_pack_property_get (gchild, attach1, &pos1);
glade_widget_pack_property_get (gchild, attach2, &pos2);
if ((pos1+1 == pos2) && ((after ? pos2 : pos1) == child_pos))
{
del = g_list_prepend (del, gchild);
}
}
if (del)
{
glade_command_delete (del);
g_list_free (del);
}
offset = -1;
}
else
{
/* Expand the table */
glade_command_set_property (glade_widget_get_property (parent, n_row_col),
size + 1);
offset = 1;
}
/* Reorder children */
for (l = children; l; l = g_list_next (l))
{
GladeWidget *gchild = glade_widget_get_from_gobject (l->data);
gint pos;
/* Skip placeholders */
if (gchild == NULL) continue;
/* if removing, do top/left before bot/right */
if (remove)
{
/* adjust top-left attachment*/
glade_widget_pack_property_get (gchild, attach1, &pos);
if(pos > child_pos || (after && pos == child_pos))
{
glade_command_set_property (glade_widget_get_pack_property (gchild, attach1), pos+offset);
}
/* adjust bottom-right attachment*/
glade_widget_pack_property_get (gchild, attach2, &pos);
if(pos > child_pos || (after && pos == child_pos))
{
glade_command_set_property (glade_widget_get_pack_property (gchild, attach2), pos+offset);
}
}
/* if inserting, do bot/right before top/left */
else
{
/* adjust bottom-right attachment*/
glade_widget_pack_property_get (gchild, attach2, &pos);
if(pos > child_pos)
{
glade_command_set_property (glade_widget_get_pack_property (gchild, attach2), pos+offset);
}
/* adjust top-left attachment*/
glade_widget_pack_property_get (gchild, attach1, &pos);
if(pos >= child_pos)
{
glade_command_set_property (glade_widget_get_pack_property (gchild, attach1), pos+offset);
}
}
}
if (remove)
{
/* Shrink the table */
glade_command_set_property (glade_widget_get_property (parent, n_row_col),
size - 1);
}
g_list_foreach (children, (GFunc) g_object_unref, NULL);
g_list_free (children);
glade_command_pop_group ();
}
void
glade_gtk_table_child_action_activate (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *object,
const gchar *action_path)
{
if (strcmp (action_path, "insert_row/after") == 0)
{
glade_gtk_table_child_insert_remove_action (adaptor, container, object,
_("Insert Row on %s"),
"n-rows","top-attach",
"bottom-attach",
FALSE, TRUE);
}
else if (strcmp (action_path, "insert_row/before") == 0)
{
glade_gtk_table_child_insert_remove_action (adaptor, container, object,
_("Insert Row on %s"),
"n-rows","top-attach",
"bottom-attach",
FALSE, FALSE);
}
else if (strcmp (action_path, "insert_column/after") == 0)
{
glade_gtk_table_child_insert_remove_action (adaptor, container, object,
_("Insert Column on %s"),
"n-columns","left-attach",
"right-attach",
FALSE, TRUE);
}
else if (strcmp (action_path, "insert_column/before") == 0)
{
glade_gtk_table_child_insert_remove_action (adaptor, container, object,
_("Insert Column on %s"),
"n-columns","left-attach",
"right-attach",
FALSE, FALSE);
}
else if (strcmp (action_path, "remove_column") == 0)
{
glade_gtk_table_child_insert_remove_action (adaptor, container, object,
_("Remove Column on %s"),
"n-columns","left-attach",
"right-attach",
TRUE, FALSE);
}
else if (strcmp (action_path, "remove_row") == 0)
{
glade_gtk_table_child_insert_remove_action (adaptor, container, object,
_("Remove Row on %s"),
"n-rows","top-attach",
"bottom-attach",
TRUE, FALSE);
}
else
GWA_GET_CLASS (GTK_TYPE_CONTAINER)->child_action_activate (adaptor,
container,
object,
action_path);
}
/* ----------------------------- GtkFrame ------------------------------ */
void
glade_gtk_frame_post_create (GladeWidgetAdaptor *adaptor,
GObject *frame,
GladeCreateReason reason)
{
static GladeWidgetAdaptor *label_adaptor = NULL, *alignment_adaptor = NULL;
GladeWidget *gframe, *glabel, *galignment;
GtkWidget *label;
gchar *label_text;
if (reason != GLADE_CREATE_USER)
return;
g_return_if_fail (GTK_IS_FRAME (frame));
gframe = glade_widget_get_from_gobject (frame);
g_return_if_fail (GLADE_IS_WIDGET (gframe));
/* If we didnt put this object here or if frame is an aspect frame... */
if (((label = gtk_frame_get_label_widget (GTK_FRAME (frame))) == NULL ||
(glade_widget_get_from_gobject (label) == NULL)) &&
(GTK_IS_ASPECT_FRAME (frame) == FALSE))
{
if (label_adaptor == NULL)
label_adaptor = glade_widget_adaptor_get_by_type (GTK_TYPE_LABEL);
if (alignment_adaptor == NULL)
alignment_adaptor = glade_widget_adaptor_get_by_type (GTK_TYPE_ALIGNMENT);
/* add label (as an internal child) */
glabel = glade_widget_adaptor_create_widget (label_adaptor, FALSE,
"parent", gframe,
"project", glade_widget_get_project (gframe),
NULL);
label_text = g_strdup_printf ("<b>%s</b>", glade_widget_get_name (gframe));
glade_widget_property_set (glabel, "label", label_text);
glade_widget_property_set (glabel, "use-markup", "TRUE");
g_free (label_text);
g_object_set_data (glabel->object, "special-child-type", "label_item");
glade_widget_add_child (gframe, glabel, FALSE);
/* add alignment */
galignment = glade_widget_adaptor_create_widget (alignment_adaptor, FALSE,
"parent", gframe,
"project", glade_widget_get_project (gframe),
NULL);
glade_widget_property_set (galignment, "left-padding", 12);
glade_widget_add_child (gframe, galignment, FALSE);
}
/* Chain Up */
GWA_GET_CLASS (GTK_TYPE_CONTAINER)->post_create (adaptor, frame, reason);
}
void
glade_gtk_frame_replace_child (GladeWidgetAdaptor *adaptor,
GtkWidget *container,
GtkWidget *current,
GtkWidget *new_widget)
{
gchar *special_child_type;
special_child_type =
g_object_get_data (G_OBJECT (current), "special-child-type");
if (special_child_type && !strcmp (special_child_type, "label_item"))
{
g_object_set_data (G_OBJECT (new_widget), "special-child-type", "label_item");
gtk_frame_set_label_widget (GTK_FRAME (container), new_widget);
return;
}
/* Chain Up */
GWA_GET_CLASS
(GTK_TYPE_CONTAINER)->replace_child (adaptor,
G_OBJECT (container),
G_OBJECT (current),
G_OBJECT (new_widget));
}
void
glade_gtk_frame_add_child (GladeWidgetAdaptor *adaptor,
GObject *object,
GObject *child)
{
GtkWidget *bin_child;
gchar *special_child_type;
special_child_type = g_object_get_data (child, "special-child-type");
if (special_child_type && !strcmp (special_child_type, "label"))
{
g_object_set_data (child,
"special-child-type",
"label_item");
gtk_frame_set_label_widget (GTK_FRAME (object),
GTK_WIDGET (child));
}
else if (special_child_type &&
!strcmp (special_child_type, "label_item"))
{
gtk_frame_set_label_widget (GTK_FRAME (object),
GTK_WIDGET (child));
}
else
{
/* Get a placeholder out of the way before adding the child
*/
bin_child = gtk_bin_get_child (GTK_BIN (object));
if (bin_child)
{
if (GLADE_IS_PLACEHOLDER (bin_child))
gtk_container_remove (GTK_CONTAINER (object), bin_child);
else
{
g_critical ("Cant add more than one widget to a GtkFrame");
return;
}
}
gtk_container_add (GTK_CONTAINER (object),
GTK_WIDGET (child));
}
}
void
glade_gtk_frame_remove_child (GladeWidgetAdaptor *adaptor,
GObject *object,
GObject *child)
{
gchar *special_child_type;
special_child_type = g_object_get_data (child, "special-child-type");
if (special_child_type &&
!strcmp (special_child_type, "label_item"))
{
gtk_frame_set_label_widget (GTK_FRAME (object),
glade_placeholder_new ());
}
else
{
gtk_container_remove (GTK_CONTAINER (object),
GTK_WIDGET (child));
gtk_container_add (GTK_CONTAINER (object),
glade_placeholder_new ());
}
}
static gboolean
write_special_child_label_item (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlContext *context,
GladeXmlNode *node,
GladeWriteWidgetFunc write_func)
{
gchar *special_child_type = NULL;
GObject *child;
child = widget->object;
if (child)
special_child_type = g_object_get_data (child, "special-child-type");
if (special_child_type && !strcmp (special_child_type, "label_item"))
{
g_object_set_data (child,
"special-child-type",
"label");
write_func (adaptor, widget, context, node);
g_object_set_data (child,
"special-child-type",
"label_item");
return TRUE;
}
else
return FALSE;
}
void
glade_gtk_frame_write_child (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlContext *context,
GladeXmlNode *node)
{
if (!write_special_child_label_item (adaptor, widget, context, node,
GWA_GET_CLASS(GTK_TYPE_CONTAINER)->write_child))
/* Chain Up */
GWA_GET_CLASS
(GTK_TYPE_CONTAINER)->write_child (adaptor,
widget,
context,
node);
}
/* ----------------------------- GtkNotebook ------------------------------ */
typedef struct
{
gint pages;
gint page;
GList *children;
GList *tabs;
GList *extra_children;
GList *extra_tabs;
} NotebookChildren;
static gboolean glade_gtk_notebook_setting_position = FALSE;
static gint
notebook_child_compare_func (GtkWidget *widget_a, GtkWidget *widget_b)
{
GladeWidget *gwidget_a, *gwidget_b;
gint pos_a = 0, pos_b = 0;
gwidget_a = glade_widget_get_from_gobject (widget_a);
gwidget_b = glade_widget_get_from_gobject (widget_b);
g_assert (gwidget_a && gwidget_b);
glade_widget_pack_property_get (gwidget_a, "position", &pos_a);
glade_widget_pack_property_get (gwidget_b, "position", &pos_b);
return pos_a - pos_b;
}
static gint
notebook_find_child (GtkWidget *check,
gpointer cmp_pos_p)
{
GladeWidget *gcheck;
gint position = 0, cmp_pos = GPOINTER_TO_INT (cmp_pos_p);
gcheck = glade_widget_get_from_gobject (check);
g_assert (gcheck);
glade_widget_pack_property_get (gcheck, "position", &position);
return position - cmp_pos;
}
static gint
notebook_search_tab (GtkNotebook *notebook,
GtkWidget *tab)
{
GtkWidget *page;
gint i;
for (i = 0; i < gtk_notebook_get_n_pages (notebook); i++)
{
page = gtk_notebook_get_nth_page (notebook, i);
if (tab == gtk_notebook_get_tab_label (notebook, page))
return i;
}
g_critical ("Unable to find tab position in a notebook");
return -1;
}
static GtkWidget *
notebook_get_filler (NotebookChildren *nchildren, gboolean page)
{
GtkWidget *widget = NULL;
if (page && nchildren->extra_children)
{
widget = nchildren->extra_children->data;
nchildren->extra_children =
g_list_remove (nchildren->extra_children, widget);
g_assert (widget);
}
else if (!page && nchildren->extra_tabs)
{
widget = nchildren->extra_tabs->data;
nchildren->extra_tabs =
g_list_remove (nchildren->extra_tabs, widget);
g_assert (widget);
}
if (widget == NULL)
{
/* Need explicit reference here */
widget = glade_placeholder_new ();
g_object_ref (G_OBJECT (widget));
if (!page)
g_object_set_data (G_OBJECT (widget),
"special-child-type", "tab");
}
return widget;
}
static GtkWidget *
notebook_get_page (NotebookChildren *nchildren, gint position)
{
GList *node;
GtkWidget *widget = NULL;
if ((node = g_list_find_custom
(nchildren->children,
GINT_TO_POINTER (position),
(GCompareFunc)notebook_find_child)) != NULL)
{
widget = node->data;
nchildren->children =
g_list_remove (nchildren->children, widget);
}
else
widget = notebook_get_filler (nchildren, TRUE);
return widget;
}
static GtkWidget *
notebook_get_tab (NotebookChildren *nchildren, gint position)
{
GList *node;
GtkWidget *widget = NULL;
if ((node = g_list_find_custom
(nchildren->tabs,
GINT_TO_POINTER (position),
(GCompareFunc)notebook_find_child)) != NULL)
{
widget = node->data;
nchildren->tabs =
g_list_remove (nchildren->tabs, widget);
}
else
widget = notebook_get_filler (nchildren, FALSE);
return widget;
}
static NotebookChildren *
glade_gtk_notebook_extract_children (GtkWidget *notebook)
{
NotebookChildren *nchildren;
gchar *special_child_type;
GList *list, *children =
glade_util_container_get_all_children (GTK_CONTAINER (notebook));
GladeWidget *gchild;
GtkWidget *page;
gint position = 0;
nchildren = g_new0 (NotebookChildren, 1);
nchildren->pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook));
nchildren->page = gtk_notebook_get_current_page (GTK_NOTEBOOK (notebook));
/* Ref all the project widgets and build returned list first */
for (list = children; list; list = list->next)
{
if ((gchild = glade_widget_get_from_gobject (list->data)) != NULL)
{
special_child_type =
g_object_get_data (G_OBJECT (list->data),
"special-child-type");
glade_widget_pack_property_get (gchild, "position", &position);
g_object_ref (G_OBJECT (list->data));
/* Sort it into the proper struct member
*/
if (special_child_type == NULL)
{
if (g_list_find_custom (nchildren->children,
GINT_TO_POINTER (position),
(GCompareFunc)notebook_find_child))
nchildren->extra_children =
g_list_insert_sorted
(nchildren->extra_children, list->data,
(GCompareFunc)notebook_child_compare_func);
else
nchildren->children =
g_list_insert_sorted
(nchildren->children, list->data,
(GCompareFunc)notebook_child_compare_func);
} else {
if (g_list_find_custom (nchildren->tabs,
GINT_TO_POINTER (position),
(GCompareFunc)notebook_find_child))
nchildren->extra_tabs =
g_list_insert_sorted
(nchildren->extra_tabs, list->data,
(GCompareFunc)notebook_child_compare_func);
else
nchildren->tabs =
g_list_insert_sorted
(nchildren->tabs, list->data,
(GCompareFunc)notebook_child_compare_func);
}
}
}
/* Remove all pages, resulting in the unparenting of all widgets including tab-labels.
*/
while (gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook)) > 0)
{
page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 0);
/* Explicitly remove the tab label first */
gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), page, NULL);
gtk_notebook_remove_page (GTK_NOTEBOOK (notebook), 0);
}
if (children)
g_list_free (children);
return nchildren;
}
static void
glade_gtk_notebook_insert_children (GtkWidget *notebook, NotebookChildren *nchildren)
{
gint i;
/*********************************************************
INSERT PAGES
*********************************************************/
for (i = 0; i < nchildren->pages; i++)
{
GtkWidget *page = notebook_get_page (nchildren, i);
GtkWidget *tab = notebook_get_tab (nchildren, i);
gtk_notebook_insert_page (GTK_NOTEBOOK (notebook), page, NULL, i);
gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), page, tab);
g_object_unref (G_OBJECT (page));
g_object_unref (G_OBJECT (tab));
}
/* Stay on the same page */
gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), nchildren->page);
/* Free the original lists now */
if (nchildren->children)
g_list_free (nchildren->children);
if (nchildren->tabs)
g_list_free (nchildren->tabs);
if (nchildren->children ||
nchildren->tabs ||
nchildren->extra_children ||
nchildren->extra_tabs)
g_critical ("Unbalanced children when inserting notebook children"
" (pages: %d tabs: %d extra pages: %d extra tabs %d)",
g_list_length (nchildren->children),
g_list_length (nchildren->tabs),
g_list_length (nchildren->extra_children),
g_list_length (nchildren->extra_tabs));
g_free (nchildren);
}
static void
glade_gtk_notebook_switch_page (GtkNotebook *notebook,
GtkWidget *page,
guint page_num,
gpointer user_data)
{
GladeWidget *gnotebook = glade_widget_get_from_gobject (notebook);
glade_widget_property_set (gnotebook, "page", page_num);
}
/* Track project selection to set the notebook pages to display
* the selected widget.
*/
static void
glade_gtk_notebook_selection_changed (GladeProject *project,
GladeWidget *gwidget)
{
GladeWidget *selected;
GList *list;
gint i;
GtkWidget *page;
if ((list = glade_project_selection_get (project)) != NULL &&
g_list_length (list) == 1)
{
selected = glade_widget_get_from_gobject (list->data);
/* Check if selected widget is inside the notebook */
if (GTK_IS_WIDGET (selected->object) &&
gtk_widget_is_ancestor (GTK_WIDGET (selected->object),
GTK_WIDGET (gwidget->object)))
{
/* Find and activate the page */
for (i = 0; i < gtk_notebook_get_n_pages (GTK_NOTEBOOK (gwidget->object)); i++)
{
page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (gwidget->object), i);
if (GTK_WIDGET (selected->object) == page ||
gtk_widget_is_ancestor (GTK_WIDGET (selected->object),
GTK_WIDGET (page)))
{
glade_widget_property_set (gwidget, "page", i);
return;
}
}
}
}
}
static void
glade_gtk_notebook_project_changed (GladeWidget *gwidget,
GParamSpec *pspec,
gpointer userdata)
{
GladeProject
*project = glade_widget_get_project (gwidget),
*old_project = g_object_get_data (G_OBJECT (gwidget), "notebook-project-ptr");
if (old_project)
g_signal_handlers_disconnect_by_func (G_OBJECT (old_project),
G_CALLBACK (glade_gtk_notebook_selection_changed),
gwidget);
if (project)
g_signal_connect (G_OBJECT (project), "selection-changed",
G_CALLBACK (glade_gtk_notebook_selection_changed), gwidget);
g_object_set_data (G_OBJECT (gwidget), "notebook-project-ptr", project);
}
void
glade_gtk_notebook_post_create (GladeWidgetAdaptor *adaptor,
GObject *notebook,
GladeCreateReason reason)
{
GladeWidget *gwidget = glade_widget_get_from_gobject (notebook);
gtk_notebook_popup_disable (GTK_NOTEBOOK (notebook));
g_signal_connect (G_OBJECT (gwidget), "notify::project",
G_CALLBACK (glade_gtk_notebook_project_changed), NULL);
glade_gtk_notebook_project_changed (gwidget, NULL, NULL);
g_signal_connect (G_OBJECT (notebook), "switch-page",
G_CALLBACK (glade_gtk_notebook_switch_page), NULL);
}
static gint
glade_gtk_notebook_get_first_blank_page (GtkNotebook *notebook)
{
GladeWidget *gwidget;
GtkWidget *widget;
gint position;
for (position = 0; position < gtk_notebook_get_n_pages (notebook); position++)
{
widget = gtk_notebook_get_nth_page (notebook, position);
if ((gwidget = glade_widget_get_from_gobject (widget)) != NULL)
{
GladeProperty *property =
glade_widget_get_property (gwidget, "position");
gint gwidget_position = g_value_get_int (property->value);
if ((gwidget_position - position) > 0)
return position;
}
}
return position;
}
static GladeWidget *
glade_gtk_notebook_generate_tab (GladeWidget *notebook,
gint page_id)
{
static GladeWidgetAdaptor *wadaptor = NULL;
gchar *str;
GladeWidget *glabel;
if (wadaptor == NULL)
wadaptor = glade_widget_adaptor_get_by_type (GTK_TYPE_LABEL);
glabel = glade_widget_adaptor_create_widget (wadaptor, FALSE,
"parent", notebook,
"project", glade_widget_get_project (notebook),
NULL);
str = g_strdup_printf ("page %d", page_id);
glade_widget_property_set (glabel, "label", str);
g_free (str);
g_object_set_data (glabel->object, "special-child-type", "tab");
gtk_widget_show (GTK_WIDGET (glabel->object));
return glabel;
}
static void
glade_gtk_notebook_set_n_pages (GObject *object, const GValue *value)
{
GladeWidget *widget;
GtkNotebook *notebook;
GtkWidget *child_widget, *tab_widget;
gint new_size, i;
gint old_size;
notebook = GTK_NOTEBOOK (object);
g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
widget = glade_widget_get_from_gobject (GTK_WIDGET (notebook));
g_return_if_fail (widget != NULL);
new_size = g_value_get_int (value);
old_size = gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook));
/* Ensure base size of notebook */
if (glade_widget_superuser () == FALSE)
{
for (i = gtk_notebook_get_n_pages (notebook); i < new_size; i++)
{
gint position = glade_gtk_notebook_get_first_blank_page (notebook);
GtkWidget *placeholder = glade_placeholder_new ();
GladeWidget *gtab;
gtk_notebook_insert_page (notebook, placeholder, NULL, position);
/* XXX Ugly hack amongst many, this one only creates project widgets
* when the 'n-pages' of a notebook is initially set, otherwise it puts
* placeholders. (this makes the job easier when doing "insert before/after")
*/
if (old_size == 0 && new_size > 1)
{
gtab = glade_gtk_notebook_generate_tab (widget, position + 1);
/* Must pass through GladeWidget api so that packing props
* are correctly assigned.
*/
glade_widget_add_child (widget, gtab, FALSE);
}
else
{
GtkWidget *tab_placeholder = glade_placeholder_new ();
g_object_set_data (G_OBJECT (tab_placeholder), "special-child-type", "tab");
gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), placeholder,
tab_placeholder);
}
}
}
/*
* Thing to remember is that GtkNotebook starts the
* page numbers from 0, not 1 (C-style). So we need to do
* old_size-1, where we're referring to "nth" widget.
*/
while (old_size > new_size) {
/* Get the last page and remove it (project objects have been cleared by
* the action code already). */
child_widget = gtk_notebook_get_nth_page (notebook, old_size-1);
tab_widget = gtk_notebook_get_tab_label (notebook, child_widget);
/* Ok there shouldnt be widget in the content area, that's
* the placeholder, we should clean up the project widget that
* we put in the tab here though (this happens in the case where
* we undo increasing the "pages" property).
*/
if (glade_widget_get_from_gobject (child_widget))
g_critical ("Bug in notebook_set_n_pages()");
gtk_notebook_remove_page (notebook, old_size-1);
old_size--;
}
}
void
glade_gtk_notebook_set_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *id,
const GValue *value)
{
if (!strcmp (id, "pages"))
glade_gtk_notebook_set_n_pages (object, value);
else
GWA_GET_CLASS (GTK_TYPE_CONTAINER)->set_property (adaptor, object,
id, value);
}
static gboolean
glade_gtk_notebook_verify_n_pages (GObject *object, const GValue *value)
{
GtkNotebook *notebook = GTK_NOTEBOOK(object);
GtkWidget *child_widget, *tab_widget;
gint old_size, new_size = g_value_get_int (value);
for (old_size = gtk_notebook_get_n_pages (notebook);
old_size > new_size; old_size--) {
/* Get the last widget. */
child_widget = gtk_notebook_get_nth_page (notebook, old_size-1);
tab_widget = gtk_notebook_get_tab_label (notebook, child_widget);
/*
* If we got it, and its not a placeholder, remove it
* from project.
*/
if (glade_widget_get_from_gobject (child_widget) ||
glade_widget_get_from_gobject (tab_widget))
return FALSE;
}
return TRUE;
}
gboolean
glade_gtk_notebook_verify_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *id,
const GValue *value)
{
if (!strcmp (id, "pages"))
return glade_gtk_notebook_verify_n_pages (object, value);
else if (GWA_GET_CLASS (GTK_TYPE_CONTAINER)->verify_property)
GWA_GET_CLASS (GTK_TYPE_CONTAINER)->verify_property (adaptor, object,
id, value);
return TRUE;
}
void
glade_gtk_notebook_add_child (GladeWidgetAdaptor *adaptor,
GObject *object,
GObject *child)
{
GtkNotebook *notebook;
gint num_page, position = 0;
GtkWidget *last_page;
GladeWidget *gwidget;
gchar *special_child_type;
notebook = GTK_NOTEBOOK (object);
num_page = gtk_notebook_get_n_pages (notebook);
gwidget = glade_widget_get_from_gobject (object);
/* Just append pages blindly when loading/dupping
*/
if (glade_widget_superuser ())
{
special_child_type = g_object_get_data (child, "special-child-type");
if (special_child_type &&
!strcmp (special_child_type, "tab"))
{
last_page = gtk_notebook_get_nth_page (notebook, num_page - 1);
gtk_notebook_set_tab_label (notebook, last_page,
GTK_WIDGET (child));
}
else
{
gtk_container_add (GTK_CONTAINER (object), GTK_WIDGET (child));
glade_widget_property_set (gwidget, "pages", num_page + 1);
gwidget = glade_widget_get_from_gobject (child);
if (gwidget && gwidget->packing_properties)
glade_widget_pack_property_set (gwidget, "position", num_page);
}
}
else
{
NotebookChildren *nchildren;
/* Just destroy placeholders */
if (GLADE_IS_PLACEHOLDER (child))
gtk_widget_destroy (GTK_WIDGET (child));
else
{
gwidget = glade_widget_get_from_gobject (child);
g_assert (gwidget);
glade_widget_pack_property_get (gwidget, "position", &position);
nchildren = glade_gtk_notebook_extract_children (GTK_WIDGET (notebook));
if (g_object_get_data (child, "special-child-type") != NULL)
{
if (g_list_find_custom (nchildren->tabs,
GINT_TO_POINTER (position),
(GCompareFunc)notebook_find_child))
nchildren->extra_tabs =
g_list_insert_sorted
(nchildren->extra_tabs, child,
(GCompareFunc)notebook_child_compare_func);
else
nchildren->tabs =
g_list_insert_sorted
(nchildren->tabs, child,
(GCompareFunc)notebook_child_compare_func);
}
else
{
if (g_list_find_custom (nchildren->children,
GINT_TO_POINTER (position),
(GCompareFunc)notebook_find_child))
nchildren->extra_children =
g_list_insert_sorted
(nchildren->extra_children, child,
(GCompareFunc)notebook_child_compare_func);
else
nchildren->children =
g_list_insert_sorted
(nchildren->children, child,
(GCompareFunc)notebook_child_compare_func);
}
/* Takes an explicit reference when sitting on the list */
g_object_ref (child);
glade_gtk_notebook_insert_children (GTK_WIDGET (notebook), nchildren);
}
}
}
void
glade_gtk_notebook_remove_child (GladeWidgetAdaptor *adaptor,
GObject *object,
GObject *child)
{
NotebookChildren *nchildren;
nchildren = glade_gtk_notebook_extract_children (GTK_WIDGET (object));
if (g_list_find (nchildren->children, child))
{
nchildren->children =
g_list_remove (nchildren->children, child);
g_object_unref (child);
}
else if (g_list_find (nchildren->extra_children, child))
{
nchildren->extra_children =
g_list_remove (nchildren->extra_children, child);
g_object_unref (child);
}
else if (g_list_find (nchildren->tabs, child))
{
nchildren->tabs =
g_list_remove (nchildren->tabs, child);
g_object_unref (child);
}
else if (g_list_find (nchildren->extra_tabs, child))
{
nchildren->extra_tabs =
g_list_remove (nchildren->extra_tabs, child);
g_object_unref (child);
}
glade_gtk_notebook_insert_children (GTK_WIDGET (object), nchildren);
}
void
glade_gtk_notebook_replace_child (GladeWidgetAdaptor *adaptor,
GtkWidget *container,
GtkWidget *current,
GtkWidget *new_widget)
{
GtkNotebook *notebook;
GladeWidget *gcurrent, *gnew;
gint position = 0;
notebook = GTK_NOTEBOOK (container);
if ((gcurrent = glade_widget_get_from_gobject (current)) != NULL)
glade_widget_pack_property_get (gcurrent, "position", &position);
else
{
if ((position = gtk_notebook_page_num (notebook, current)) < 0)
{
position = notebook_search_tab (notebook, current);
g_assert (position >= 0);
}
}
if (g_object_get_data (G_OBJECT (current), "special-child-type"))
g_object_set_data (G_OBJECT (new_widget), "special-child-type", "tab");
glade_gtk_notebook_remove_child (adaptor,
G_OBJECT (container),
G_OBJECT (current));
if (GLADE_IS_PLACEHOLDER (new_widget) == FALSE)
{
gnew = glade_widget_get_from_gobject (new_widget);
glade_gtk_notebook_add_child (adaptor,
G_OBJECT (container),
G_OBJECT (new_widget));
if (glade_widget_pack_property_set (gnew, "position", position) == FALSE)
g_critical ("No position property found on new widget");
}
else
gtk_widget_destroy (GTK_WIDGET (new_widget));
}
gboolean
glade_gtk_notebook_child_verify_property (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *child,
const gchar *id,
GValue *value)
{
if (!strcmp (id, "position"))
return g_value_get_int (value) >= 0 &&
g_value_get_int (value) <
gtk_notebook_get_n_pages (GTK_NOTEBOOK (container));
else if (GWA_GET_CLASS (GTK_TYPE_CONTAINER)->child_verify_property)
GWA_GET_CLASS
(GTK_TYPE_CONTAINER)->child_verify_property (adaptor,
container, child,
id, value);
return TRUE;
}
void
glade_gtk_notebook_set_child_property (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *child,
const gchar *property_name,
const GValue *value)
{
NotebookChildren *nchildren;
if (strcmp (property_name, "position") == 0)
{
/* If we are setting this internally, avoid feedback. */
if (glade_gtk_notebook_setting_position ||
glade_widget_superuser ())
return;
/* Just rebuild the notebook, property values are already set at this point */
nchildren = glade_gtk_notebook_extract_children (GTK_WIDGET (container));
glade_gtk_notebook_insert_children (GTK_WIDGET (container), nchildren);
}
/* packing properties are unsupported on tabs ... except "position" */
else if (g_object_get_data (child, "special-child-type") == NULL)
GWA_GET_CLASS
(GTK_TYPE_CONTAINER)->child_set_property (adaptor,
container, child,
property_name, value);
}
void
glade_gtk_notebook_get_child_property (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *child,
const gchar *property_name,
GValue *value)
{
gint position;
if (strcmp (property_name, "position") == 0)
{
if (g_object_get_data (child, "special-child-type") != NULL)
{
if ((position = notebook_search_tab (GTK_NOTEBOOK (container),
GTK_WIDGET (child))) >= 0)
g_value_set_int (value, position);
else
g_value_set_int (value, 0);
}
else
gtk_container_child_get_property (GTK_CONTAINER (container),
GTK_WIDGET (child),
property_name,
value);
}
/* packing properties are unsupported on tabs ... except "position" */
else if (g_object_get_data (child, "special-child-type") == NULL)
gtk_container_child_get_property (GTK_CONTAINER (container),
GTK_WIDGET (child),
property_name,
value);
}
static void
glade_gtk_box_notebook_child_insert_remove_action (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *object,
const gchar *size_prop,
const gchar *group_format,
gboolean remove,
gboolean after)
{
GladeWidget *parent;
GList *children, *l;
gint child_pos, size, offset;
if (GTK_IS_NOTEBOOK (container) &&
g_object_get_data (object, "special-child-type"))
/* Its a Tab! */
child_pos = notebook_search_tab (GTK_NOTEBOOK (container),
GTK_WIDGET (object));
else
gtk_container_child_get (GTK_CONTAINER (container),
GTK_WIDGET (object),
"position", &child_pos, NULL);
parent = glade_widget_get_from_gobject (container);
glade_command_push_group (group_format, glade_widget_get_name (parent));
/* Make sure widgets does not get destroyed */
children = glade_widget_adaptor_get_children (adaptor, container);
g_list_foreach (children, (GFunc) g_object_ref, NULL);
glade_widget_property_get (parent, size_prop, &size);
if (remove)
{
GList *del = NULL;
offset = -1;
/* Remove children first */
for (l = children; l; l = g_list_next (l))
{
GladeWidget *gchild = glade_widget_get_from_gobject (l->data);
gint pos;
/* Skip placeholders */
if (gchild == NULL) continue;
glade_widget_pack_property_get (gchild, "position", &pos);
if (pos == child_pos) del = g_list_prepend (del, gchild);
}
if (del)
{
glade_command_delete (del);
g_list_free (del);
}
}
else
{
/* Expand container */
glade_command_set_property (glade_widget_get_property (parent, size_prop),
size + 1);
offset = 1;
}
/* Reoder children (fix the position property tracking widget positions) */
for (l = g_list_last (children); l; l = g_list_previous (l))
{
GladeWidget *gchild = glade_widget_get_from_gobject (l->data);
gint pos;
/* Skip placeholders */
if (gchild == NULL) continue;
glade_widget_pack_property_get (gchild, "position", &pos);
if ((after) ? pos > child_pos : pos >= child_pos)
glade_command_set_property (glade_widget_get_pack_property (gchild, "position"),
pos + offset);
}
if (remove)
{
/* Shrink container */
glade_command_set_property (glade_widget_get_property (parent, size_prop),
size - 1);
}
/* If it's a notebook we need to create an undoable tab now */
else if (GTK_IS_NOTEBOOK (container))
{
gint new_pos = after ? child_pos + 1 : child_pos;
GtkWidget *new_page;
GtkWidget *tab_placeholder;
GladeWidget *gtab;
GList list = { 0, };
new_page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (container), new_pos);
/* Deleting the project widget gives us a real placeholder now */
new_page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (container), new_pos);
tab_placeholder = gtk_notebook_get_tab_label (GTK_NOTEBOOK (container), new_page);
gtab = glade_gtk_notebook_generate_tab (parent, new_pos + 1);
list.data = gtab;
glade_command_paste (&list, parent, GLADE_PLACEHOLDER (tab_placeholder));
}
g_list_foreach (children, (GFunc) g_object_unref, NULL);
g_list_free (children);
glade_command_pop_group ();
}
void
glade_gtk_notebook_child_action_activate (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *object,
const gchar *action_path)
{
if (strcmp (action_path, "insert_page_after") == 0)
{
glade_gtk_box_notebook_child_insert_remove_action (adaptor, container,
object, "pages",
_("Insert page on %s"),
FALSE, TRUE);
}
else if (strcmp (action_path, "insert_page_before") == 0)
{
glade_gtk_box_notebook_child_insert_remove_action (adaptor, container,
object, "pages",
_("Insert page on %s"),
FALSE, FALSE);
}
else if (strcmp (action_path, "remove_page") == 0)
{
glade_gtk_box_notebook_child_insert_remove_action (adaptor, container,
object, "pages",
_("Remove page from %s"),
TRUE, TRUE);
}
else
GWA_GET_CLASS (GTK_TYPE_CONTAINER)->child_action_activate (adaptor,
container,
object,
action_path);
}
/* ----------------------------- GtkPaned ------------------------------ */
void
glade_gtk_paned_post_create (GladeWidgetAdaptor *adaptor,
GObject *paned,
GladeCreateReason reason)
{
g_return_if_fail (GTK_IS_PANED (paned));
if (reason == GLADE_CREATE_USER && gtk_paned_get_child1 (GTK_PANED (paned)) == NULL)
gtk_paned_add1 (GTK_PANED (paned), glade_placeholder_new ());
if (reason == GLADE_CREATE_USER && gtk_paned_get_child2 (GTK_PANED (paned)) == NULL)
gtk_paned_add2 (GTK_PANED (paned), glade_placeholder_new ());
}
void
glade_gtk_paned_add_child (GladeWidgetAdaptor *adaptor,
GObject *object,
GObject *child)
{
GtkPaned *paned;
GtkWidget *child1, *child2;
gboolean loading;
g_return_if_fail (GTK_IS_PANED (object));
paned = GTK_PANED (object);
loading = glade_util_object_is_loading (object);
child1 = gtk_paned_get_child1 (paned);
child2 = gtk_paned_get_child2 (paned);
if (loading == FALSE)
{
/* Remove a placeholder */
if (child1 && GLADE_IS_PLACEHOLDER (child1))
{
gtk_container_remove (GTK_CONTAINER (object), child1);
child1 = NULL;
}
else if (child2 && GLADE_IS_PLACEHOLDER (child2))
{
gtk_container_remove (GTK_CONTAINER (object), child2);
child2 = NULL;
}
}
/* Add the child */
if (child1 == NULL)
gtk_paned_add1 (paned, GTK_WIDGET (child));
else if (child2 == NULL)
gtk_paned_add2 (paned, GTK_WIDGET (child));
if (GLADE_IS_PLACEHOLDER (child) == FALSE && loading)
{
GladeWidget *gchild = glade_widget_get_from_gobject (child);
if (gchild && gchild->packing_properties)
{
if (child1 == NULL)
glade_widget_pack_property_set (gchild, "first", TRUE);
else if (child2 == NULL)
glade_widget_pack_property_set (gchild, "first", FALSE);
}
}
}
void
glade_gtk_paned_remove_child (GladeWidgetAdaptor *adaptor,
GObject *object,
GObject *child)
{
gtk_container_remove (GTK_CONTAINER (object), GTK_WIDGET (child));
glade_gtk_paned_post_create (adaptor, object, GLADE_CREATE_USER);
}
void
glade_gtk_paned_set_child_property (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *child,
const gchar *property_name,
const GValue *value)
{
if (strcmp (property_name, "first") == 0)
{
GtkPaned *paned = GTK_PANED (container);
gboolean first = g_value_get_boolean (value);
GtkWidget *place, *wchild = GTK_WIDGET (child);
place = (first) ? gtk_paned_get_child1 (paned) :
gtk_paned_get_child2 (paned);
if (place && GLADE_IS_PLACEHOLDER (place))
gtk_container_remove (GTK_CONTAINER (container), place);
g_object_ref (child);
gtk_container_remove (GTK_CONTAINER (container), wchild);
if (first)
gtk_paned_add1 (paned, wchild);
else
gtk_paned_add2 (paned, wchild);
g_object_unref (child);
/* Ensure placeholders */
if (glade_util_object_is_loading (child) == FALSE)
{
if ((place = gtk_paned_get_child1 (paned)) == NULL)
gtk_paned_add1 (paned, glade_placeholder_new ());
if ((place = gtk_paned_get_child2 (paned)) == NULL)
gtk_paned_add2 (paned, glade_placeholder_new ());
}
}
else
/* Chain Up */
GWA_GET_CLASS
(GTK_TYPE_CONTAINER)->child_set_property (adaptor,
container, child,
property_name, value);
}
void
glade_gtk_paned_get_child_property (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *child,
const gchar *property_name,
GValue *value)
{
if (strcmp (property_name, "first") == 0)
g_value_set_boolean (value, GTK_WIDGET (child) ==
gtk_paned_get_child1 (GTK_PANED (container)));
else
/* Chain Up */
GWA_GET_CLASS
(GTK_TYPE_CONTAINER)->child_get_property (adaptor,
container, child,
property_name, value);
}
/* ----------------------------- GtkExpander ------------------------------ */
void
glade_gtk_expander_post_create (GladeWidgetAdaptor *adaptor,
GObject *expander,
GladeCreateReason reason)
{
static GladeWidgetAdaptor *wadaptor = NULL;
GladeWidget *gexpander, *glabel;
GtkWidget *label;
if (wadaptor == NULL)
wadaptor = glade_widget_adaptor_get_by_type (GTK_TYPE_LABEL);
if (reason != GLADE_CREATE_USER) return;
g_return_if_fail (GTK_IS_EXPANDER (expander));
gexpander = glade_widget_get_from_gobject (expander);
g_return_if_fail (GLADE_IS_WIDGET (gexpander));
/* If we didnt put this object here... */
if ((label = gtk_expander_get_label_widget (GTK_EXPANDER (expander))) == NULL ||
(glade_widget_get_from_gobject (label) == NULL))
{
glabel = glade_widget_adaptor_create_widget (wadaptor, FALSE,
"parent", gexpander,
"project", glade_widget_get_project (gexpander),
NULL);
glade_widget_property_set (glabel, "label", "expander");
g_object_set_data (glabel->object, "special-child-type", "label_item");
glade_widget_add_child (gexpander, glabel, FALSE);
}
gtk_expander_set_expanded (GTK_EXPANDER (expander), TRUE);
gtk_container_add (GTK_CONTAINER (expander), glade_placeholder_new ());
}
void
glade_gtk_expander_replace_child (GladeWidgetAdaptor *adaptor,
GtkWidget *container,
GtkWidget *current,
GtkWidget *new_widget)
{
gchar *special_child_type;
special_child_type =
g_object_get_data (G_OBJECT (current), "special-child-type");
if (special_child_type && !strcmp (special_child_type, "label_item"))
{
g_object_set_data (G_OBJECT (new_widget), "special-child-type", "label_item");
gtk_expander_set_label_widget (GTK_EXPANDER (container), new_widget);
return;
}
/* Chain Up */
GWA_GET_CLASS
(GTK_TYPE_CONTAINER)->replace_child (adaptor,
G_OBJECT (container),
G_OBJECT (current),
G_OBJECT (new_widget));
}
void
glade_gtk_expander_add_child (GladeWidgetAdaptor *adaptor,
GObject *object,
GObject *child)
{
gchar *special_child_type;
special_child_type = g_object_get_data (child, "special-child-type");
if (special_child_type &&
!strcmp (special_child_type, "label"))
{
g_object_set_data (child,
"special-child-type",
"label_item");
gtk_expander_set_label_widget (GTK_EXPANDER (object),
GTK_WIDGET (child));
}
else if (special_child_type &&
!strcmp (special_child_type, "label_item"))
{
gtk_expander_set_label_widget (GTK_EXPANDER (object),
GTK_WIDGET (child));
}
else
/* Chain Up */
GWA_GET_CLASS (GTK_TYPE_CONTAINER)->add (adaptor, object, child);
}
void
glade_gtk_expander_remove_child (GladeWidgetAdaptor *adaptor,
GObject *object,
GObject *child)
{
gchar *special_child_type;
special_child_type = g_object_get_data (child, "special-child-type");
if (special_child_type &&
!strcmp (special_child_type, "label_item"))
{
gtk_expander_set_label_widget (GTK_EXPANDER (object),
glade_placeholder_new ());
}
else
{
gtk_container_remove (GTK_CONTAINER (object),
GTK_WIDGET (child));
gtk_container_add (GTK_CONTAINER (object),
glade_placeholder_new ());
}
}
void
glade_gtk_expander_write_child (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlContext *context,
GladeXmlNode *node)
{
if (!write_special_child_label_item (adaptor, widget, context, node,
GWA_GET_CLASS(GTK_TYPE_CONTAINER)->write_child))
/* Chain Up */
GWA_GET_CLASS
(GTK_TYPE_CONTAINER)->write_child (adaptor,
widget,
context,
node);
}
/* -------------------------------- GtkEntry -------------------------------- */
gboolean
glade_gtk_entry_depends (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeWidget *another)
{
if (GTK_IS_ENTRY_BUFFER (another->object))
return TRUE;
return GWA_GET_CLASS (GTK_TYPE_WIDGET)->depends (adaptor, widget, another);
}
static void
glade_gtk_entry_changed (GtkEditable *editable, GladeWidget *gentry)
{
const gchar *text, *text_prop;
GladeProperty *prop;
gboolean use_buffer;
if (glade_widget_superuser ())
return;
text = gtk_entry_get_text (GTK_ENTRY (editable));
glade_widget_property_get (gentry, "text", &text_prop);
glade_widget_property_get (gentry, "use-entry-buffer", &use_buffer);
if (use_buffer == FALSE && g_strcmp0 (text, text_prop))
{
if ((prop = glade_widget_get_property (gentry, "text")))
glade_command_set_property (prop, text);
}
}
void
glade_gtk_entry_post_create (GladeWidgetAdaptor *adaptor,
GObject *object,
GladeCreateReason reason)
{
GladeWidget *gentry;
g_return_if_fail (GTK_IS_ENTRY (object));
gentry = glade_widget_get_from_gobject (object);
g_return_if_fail (GLADE_IS_WIDGET (gentry));
g_signal_connect (object, "changed",
G_CALLBACK (glade_gtk_entry_changed), gentry);
}
GladeEditable *
glade_gtk_entry_create_editable (GladeWidgetAdaptor *adaptor,
GladeEditorPageType type)
{
GladeEditable *editable;
/* Get base editable */
editable = GWA_GET_CLASS (GTK_TYPE_WIDGET)->create_editable (adaptor, type);
if (type == GLADE_PAGE_GENERAL)
return (GladeEditable *)glade_entry_editor_new (adaptor, editable);
return editable;
}
void
glade_gtk_entry_set_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *id,
const GValue *value)
{
GladeImageEditMode mode;
GladeWidget *gwidget = glade_widget_get_from_gobject (object);
GladeProperty *property = glade_widget_get_property (gwidget, id);
if (!strcmp (id, "use-entry-buffer"))
{
glade_widget_property_set_sensitive (gwidget, "text", FALSE, NOT_SELECTED_MSG);
glade_widget_property_set_sensitive (gwidget, "buffer", FALSE, NOT_SELECTED_MSG);
if (g_value_get_boolean (value))
glade_widget_property_set_sensitive (gwidget, "buffer", TRUE, NULL);
else
glade_widget_property_set_sensitive (gwidget, "text", TRUE, NULL);
}
else if (!strcmp (id, "primary-icon-mode"))
{
mode = g_value_get_int (value);
glade_widget_property_set_sensitive (gwidget, "primary-icon-stock", FALSE, NOT_SELECTED_MSG);
glade_widget_property_set_sensitive (gwidget, "primary-icon-name", FALSE, NOT_SELECTED_MSG);
glade_widget_property_set_sensitive (gwidget, "primary-icon-pixbuf", FALSE, NOT_SELECTED_MSG);
switch (mode) {
case GLADE_IMAGE_MODE_STOCK:
glade_widget_property_set_sensitive (gwidget, "primary-icon-stock", TRUE, NULL);
break;
case GLADE_IMAGE_MODE_ICON:
glade_widget_property_set_sensitive (gwidget, "primary-icon-name", TRUE, NULL);
break;
case GLADE_IMAGE_MODE_FILENAME:
glade_widget_property_set_sensitive (gwidget, "primary-icon-pixbuf", TRUE, NULL);
break;
}
}
else if (!strcmp (id, "secondary-icon-mode"))
{
mode = g_value_get_int (value);
glade_widget_property_set_sensitive (gwidget, "secondary-icon-stock", FALSE, NOT_SELECTED_MSG);
glade_widget_property_set_sensitive (gwidget, "secondary-icon-name", FALSE, NOT_SELECTED_MSG);
glade_widget_property_set_sensitive (gwidget, "secondary-icon-pixbuf", FALSE, NOT_SELECTED_MSG);
switch (mode) {
case GLADE_IMAGE_MODE_STOCK:
glade_widget_property_set_sensitive (gwidget, "secondary-icon-stock", TRUE, NULL);
break;
case GLADE_IMAGE_MODE_ICON:
glade_widget_property_set_sensitive (gwidget, "secondary-icon-name", TRUE, NULL);
break;
case GLADE_IMAGE_MODE_FILENAME:
glade_widget_property_set_sensitive (gwidget, "secondary-icon-pixbuf", TRUE, NULL);
break;
}
}
else if (!strcmp (id, "primary-icon-tooltip-text") ||
!strcmp (id, "primary-icon-tooltip-markup"))
{
/* Avoid a silly crash in GTK+ */
if (gtk_entry_get_icon_storage_type (GTK_ENTRY (object),
GTK_ENTRY_ICON_PRIMARY) != GTK_IMAGE_EMPTY)
GWA_GET_CLASS (GTK_TYPE_WIDGET)->set_property (adaptor, object, id, value);
}
else if (!strcmp (id, "secondary-icon-tooltip-text") ||
!strcmp (id, "secondary-icon-tooltip-markup"))
{
/* Avoid a silly crash in GTK+ */
if (gtk_entry_get_icon_storage_type (GTK_ENTRY (object),
GTK_ENTRY_ICON_SECONDARY) != GTK_IMAGE_EMPTY)
GWA_GET_CLASS (GTK_TYPE_WIDGET)->set_property (adaptor, object, id, value);
}
else if (!strcmp (id, "text"))
{
g_signal_handlers_block_by_func (object, glade_gtk_entry_changed, gwidget);
if (g_value_get_string (value))
gtk_entry_set_text (GTK_ENTRY (object), g_value_get_string (value));
else
gtk_entry_set_text (GTK_ENTRY (object), "");
g_signal_handlers_unblock_by_func (object, glade_gtk_entry_changed, gwidget);
}
else if (GPC_VERSION_CHECK (property->klass, gtk_major_version, gtk_minor_version + 1))
GWA_GET_CLASS (GTK_TYPE_WIDGET)->set_property (adaptor, object, id, value);
}
void
glade_gtk_entry_read_widget (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlNode *node)
{
GladeProperty *property;
if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
return;
/* First chain up and read in all the normal properties.. */
GWA_GET_CLASS (GTK_TYPE_WIDGET)->read_widget (adaptor, widget, node);
if (glade_widget_property_original_default (widget, "text") == FALSE)
{
property = glade_widget_get_property (widget, "text");
glade_widget_property_set (widget, "use-entry-buffer", FALSE);
glade_property_sync (property);
}
else
{
gint target_minor, target_major;
glade_project_get_target_version (widget->project, "gtk+", &target_major, &target_minor);
property = glade_widget_get_property (widget, "buffer");
/* Only default to the buffer setting if the project version supports it. */
if (GPC_VERSION_CHECK (property->klass, target_major, target_minor))
{
glade_widget_property_set (widget, "use-entry-buffer", TRUE);
glade_property_sync (property);
}
else
glade_widget_property_set (widget, "use-entry-buffer", FALSE);
}
if (glade_widget_property_original_default (widget, "primary-icon-name") == FALSE)
{
property = glade_widget_get_property (widget, "primary-icon-name");
glade_widget_property_set (widget, "primary-icon-mode", GLADE_IMAGE_MODE_ICON);
}
else if (glade_widget_property_original_default (widget, "primary-icon-pixbuf") == FALSE)
{
property = glade_widget_get_property (widget, "primary-icon-pixbuf");
glade_widget_property_set (widget, "primary-icon-mode", GLADE_IMAGE_MODE_FILENAME);
}
else/* if (glade_widget_property_original_default (widget, "stock") == FALSE) */
{
property = glade_widget_get_property (widget, "primary-icon-stock");
glade_widget_property_set (widget, "primary-icon-mode", GLADE_IMAGE_MODE_STOCK);
}
glade_property_sync (property);
if (glade_widget_property_original_default (widget, "secondary-icon-name") == FALSE)
{
property = glade_widget_get_property (widget, "secondary-icon-name");
glade_widget_property_set (widget, "secondary-icon-mode", GLADE_IMAGE_MODE_ICON);
}
else if (glade_widget_property_original_default (widget, "secondary-icon-pixbuf") == FALSE)
{
property = glade_widget_get_property (widget, "secondary-icon-pixbuf");
glade_widget_property_set (widget, "secondary-icon-mode", GLADE_IMAGE_MODE_FILENAME);
}
else/* if (glade_widget_property_original_default (widget, "stock") == FALSE) */
{
property = glade_widget_get_property (widget, "secondary-icon-stock");
glade_widget_property_set (widget, "secondary-icon-mode", GLADE_IMAGE_MODE_STOCK);
}
glade_property_sync (property);
}
/* ----------------------------- GtkFixed/GtkLayout ------------------------------ */
#if 0
static void
glade_gtk_fixed_layout_finalize(GdkPixmap *backing)
{
g_object_unref(backing);
}
#endif
static void
glade_gtk_fixed_layout_realize (GtkWidget *widget)
{
#if _FIXME_FIXME_CAIRO_
GdkPixbuf *pixbuf = gdk_pixbuf_new_from_xpm_data (fixed_bg_xpm);
GdkPixmap *backing;
gdk_pixbuf_render_pixmap_and_mask (pixbuf, &backing, NULL, 1);
if (GTK_IS_LAYOUT (widget))
gdk_window_set_back_pixmap (gtk_layout_get_bin_window (GTK_LAYOUT (widget)),
backing, FALSE);
else
gdk_window_set_back_pixmap (gtk_widget_get_window (widget), backing, FALSE);
/* For cleanup later
*/
g_object_weak_ref(G_OBJECT(widget),
(GWeakNotify)glade_gtk_fixed_layout_finalize, backing);
#endif
}
static void
glade_gtk_fixed_layout_sync_size_requests (GtkWidget *widget)
{
GList *children, *l;
if ((children = gtk_container_get_children (GTK_CONTAINER (widget))) != NULL)
{
for (l = children; l; l = l->next)
{
GtkWidget *child = l->data;
GladeWidget *gchild = glade_widget_get_from_gobject (child);
gint width = -1, height = -1;
if (!gchild)
continue;
glade_widget_property_get (gchild, "width-request", &width);
glade_widget_property_get (gchild, "height-request", &height);
gtk_widget_set_size_request (child, width, height);
}
g_list_free (children);
}
}
void
glade_gtk_fixed_layout_post_create (GladeWidgetAdaptor *adaptor,
GObject *object,
GladeCreateReason reason)
{
/* This is needed at least to set a backing pixmap. */
gtk_widget_set_has_window (GTK_WIDGET (object), FALSE);
/* For backing pixmap
*/
g_signal_connect_after(object, "realize",
G_CALLBACK(glade_gtk_fixed_layout_realize), NULL);
/* Sync up size request at project load time */
if (reason == GLADE_CREATE_LOAD)
g_signal_connect_after(object, "realize",
G_CALLBACK(glade_gtk_fixed_layout_sync_size_requests), NULL);
}
void
glade_gtk_fixed_layout_add_child (GladeWidgetAdaptor *adaptor,
GObject *object,
GObject *child)
{
g_return_if_fail (GTK_IS_CONTAINER (object));
g_return_if_fail (GTK_IS_WIDGET (child));
gtk_container_add (GTK_CONTAINER (object), GTK_WIDGET (child));
}
void
glade_gtk_fixed_layout_remove_child (GladeWidgetAdaptor *adaptor,
GObject *object,
GObject *child)
{
g_return_if_fail (GTK_IS_CONTAINER (object));
g_return_if_fail (GTK_IS_WIDGET (child));
gtk_container_remove (GTK_CONTAINER (object), GTK_WIDGET (child));
}
/* ----------------------------- GtkWindow ------------------------------ */
static void
glade_gtk_window_read_accel_groups (GladeWidget *widget,
GladeXmlNode *node)
{
GladeXmlNode *groups_node;
GladeProperty *property;
gchar *string = NULL;
if ((groups_node =
glade_xml_search_child (node, GLADE_TAG_ACCEL_GROUPS)) != NULL)
{
GladeXmlNode *node;
for (node = glade_xml_node_get_children (groups_node);
node; node = glade_xml_node_next (node))
{
gchar *group_name, *tmp;
if (!glade_xml_node_verify (node, GLADE_TAG_ACCEL_GROUP))
continue;
group_name = glade_xml_get_property_string_required
(node, GLADE_TAG_NAME, NULL);
if (string == NULL)
string = group_name;
else if (group_name != NULL)
{
tmp = g_strdup_printf ("%s%s%s", string, GPC_OBJECT_DELIMITER, group_name);
string = (g_free (string), tmp);
g_free (group_name);
}
}
}
if (string)
{
property = glade_widget_get_property (widget, "accel-groups");
g_assert (property);
/* we must synchronize this directly after loading this project
* (i.e. lookup the actual objects after they've been parsed and
* are present).
*/
g_object_set_data_full (G_OBJECT (property),
"glade-loaded-object",
string, g_free);
}
}
void
glade_gtk_window_read_widget (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlNode *node)
{
if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
return;
/* First chain up and read in all the normal properties.. */
GWA_GET_CLASS (GTK_TYPE_WIDGET)->read_widget (adaptor, widget, node);
glade_gtk_window_read_accel_groups (widget, node);
}
static void
glade_gtk_window_write_accel_groups (GladeWidget *widget,
GladeXmlContext *context,
GladeXmlNode *node)
{
GladeXmlNode *groups_node, *group_node;
GList *groups = NULL, *list;
GladeWidget *agroup;
groups_node = glade_xml_node_new (context, GLADE_TAG_ACCEL_GROUPS);
if (glade_widget_property_get (widget, "accel-groups", &groups))
{
for (list = groups; list; list = list->next)
{
agroup = glade_widget_get_from_gobject (list->data);
group_node = glade_xml_node_new (context, GLADE_TAG_ACCEL_GROUP);
glade_xml_node_append_child (groups_node, group_node);
glade_xml_node_set_property_string (group_node, GLADE_TAG_NAME, agroup->name);
}
}
if (!glade_xml_node_get_children (groups_node))
glade_xml_node_delete (groups_node);
else
glade_xml_node_append_child (node, groups_node);
}
void
glade_gtk_window_write_widget (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlContext *context,
GladeXmlNode *node)
{
if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
return;
/* First chain up and read in all the normal properties.. */
GWA_GET_CLASS (GTK_TYPE_WIDGET)->write_widget (adaptor, widget, context, node);
glade_gtk_window_write_accel_groups (widget, context, node);
}
/* ----------------------------- GtkDialog(s) ------------------------------ */
static void
glade_gtk_dialog_stop_offending_signals (GtkWidget *widget)
{
static gpointer hierarchy = NULL, screen;
if (hierarchy == NULL)
{
hierarchy = GUINT_TO_POINTER (g_signal_lookup ("hierarchy-changed",
GTK_TYPE_WIDGET));
screen = GUINT_TO_POINTER (g_signal_lookup ("screen-changed",
GTK_TYPE_WIDGET));
}
g_signal_connect (widget, "hierarchy-changed",
G_CALLBACK (glade_gtk_stop_emission_POINTER),
hierarchy);
g_signal_connect (widget, "screen-changed",
G_CALLBACK (glade_gtk_stop_emission_POINTER),
screen);
}
static void
glade_gtk_file_chooser_default_forall (GtkWidget *widget, gpointer data)
{
/* Since GtkFileChooserDefault is not exposed we check if its a
* GtkFileChooser
*/
if (GTK_IS_FILE_CHOOSER (widget))
{
/* Finally we can connect to the signals we want to stop its
* default handler. Since both signals has the same signature
* we use one callback for both :)
*/
glade_gtk_dialog_stop_offending_signals (widget);
}
}
static void
glade_gtk_file_chooser_forall (GtkWidget *widget, gpointer data)
{
/* GtkFileChooserWidget packs a GtkFileChooserDefault */
if (GTK_IS_FILE_CHOOSER_WIDGET (widget))
gtk_container_forall (GTK_CONTAINER (widget),
glade_gtk_file_chooser_default_forall,
NULL);
}
void
glade_gtk_dialog_post_create (GladeWidgetAdaptor *adaptor,
GObject *object,
GladeCreateReason reason)
{
GtkDialog *dialog = GTK_DIALOG (object);
GladeWidget *widget;
GladeWidget *vbox_widget, *actionarea_widget, *colorsel, *fontsel;
GladeWidget *ok_button = NULL, *cancel_button = NULL,
*help_button = NULL, *apply_button = NULL;
g_return_if_fail (GTK_IS_DIALOG (dialog));
widget = glade_widget_get_from_gobject (GTK_WIDGET (dialog));
if (!widget)
return;
if (reason == GLADE_CREATE_USER)
{
/* HIG complient border-width defaults on dialogs */
glade_widget_property_set (widget, "border-width", 5);
}
if (GTK_IS_COLOR_SELECTION_DIALOG (object))
{
GtkWidget *child;
child = gtk_dialog_get_widget_for_response (dialog, GTK_RESPONSE_OK);
ok_button = glade_widget_adaptor_create_internal
(widget, G_OBJECT (child),
"ok_button", "colorsel", FALSE, reason);
child = gtk_dialog_get_widget_for_response (dialog, GTK_RESPONSE_CANCEL);
cancel_button = glade_widget_adaptor_create_internal
(widget, G_OBJECT (child),
"cancel_button", "colorsel", FALSE, reason);
child = gtk_dialog_get_widget_for_response (dialog, GTK_RESPONSE_HELP);
help_button = glade_widget_adaptor_create_internal
(widget, G_OBJECT (child),
"help_button", "colorsel", FALSE, reason);
child = gtk_color_selection_dialog_get_color_selection (GTK_COLOR_SELECTION_DIALOG (dialog));
colorsel = glade_widget_adaptor_create_internal
(widget, G_OBJECT (child),
"color_selection", "colorsel", FALSE, reason);
/* Set this to 1 at load time, if there are any children then
* size will adjust appropriately (otherwise the default "3" gets
* set and we end up with extra placeholders).
*/
if (reason == GLADE_CREATE_LOAD)
glade_widget_property_set (colorsel, "size", 1);
}
else if (GTK_IS_FONT_SELECTION_DIALOG (object))
{
GtkWidget *child;
child = gtk_font_selection_dialog_get_ok_button (GTK_FONT_SELECTION_DIALOG (dialog));
ok_button = glade_widget_adaptor_create_internal
(widget, G_OBJECT (child),
"ok_button", "fontsel", FALSE, reason);
child = gtk_dialog_get_widget_for_response (dialog, GTK_RESPONSE_APPLY);
apply_button = glade_widget_adaptor_create_internal
(widget, G_OBJECT (child),
"apply_button", "fontsel", FALSE, reason);
child = gtk_font_selection_dialog_get_cancel_button (GTK_FONT_SELECTION_DIALOG (dialog));
cancel_button = glade_widget_adaptor_create_internal
(widget, G_OBJECT (child),
"cancel_button", "fontsel", FALSE, reason);
#if GTK_CHECK_VERSION (2, 24, 0)
child = gtk_font_selection_dialog_get_font_selection
(GTK_FONT_SELECTION_DIALOG (dialog));
#else
child = GTK_FONT_SELECTION_DIALOG (dialog)->fontsel;
#endif
fontsel = glade_widget_adaptor_create_internal
(widget, G_OBJECT (child),
"font_selection", "fontsel", FALSE, reason);
/* Set this to 1 at load time, if there are any children then
* size will adjust appropriately (otherwise the default "3" gets
* set and we end up with extra placeholders).
*/
if (reason == GLADE_CREATE_LOAD)
glade_widget_property_set (fontsel, "size", 2);
}
else
{
/* We need to stop default emissions of "hierarchy-changed" and
* "screen-changed" of GtkFileChooserDefault to avoid an abort()
* when doing a reparent.
* GtkFileChooserDialog packs a GtkFileChooserWidget in
* his internal vbox.
*/
if (GTK_IS_FILE_CHOOSER_DIALOG (object))
gtk_container_forall (GTK_CONTAINER (gtk_dialog_get_content_area (dialog)),
glade_gtk_file_chooser_forall,
NULL);
vbox_widget = glade_widget_adaptor_create_internal
(widget, G_OBJECT(gtk_dialog_get_content_area (dialog)),
"vbox", "dialog", FALSE, reason);
actionarea_widget = glade_widget_adaptor_create_internal
(vbox_widget, G_OBJECT(gtk_dialog_get_action_area (dialog)),
"action_area", "dialog", FALSE, reason);
/* These properties are controlled by the GtkDialog style properties:
* "content-area-border", "button-spacing" and "action-area-border",
* so we must disable thier use.
*/
glade_widget_remove_property (vbox_widget, "border-width");
glade_widget_remove_property (actionarea_widget, "border-width");
glade_widget_remove_property (actionarea_widget, "spacing");
/* Only set these on the original create. */
if (reason == GLADE_CREATE_USER)
{
/* HIG complient spacing defaults on dialogs */
glade_widget_property_set (vbox_widget, "spacing", 2);
if (GTK_IS_MESSAGE_DIALOG (object))
glade_widget_property_set (vbox_widget, "size", 2);
else if (GTK_IS_ABOUT_DIALOG (object))
glade_widget_property_set (vbox_widget, "size", 3);
else if (GTK_IS_FILE_CHOOSER_DIALOG (object))
glade_widget_property_set (vbox_widget, "size", 3);
else
glade_widget_property_set (vbox_widget, "size", 2);
glade_widget_property_set (actionarea_widget, "size", 2);
glade_widget_property_set (actionarea_widget, "layout-style", GTK_BUTTONBOX_END);
}
}
}
GtkWidget *
glade_gtk_dialog_get_internal_child (GladeWidgetAdaptor *adaptor,
GtkDialog *dialog,
const gchar *name)
{
GtkWidget *child = NULL;
g_return_val_if_fail (GTK_IS_DIALOG (dialog), NULL);
if (GTK_IS_COLOR_SELECTION_DIALOG (dialog))
{
if (strcmp ("ok_button", name) == 0)
child = gtk_dialog_get_widget_for_response (dialog, GTK_RESPONSE_OK);
else if (strcmp ("cancel_button", name) == 0)
child = gtk_dialog_get_widget_for_response (dialog, GTK_RESPONSE_CANCEL);
else if (strcmp ("help_button", name) == 0)
child = gtk_dialog_get_widget_for_response (dialog, GTK_RESPONSE_HELP);
else if (strcmp ("color_selection", name) == 0)
child = gtk_color_selection_dialog_get_color_selection
(GTK_COLOR_SELECTION_DIALOG (dialog));
}
else if (GTK_IS_FONT_SELECTION_DIALOG (dialog))
{
if (strcmp ("ok_button", name) == 0)
child = gtk_font_selection_dialog_get_ok_button (GTK_FONT_SELECTION_DIALOG (dialog));
else if (strcmp ("apply_button", name) == 0)
child = gtk_dialog_get_widget_for_response (dialog, GTK_RESPONSE_APPLY);
else if (strcmp ("cancel_button", name) == 0)
child = gtk_font_selection_dialog_get_cancel_button
(GTK_FONT_SELECTION_DIALOG (dialog));
else if (strcmp ("font_selection", name) == 0)
{
#if GTK_CHECK_VERSION (2, 24, 0)
child = gtk_font_selection_dialog_get_font_selection
(GTK_FONT_SELECTION_DIALOG (dialog));
#else
child = GTK_FONT_SELECTION_DIALOG (dialog)->fontsel;
#endif
}
}
else
{
/* Default generic dialog handling
*/
if (strcmp ("vbox", name) == 0)
child = gtk_dialog_get_content_area (dialog);
else if (strcmp ("action_area", name) == 0)
child = gtk_dialog_get_action_area (dialog);
}
return child;
}
GList *
glade_gtk_dialog_get_children (GladeWidgetAdaptor *adaptor,
GtkDialog *dialog)
{
GList *list = NULL;
g_return_val_if_fail (GTK_IS_DIALOG (dialog), NULL);
list = glade_util_container_get_all_children (GTK_CONTAINER (dialog));
if (GTK_IS_COLOR_SELECTION_DIALOG (dialog))
{
GtkWidget *widget;
widget = gtk_dialog_get_widget_for_response (dialog, GTK_RESPONSE_OK);
if (widget) list = g_list_prepend (list, widget);
widget = gtk_dialog_get_widget_for_response (dialog, GTK_RESPONSE_CANCEL);
if (widget) list = g_list_prepend (list, widget);
widget = gtk_dialog_get_widget_for_response (dialog, GTK_RESPONSE_HELP);
if (widget) list = g_list_prepend (list, widget);
widget = gtk_color_selection_dialog_get_color_selection (GTK_COLOR_SELECTION_DIALOG (dialog));
if (widget) list = g_list_prepend (list, widget);
}
else if (GTK_IS_FONT_SELECTION_DIALOG (dialog))
{
GtkWidget *widget;
widget = gtk_font_selection_dialog_get_ok_button (GTK_FONT_SELECTION_DIALOG (dialog));
if (widget) list = g_list_prepend (list, widget);
widget = gtk_dialog_get_widget_for_response (dialog, GTK_RESPONSE_APPLY);
if (widget) list = g_list_prepend (list, widget);
widget = gtk_font_selection_dialog_get_cancel_button (GTK_FONT_SELECTION_DIALOG (dialog));
if (widget) list = g_list_prepend (list, widget);
#if GTK_CHECK_VERSION (2, 24, 0)
widget = gtk_font_selection_dialog_get_font_selection (GTK_FONT_SELECTION_DIALOG (dialog));
#else
widget = GTK_FONT_SELECTION_DIALOG (dialog)->fontsel;
#endif
if (widget) list = g_list_prepend (list, widget);
}
return list;
}
#define GLADE_TAG_ACTION_WIDGETS "action-widgets"
#define GLADE_TAG_ACTION_WIDGET "action-widget"
#define GLADE_TAG_RESPONSE "response"
static void
glade_gtk_dialog_read_responses (GladeWidget *widget,
GladeXmlNode *widgets_node)
{
GladeXmlNode *node;
GladeWidget *action_widget;
for (node = glade_xml_node_get_children (widgets_node);
node; node = glade_xml_node_next (node))
{
gchar *widget_name, *response;
if (!glade_xml_node_verify (node, GLADE_TAG_ACTION_WIDGET))
continue;
response = glade_xml_get_property_string_required (node, GLADE_TAG_RESPONSE, NULL);
widget_name = glade_xml_get_content (node);
if ((action_widget =
glade_project_get_widget_by_name (widget->project, widget, widget_name)) != NULL)
{
glade_widget_property_set (action_widget, "response-id",
g_ascii_strtoll (response, NULL, 10));
}
g_free (response);
g_free (widget_name);
}
}
void
glade_gtk_dialog_read_child (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlNode *node)
{
GladeXmlNode *widgets_node;
GWA_GET_CLASS (GTK_TYPE_CONTAINER)->read_child (adaptor, widget, node);
node = glade_xml_node_get_parent (node);
if ((widgets_node = glade_xml_search_child (node, GLADE_TAG_ACTION_WIDGETS)) != NULL)
glade_gtk_dialog_read_responses (widget, widgets_node);
}
static void
glade_gtk_dialog_write_responses (GladeWidget *widget,
GladeXmlContext *context,
GladeXmlNode *node)
{
GladeXmlNode *widget_node;
GtkDialog *dialog = GTK_DIALOG (widget->object);
GList *l, *action_widgets =
gtk_container_get_children (GTK_CONTAINER (gtk_dialog_get_action_area (dialog)));
for (l = action_widgets; l; l = l->next)
{
GladeWidget *action_widget;
GladeProperty *property;
gchar *str;
if ((action_widget = glade_widget_get_from_gobject (l->data)) == NULL)
continue;
if ((property = glade_widget_get_property (action_widget, "response-id")) == NULL)
continue;
widget_node = glade_xml_node_new (context, GLADE_TAG_ACTION_WIDGET);
glade_xml_node_append_child (node, widget_node);
str = glade_property_class_make_string_from_gvalue (property->klass, property->value);
glade_xml_node_set_property_string (widget_node, GLADE_TAG_RESPONSE, str);
glade_xml_set_content (widget_node, action_widget->name);
g_free (str);
}
g_list_free (action_widgets);
}
void
glade_gtk_dialog_write_child (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlContext *context,
GladeXmlNode *node)
{
GladeXmlNode *widgets_node;
GladeWidget *parent;
GladeProject *project;
GWA_GET_CLASS (GTK_TYPE_CONTAINER)->write_child (adaptor, widget, context, node);
parent = widget->parent;
project = widget->project;
if (parent && GTK_IS_DIALOG (parent->object))
{
widgets_node = glade_xml_node_new (context, GLADE_TAG_ACTION_WIDGETS);
glade_gtk_dialog_write_responses (parent, context, widgets_node);
if (!glade_xml_node_get_children (widgets_node))
glade_xml_node_delete (widgets_node);
else
glade_xml_node_append_child (node, widgets_node);
}
}
/*--------------------------- GtkMessageDialog ---------------------------------*/
static gboolean
glade_gtk_message_dialog_reset_image (GtkMessageDialog *dialog)
{
GtkWidget *image;
gint message_type;
g_object_get (dialog, "message-type", &message_type, NULL);
if (message_type != GTK_MESSAGE_OTHER)
return FALSE;
image = gtk_message_dialog_get_image (dialog);
if (glade_widget_get_from_gobject (image))
{
gtk_message_dialog_set_image (dialog,
gtk_image_new_from_stock (NULL, GTK_ICON_SIZE_DIALOG));
gtk_widget_show (image);
return TRUE;
}
else
return FALSE;
}
enum {
MD_IMAGE_ACTION_INVALID,
MD_IMAGE_ACTION_RESET,
MD_IMAGE_ACTION_SET
};
static gint
glade_gtk_message_dialog_image_determine_action (GtkMessageDialog *dialog,
const GValue *value,
GtkWidget **image,
GladeWidget **gimage)
{
GtkWidget *dialog_image = gtk_message_dialog_get_image (dialog);
*image = g_value_get_object (value);
if (*image == NULL)
if (glade_widget_get_from_gobject (dialog_image))
return MD_IMAGE_ACTION_RESET;
else
return MD_IMAGE_ACTION_INVALID;
else
{
*image = GTK_WIDGET (*image);
if (dialog_image == *image)
return MD_IMAGE_ACTION_INVALID;
if (gtk_widget_get_parent (*image))
return MD_IMAGE_ACTION_INVALID;
*gimage = glade_widget_get_from_gobject (*image);
if (!*gimage)
{
g_warning ("Setting property to an object outside the project");
return MD_IMAGE_ACTION_INVALID;
}
if (glade_widget_get_parent (*gimage) || GWA_IS_TOPLEVEL ((*gimage)->adaptor))
return MD_IMAGE_ACTION_INVALID;
return MD_IMAGE_ACTION_SET;
}
}
void
glade_gtk_message_dialog_set_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *id,
const GValue *value)
{
GtkMessageDialog *dialog = GTK_MESSAGE_DIALOG (object);
GladeWidget *gwidget = glade_widget_get_from_gobject (object);
g_return_if_fail (gwidget);
if (strcmp (id, "image") == 0)
{
GtkWidget *image = NULL;
GladeWidget *gimage = NULL;
gint rslt;
rslt = glade_gtk_message_dialog_image_determine_action (dialog, value,
&image, &gimage);
switch (rslt)
{
case MD_IMAGE_ACTION_INVALID:
return;
case MD_IMAGE_ACTION_RESET:
glade_gtk_message_dialog_reset_image (dialog);
return;
case MD_IMAGE_ACTION_SET:
break; /* continue setting the property */
}
if (gtk_widget_get_parent (image))
g_critical ("Image should have no parent now");
gtk_message_dialog_set_image (dialog, image);
{
/* syncing "message-type" property */
GladeProperty *property;
property = glade_widget_get_property (gwidget, "message-type");
if (!glade_property_equals (property, GTK_MESSAGE_OTHER))
glade_command_set_property (property, GTK_MESSAGE_OTHER);
}
}
else
{
/* We must reset the image to internal,
* external image would otherwise become internal
*/
if (!strcmp (id, "message-type") &&
g_value_get_enum (value) != GTK_MESSAGE_OTHER)
{
GladeProperty *property;
property = glade_widget_get_property (gwidget, "image");
if (!glade_property_equals (property, NULL))
glade_command_set_property (property, NULL);
}
/* Chain up, even if property us message-type because
* it's not fully handled here
*/
GWA_GET_CLASS (GTK_TYPE_DIALOG)->set_property (adaptor, object,
id, value);
}
}
gboolean
glade_gtk_message_dialog_verify_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *id,
const GValue *value)
{
if (!strcmp (id, "image"))
{
GtkWidget *image; GladeWidget *gimage;
gboolean retval = MD_IMAGE_ACTION_INVALID !=
glade_gtk_message_dialog_image_determine_action (GTK_MESSAGE_DIALOG (object),
value, &image, &gimage);
return retval;
}
else
if (GWA_GET_CLASS (GTK_TYPE_CONTAINER)->verify_property)
return GWA_GET_CLASS (GTK_TYPE_CONTAINER)->verify_property (adaptor, object,
id, value);
else
return TRUE;
}
void
glade_gtk_message_dialog_get_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *property_name,
GValue *value)
{
if (!strcmp (property_name, "image"))
{
GtkMessageDialog *dialog = GTK_MESSAGE_DIALOG (object);
GtkWidget *image = gtk_message_dialog_get_image (dialog);
if (!glade_widget_get_from_gobject (image))
g_value_set_object (value, NULL);
else
g_value_set_object (value, image);
}
else
GWA_GET_CLASS (GTK_TYPE_DIALOG)->get_property (adaptor, object,
property_name, value);
}
/* ----------------------------- GtkFileChooserWidget ------------------------------ */
void
glade_gtk_file_chooser_widget_post_create (GladeWidgetAdaptor *adaptor,
GObject *object,
GladeCreateReason reason)
{
gtk_container_forall (GTK_CONTAINER (object),
glade_gtk_file_chooser_default_forall,
NULL);
}
void
glade_gtk_file_chooser_button_set_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *id,
const GValue *value)
{
/* Avoid a warning */
if (!strcmp (id, "action"))
{
if (g_value_get_enum (value) == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER ||
g_value_get_enum (value) == GTK_FILE_CHOOSER_ACTION_SAVE)
return;
}
GWA_GET_CLASS (GTK_TYPE_BOX)->set_property (adaptor,
object,
id, value);
}
/* ----------------------------- GtkFontButton ------------------------------ */
/* Use the font-buttons launch dialog to actually set the font-name
* glade property through the glade-command api.
*/
static void
glade_gtk_font_button_refresh_font_name (GtkFontButton *button,
GladeWidget *gbutton)
{
GladeProperty *property;
if ((property =
glade_widget_get_property (gbutton, "font-name")) != NULL)
glade_command_set_property (property,
gtk_font_button_get_font_name (button));
}
/* ----------------------------- GtkColorButton ------------------------------ */
static void
glade_gtk_color_button_refresh_color (GtkColorButton *button,
GladeWidget *gbutton)
{
GladeProperty *property;
GdkColor color = { 0, };
if ((property = glade_widget_get_property (gbutton, "color")) != NULL)
glade_command_set_property (property, &color);
}
void
glade_gtk_color_button_set_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *id,
const GValue *value)
{
if (!strcmp (id, "color"))
{
if (g_value_get_boxed (value))
gtk_color_button_set_color (GTK_COLOR_BUTTON (object),
(GdkColor *)g_value_get_boxed (value));
}
else
GWA_GET_CLASS (GTK_TYPE_BUTTON)->set_property (adaptor,
object,
id, value);
}
/* ----------------------------- GtkButton ------------------------------ */
static void
sync_use_appearance (GladeWidget *gwidget)
{
GladeProperty *prop = glade_widget_get_property (gwidget, "use-action-appearance");
gboolean use_appearance = FALSE;
/* This is the kind of thing we avoid doing at project load time ;-) */
if (glade_widget_superuser ())
return;
glade_property_get (prop, &use_appearance);
if (use_appearance)
{
glade_property_set (prop, FALSE);
glade_property_set (prop, TRUE);
}
}
/* shared between menuitems and toolitems too */
static void
evaluate_activatable_property_sensitivity (GObject *object,
const gchar *id,
const GValue *value)
{
GladeWidget *gwidget = glade_widget_get_from_gobject (object);
if (!strcmp (id, "related-action"))
{
GtkAction *action = g_value_get_object (value);
if (action)
{
glade_widget_property_set_sensitive (gwidget, "visible", FALSE, ACTION_APPEARANCE_MSG);
glade_widget_property_set_sensitive (gwidget, "sensitive", FALSE, ACTION_APPEARANCE_MSG);
glade_widget_property_set_sensitive (gwidget, "accel-group", FALSE, ACTION_APPEARANCE_MSG);
} else {
glade_widget_property_set_sensitive (gwidget, "visible", TRUE, NULL);
glade_widget_property_set_sensitive (gwidget, "sensitive", TRUE, NULL);
glade_widget_property_set_sensitive (gwidget, "accel-group", TRUE, NULL);
}
}
else if (!strcmp (id, "use-action-appearance"))
{
gboolean use_appearance = g_value_get_boolean (value);
if (use_appearance)
{
glade_widget_property_set_sensitive (gwidget, "label", FALSE, ACTION_APPEARANCE_MSG);
glade_widget_property_set_sensitive (gwidget, "use-underline", FALSE, ACTION_APPEARANCE_MSG);
glade_widget_property_set_sensitive (gwidget, "stock", FALSE, ACTION_APPEARANCE_MSG);
//glade_widget_property_set_sensitive (gwidget, "use-stock", FALSE, ACTION_APPEARANCE_MSG);
glade_widget_property_set_sensitive (gwidget, "image", FALSE, ACTION_APPEARANCE_MSG);
glade_widget_property_set_sensitive (gwidget, "custom-child", FALSE, ACTION_APPEARANCE_MSG);
glade_widget_property_set_sensitive (gwidget, "stock-id", FALSE, ACTION_APPEARANCE_MSG);
glade_widget_property_set_sensitive (gwidget, "label-widget", FALSE, ACTION_APPEARANCE_MSG);
glade_widget_property_set_sensitive (gwidget, "icon-name", FALSE, ACTION_APPEARANCE_MSG);
glade_widget_property_set_sensitive (gwidget, "icon-widget", FALSE, ACTION_APPEARANCE_MSG);
glade_widget_property_set_sensitive (gwidget, "icon", FALSE, ACTION_APPEARANCE_MSG);
} else {
glade_widget_property_set_sensitive (gwidget, "label", TRUE, NULL);
glade_widget_property_set_sensitive (gwidget, "use-underline", TRUE, NULL);
glade_widget_property_set_sensitive (gwidget, "stock", TRUE, NULL);
//glade_widget_property_set_sensitive (gwidget, "use-stock", TRUE, NULL);
glade_widget_property_set_sensitive (gwidget, "image", TRUE, NULL);
glade_widget_property_set_sensitive (gwidget, "custom-child", TRUE, NULL);
glade_widget_property_set_sensitive (gwidget, "stock-id", TRUE, NULL);
glade_widget_property_set_sensitive (gwidget, "label-widget", TRUE, NULL);
glade_widget_property_set_sensitive (gwidget, "icon-name", TRUE, NULL);
glade_widget_property_set_sensitive (gwidget, "icon-widget", TRUE, NULL);
glade_widget_property_set_sensitive (gwidget, "icon", TRUE, NULL);
}
}
}
GladeEditable *
glade_gtk_button_create_editable (GladeWidgetAdaptor *adaptor,
GladeEditorPageType type)
{
GladeEditable *editable;
/* Get base editable */
editable = GWA_GET_CLASS (GTK_TYPE_CONTAINER)->create_editable (adaptor, type);
if (type == GLADE_PAGE_GENERAL)
{
editable = (GladeEditable *)glade_activatable_editor_new (adaptor, editable);
return (GladeEditable *)glade_button_editor_new (adaptor, editable);
}
return editable;
}
void
glade_gtk_button_post_create (GladeWidgetAdaptor *adaptor,
GObject *button,
GladeCreateReason reason)
{
GladeWidget *gbutton = glade_widget_get_from_gobject (button);
g_return_if_fail (GTK_IS_BUTTON (button));
g_return_if_fail (GLADE_IS_WIDGET (gbutton));
if (GTK_IS_FONT_BUTTON (button))
g_signal_connect
(button, "font-set",
G_CALLBACK (glade_gtk_font_button_refresh_font_name), gbutton);
else if (GTK_IS_COLOR_BUTTON (button))
g_signal_connect
(button, "color-set",
G_CALLBACK (glade_gtk_color_button_refresh_color), gbutton);
/* Disabled response-id until its in an action area */
glade_widget_property_set_sensitive (gbutton, "response-id", FALSE,
RESPID_INSENSITIVE_MSG);
glade_widget_property_set_enabled (gbutton, "response-id", FALSE);
}
void
glade_gtk_button_set_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *id,
const GValue *value)
{
GladeWidget *widget = glade_widget_get_from_gobject (object);
GladeProperty *property = glade_widget_get_property (widget, id);
evaluate_activatable_property_sensitivity (object, id, value);
if (strcmp (id, "custom-child") == 0)
{
GtkWidget *child = gtk_bin_get_child (GTK_BIN (object));
if (g_value_get_boolean (value))
{
if (child)
gtk_container_remove (GTK_CONTAINER (object), child);
gtk_container_add (GTK_CONTAINER (object), glade_placeholder_new ());
}
else if (child && GLADE_IS_PLACEHOLDER (child))
gtk_container_remove (GTK_CONTAINER (object), child);
}
else if (strcmp (id, "stock") == 0)
{
gboolean use_stock = FALSE;
glade_widget_property_get (widget, "use-stock", &use_stock);
if (use_stock)
gtk_button_set_label (GTK_BUTTON (object), g_value_get_string (value));
}
else if (strcmp (id, "use-stock") == 0)
{
/* I guess its my bug in GTK+, we need to resync the appearance property
* on GtkButton when the GtkButton:use-stock property changes.
*/
GWA_GET_CLASS (GTK_TYPE_CONTAINER)->set_property (adaptor, object,
id, value);
sync_use_appearance (widget);
}
else if (GPC_VERSION_CHECK (property->klass, gtk_major_version, gtk_minor_version + 1))
GWA_GET_CLASS (GTK_TYPE_CONTAINER)->set_property (adaptor, object,
id, value);
}
void
glade_gtk_button_read_widget (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlNode *node)
{
gboolean use_stock;
gchar *label = NULL;
if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
return;
/* First chain up and read in all the normal properties.. */
GWA_GET_CLASS (GTK_TYPE_CONTAINER)->read_widget (adaptor, widget, node);
/* Update the stock property */
glade_widget_property_get (widget, "use-stock", &use_stock);
if (use_stock)
{
glade_widget_property_get (widget, "label", &label);
glade_widget_property_set (widget, "stock", label);
}
}
void
glade_gtk_button_write_widget (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlContext *context,
GladeXmlNode *node)
{
GladeProperty *prop;
gboolean use_stock;
gchar *stock = NULL;
if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
return;
/* Do not save GtkColorButton and GtkFontButton label property */
if (!(GTK_IS_COLOR_BUTTON (widget->object) || GTK_IS_FONT_BUTTON (widget->object)))
{
/* Make a copy of the GladeProperty,
* override its value and ensure non-translatable if use-stock is TRUE
*/
prop = glade_widget_get_property (widget, "label");
prop = glade_property_dup (prop, widget);
glade_widget_property_get (widget, "use-stock", &use_stock);
if (use_stock)
{
glade_widget_property_get (widget, "stock", &stock);
glade_property_i18n_set_translatable (prop, FALSE);
glade_property_set (prop, stock);
}
glade_property_write (prop, context, node);
g_object_unref (G_OBJECT (prop));
}
/* Write out other normal properties and any other class derived custom properties after ... */
GWA_GET_CLASS (GTK_TYPE_CONTAINER)->write_widget (adaptor, widget, context, node);
}
/* ----------------------------- GtkImage ------------------------------ */
void
glade_gtk_image_read_widget (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlNode *node)
{
GladeProperty *property;
if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
return;
/* First chain up and read in all the normal properties.. */
GWA_GET_CLASS (GTK_TYPE_WIDGET)->read_widget (adaptor, widget, node);
if (glade_widget_property_original_default (widget, "icon-name") == FALSE)
{
property = glade_widget_get_property (widget, "icon-name");
glade_widget_property_set (widget, "image-mode", GLADE_IMAGE_MODE_ICON);
}
else if (glade_widget_property_original_default (widget, "pixbuf") == FALSE)
{
property = glade_widget_get_property (widget, "pixbuf");
glade_widget_property_set (widget, "image-mode", GLADE_IMAGE_MODE_FILENAME);
}
else/* if (glade_widget_property_original_default (widget, "stock") == FALSE) */
{
property = glade_widget_get_property (widget, "stock");
glade_widget_property_set (widget, "image-mode", GLADE_IMAGE_MODE_STOCK);
}
glade_property_sync (property);
}
void
glade_gtk_image_write_widget (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlContext *context,
GladeXmlNode *node)
{
GladeXmlNode *prop_node;
GladeProperty *size_prop;
GtkIconSize icon_size;
gchar *value;
if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
return;
/* First chain up and write all the normal properties (including "use-stock")... */
GWA_GET_CLASS (GTK_TYPE_WIDGET)->write_widget (adaptor, widget, context, node);
/* We have to save icon-size as an integer, the core will take care of
* loading the int value though.
*/
size_prop = glade_widget_get_property (widget, "icon-size");
if (!glade_property_original_default (size_prop))
{
prop_node = glade_xml_node_new (context, GLADE_TAG_PROPERTY);
glade_xml_node_append_child (node, prop_node);
glade_xml_node_set_property_string (prop_node, GLADE_TAG_NAME, size_prop->klass->id);
glade_property_get (size_prop, &icon_size);
value = g_strdup_printf ("%d", icon_size);
glade_xml_set_content (prop_node, value);
g_free (value);
}
}
static void
glade_gtk_image_set_image_mode (GObject *object, const GValue *value)
{
GladeWidget *gwidget;
GladeImageEditMode type;
gwidget = glade_widget_get_from_gobject (object);
g_return_if_fail (GTK_IS_IMAGE (object));
g_return_if_fail (GLADE_IS_WIDGET (gwidget));
glade_widget_property_set_sensitive (gwidget, "stock", FALSE, NOT_SELECTED_MSG);
glade_widget_property_set_sensitive (gwidget, "icon-name", FALSE, NOT_SELECTED_MSG);
glade_widget_property_set_sensitive (gwidget, "pixbuf", FALSE, NOT_SELECTED_MSG);
glade_widget_property_set_sensitive (gwidget, "icon-size", FALSE,
_("This property only applies to stock images"));
glade_widget_property_set_sensitive (gwidget, "pixel-size", FALSE,
_("This property only applies to named icons"));
switch ((type = g_value_get_int (value)))
{
case GLADE_IMAGE_MODE_STOCK:
glade_widget_property_set_sensitive (gwidget, "stock", TRUE, NULL);
glade_widget_property_set_sensitive (gwidget, "icon-size", TRUE, NULL);
break;
case GLADE_IMAGE_MODE_ICON:
glade_widget_property_set_sensitive (gwidget, "icon-name", TRUE, NULL);
glade_widget_property_set_sensitive (gwidget, "pixel-size", TRUE, NULL);
break;
case GLADE_IMAGE_MODE_FILENAME:
glade_widget_property_set_sensitive (gwidget, "pixbuf", TRUE, NULL);
default:
break;
}
}
void
glade_gtk_image_get_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *id,
GValue *value)
{
if (!strcmp (id, "icon-size"))
{
/* Make the int an enum... */
GValue int_value = { 0, };
g_value_init (&int_value, G_TYPE_INT);
GWA_GET_CLASS (GTK_TYPE_WIDGET)->get_property (adaptor, object, id, &int_value);
g_value_set_enum (value, g_value_get_int (&int_value));
g_value_unset (&int_value);
}
else
GWA_GET_CLASS (GTK_TYPE_WIDGET)->set_property (adaptor, object,
id, value);
}
void
glade_gtk_image_set_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *id,
const GValue *value)
{
if (!strcmp (id, "image-mode"))
glade_gtk_image_set_image_mode (object, value);
else if (!strcmp (id, "icon-size"))
{
/* Make the enum an int... */
GValue int_value = { 0, };
g_value_init (&int_value, G_TYPE_INT);
g_value_set_int (&int_value, g_value_get_enum (value));
GWA_GET_CLASS (GTK_TYPE_WIDGET)->set_property (adaptor, object, id, &int_value);
g_value_unset (&int_value);
}
else
{
GladeWidget *widget = glade_widget_get_from_gobject (object);
GladeImageEditMode mode = 0;
glade_widget_property_get (widget, "image-mode", &mode);
/* avoid setting properties in the wrong mode... */
switch (mode)
{
case GLADE_IMAGE_MODE_STOCK:
if (!strcmp (id, "icon-name") ||
!strcmp (id, "pixbuf"))
return;
break;
case GLADE_IMAGE_MODE_ICON:
if (!strcmp (id, "stock") ||
!strcmp (id, "pixbuf"))
return;
break;
case GLADE_IMAGE_MODE_FILENAME:
if (!strcmp (id, "stock") ||
!strcmp (id, "icon-name"))
return;
default:
break;
}
GWA_GET_CLASS (GTK_TYPE_WIDGET)->set_property (adaptor, object,
id, value);
}
}
GladeEditable *
glade_gtk_image_create_editable (GladeWidgetAdaptor *adaptor,
GladeEditorPageType type)
{
GladeEditable *editable;
/* Get base editable */
editable = GWA_GET_CLASS (GTK_TYPE_WIDGET)->create_editable (adaptor, type);
if (type == GLADE_PAGE_GENERAL)
return (GladeEditable *)glade_image_editor_new (adaptor, editable);
return editable;
}
/* ----------------------------- GtkMenu ------------------------------ */
GObject *
glade_gtk_menu_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties)
{
GladeWidgetAdaptor *adaptor;
GObject *ret_obj;
ret_obj = GWA_GET_OCLASS(GTK_TYPE_CONTAINER)->constructor
(type, n_construct_properties, construct_properties);
adaptor = GLADE_WIDGET_ADAPTOR (ret_obj);
glade_widget_adaptor_action_remove (adaptor, "add_parent");
glade_widget_adaptor_action_remove (adaptor, "remove_parent");
return ret_obj;
}
/* ----------------------------- GtkMenuShell ------------------------------ */
void
glade_gtk_menu_shell_add_child (GladeWidgetAdaptor *adaptor,
GObject *object,
GObject *child)
{
g_return_if_fail (GTK_IS_MENU_SHELL (object));
g_return_if_fail (GTK_IS_MENU_ITEM (child));
gtk_menu_shell_append (GTK_MENU_SHELL (object), GTK_WIDGET (child));
}
void
glade_gtk_menu_shell_remove_child (GladeWidgetAdaptor *adaptor,
GObject *object,
GObject *child)
{
g_return_if_fail (GTK_IS_MENU_SHELL (object));
g_return_if_fail (GTK_IS_MENU_ITEM (child));
gtk_container_remove (GTK_CONTAINER (object), GTK_WIDGET (child));
}
static gint
glade_gtk_menu_shell_get_item_position (GObject *container, GObject *child)
{
gint position = 0;
GList *list = gtk_container_get_children (GTK_CONTAINER (container));
while (list)
{
if (G_OBJECT (list->data) == child) break;
list = list->next;
position++;
}
g_list_free (list);
return position;
}
void
glade_gtk_menu_shell_get_child_property (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *child,
const gchar *property_name,
GValue *value)
{
g_return_if_fail (GTK_IS_MENU_SHELL (container));
g_return_if_fail (GTK_IS_MENU_ITEM (child));
if (strcmp (property_name, "position") == 0)
{
g_value_set_int (value,
glade_gtk_menu_shell_get_item_position (container,
child));
}
else
/* Chain Up */
GWA_GET_CLASS
(GTK_TYPE_CONTAINER)->child_get_property (adaptor,
container,
child,
property_name,
value);
}
void
glade_gtk_menu_shell_set_child_property (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *child,
const gchar *property_name,
GValue *value)
{
g_return_if_fail (GTK_IS_MENU_SHELL (container));
g_return_if_fail (GTK_IS_MENU_ITEM (child));
g_return_if_fail (property_name != NULL || value != NULL);
if (strcmp (property_name, "position") == 0)
{
GladeWidget *gitem;
gint position;
gitem = glade_widget_get_from_gobject (child);
g_return_if_fail (GLADE_IS_WIDGET (gitem));
position = g_value_get_int (value);
if (position < 0)
{
position = glade_gtk_menu_shell_get_item_position (container, child);
g_value_set_int (value, position);
}
g_object_ref (child);
gtk_container_remove (GTK_CONTAINER (container), GTK_WIDGET (child));
gtk_menu_shell_insert (GTK_MENU_SHELL (container), GTK_WIDGET (child), position);
g_object_unref (child);
}
else
/* Chain Up */
GWA_GET_CLASS
(GTK_TYPE_CONTAINER)->child_set_property (adaptor,
container, child,
property_name, value);
}
static gchar *
glade_gtk_menu_shell_tool_item_get_display_name (GladeBaseEditor *editor,
GladeWidget *gchild,
gpointer user_data)
{
GObject *child = glade_widget_get_object (gchild);
gchar *name;
if (GTK_IS_SEPARATOR_MENU_ITEM (child) ||
GTK_IS_SEPARATOR_TOOL_ITEM (child))
name = _("<separator>");
else if (GTK_IS_MENU_ITEM (child))
glade_widget_property_get (gchild, "label", &name);
else if (GTK_IS_TOOL_BUTTON (child))
{
glade_widget_property_get (gchild, "label", &name);
if (name == NULL || strlen (name) == 0)
glade_widget_property_get (gchild, "stock-id", &name);
}
else
name = _("<custom>");
return g_strdup (name);
}
static GladeWidget *
glade_gtk_menu_shell_item_get_parent (GladeWidget *gparent, GObject *parent)
{
GtkWidget *submenu = NULL;
if (GTK_IS_MENU_TOOL_BUTTON (parent))
submenu = gtk_menu_tool_button_get_menu (GTK_MENU_TOOL_BUTTON (parent));
else if (GTK_IS_MENU_ITEM (parent))
submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (parent));
if (submenu)
gparent = glade_widget_get_from_gobject (submenu);
else
gparent = glade_command_create (glade_widget_adaptor_get_by_type (GTK_TYPE_MENU),
gparent, NULL, glade_widget_get_project (gparent));
return gparent;
}
static GladeWidget *
glade_gtk_menu_shell_build_child (GladeBaseEditor *editor,
GladeWidget *gparent,
GType type,
gpointer data)
{
GObject *parent = glade_widget_get_object (gparent);
GladeWidget *gitem_new;
if (GTK_IS_SEPARATOR_MENU_ITEM (parent))
return NULL;
/* Get or build real parent */
if (GTK_IS_MENU_ITEM (parent) || GTK_IS_MENU_TOOL_BUTTON (parent))
gparent = glade_gtk_menu_shell_item_get_parent (gparent, parent);
/* Build child */
gitem_new = glade_command_create (glade_widget_adaptor_get_by_type (type),
gparent, NULL,
glade_widget_get_project (gparent));
if (type != GTK_TYPE_SEPARATOR_MENU_ITEM)
{
glade_widget_property_set (gitem_new, "label",
glade_widget_get_name (gitem_new));
glade_widget_property_set (gitem_new, "use-underline", TRUE);
}
return gitem_new;
}
static gboolean
glade_gtk_menu_shell_delete_child (GladeBaseEditor *editor,
GladeWidget *gparent,
GladeWidget *gchild,
gpointer data)
{
GObject *item = glade_widget_get_object (gparent);
GtkWidget *submenu = NULL;
GList list = {0, };
gint n_children = 0;
if (GTK_IS_MENU_ITEM (item) &&
(submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (item))))
{
GList *l = gtk_container_get_children (GTK_CONTAINER (submenu));
n_children = g_list_length (l);
g_list_free (l);
}
if (submenu && n_children == 1)
list.data = glade_widget_get_parent (gchild);
else
list.data = gchild;
/* Remove widget */
glade_command_delete (&list);
return TRUE;
}
static gboolean
glade_gtk_menu_shell_move_child (GladeBaseEditor *editor,
GladeWidget *gparent,
GladeWidget *gchild,
gpointer data)
{
GObject *parent = glade_widget_get_object (gparent);
GObject *child = glade_widget_get_object (gchild);
GladeWidget *old_parent = gchild->parent;
GList list = {0, };
if (GTK_IS_SEPARATOR_MENU_ITEM (parent) ||
GTK_IS_SEPARATOR_TOOL_ITEM (parent))
return FALSE;
if (GTK_IS_MENU_ITEM (child) && GTK_IS_TOOLBAR (parent))
return FALSE;
if (GTK_IS_TOOL_ITEM (child) &&
(GTK_IS_MENU (parent) || GTK_IS_MENU_BAR (parent) || GTK_IS_MENU_ITEM (parent)))
return FALSE;
if (GTK_IS_TOOL_ITEM (parent) &&
(!GTK_IS_MENU_TOOL_BUTTON (parent) || !GTK_IS_MENU_ITEM (child)))
return FALSE;
if (GTK_IS_MENU_ITEM (parent) || GTK_IS_MENU_TOOL_BUTTON (parent))
gparent = glade_gtk_menu_shell_item_get_parent (gparent, parent);
if (gparent != glade_widget_get_parent (gchild))
{
list.data = gchild;
glade_command_dnd (&list, gparent, NULL);
}
/* Delete dangling childless menus */
if (GTK_IS_MENU (old_parent->object) &&
old_parent->parent && GTK_IS_MENU_ITEM (old_parent->parent->object))
{
GList del = { 0, }, *children;
children = gtk_container_get_children (GTK_CONTAINER (old_parent->object));
if (!children)
{
del.data = old_parent;
glade_command_delete (&del);
}
g_list_free (children);
}
return TRUE;
}
static gboolean
glade_gtk_menu_shell_change_type (GladeBaseEditor *editor,
GladeWidget *gchild,
GType type,
gpointer data)
{
GObject *child = glade_widget_get_object (gchild);
if ((type == GTK_TYPE_SEPARATOR_MENU_ITEM &&
gtk_menu_item_get_submenu (GTK_MENU_ITEM (child))) ||
(GTK_IS_MENU_TOOL_BUTTON (child) &&
gtk_menu_tool_button_get_menu (GTK_MENU_TOOL_BUTTON (child))))
return TRUE;
/* Delete the internal image of an image menu item before going ahead and changing types. */
if (GTK_IS_IMAGE_MENU_ITEM (child))
{
GList list = { 0, };
GtkWidget *image = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (child));
GladeWidget *widget;
if (image && (widget = glade_widget_get_from_gobject (image)))
{
list.data = widget;
glade_command_unlock_widget (widget);
glade_command_delete (&list);
}
}
return FALSE;
}
static void
glade_gtk_toolbar_child_selected (GladeBaseEditor *editor,
GladeWidget *gchild,
gpointer data)
{
GObject *child = glade_widget_get_object (gchild);
GType type = G_OBJECT_TYPE (child);
glade_base_editor_add_label (editor, _("Tool Item"));
glade_base_editor_add_default_properties (editor, gchild);
glade_base_editor_add_label (editor, _("Properties"));
glade_base_editor_add_editable (editor, gchild, GLADE_PAGE_GENERAL);
if (type == GTK_TYPE_SEPARATOR_TOOL_ITEM) return;
glade_base_editor_add_label (editor, _("Packing"));
glade_base_editor_add_properties (editor, gchild, TRUE,
"expand", "homogeneous", NULL);
}
static void
glade_gtk_menu_shell_tool_item_child_selected (GladeBaseEditor *editor,
GladeWidget *gchild,
gpointer data)
{
GObject *child = glade_widget_get_object (gchild);
GType type = G_OBJECT_TYPE (child);
if (GTK_IS_TOOL_ITEM (child))
{
glade_gtk_toolbar_child_selected (editor, gchild, data);
return;
}
glade_base_editor_add_label (editor, _("Menu Item"));
glade_base_editor_add_default_properties (editor, gchild);
if (GTK_IS_SEPARATOR_MENU_ITEM (child)) return;
glade_base_editor_add_label (editor, _("Properties"));
if (type != GTK_TYPE_IMAGE_MENU_ITEM)
glade_base_editor_add_properties (editor, gchild, FALSE, "label", "tooltip", NULL);
if (type == GTK_TYPE_IMAGE_MENU_ITEM)
glade_base_editor_add_editable (editor, gchild, GLADE_PAGE_GENERAL);
else if (type == GTK_TYPE_CHECK_MENU_ITEM)
glade_base_editor_add_properties (editor, gchild, FALSE,
"active", "draw-as-radio",
"inconsistent", NULL);
else if (type == GTK_TYPE_RADIO_MENU_ITEM)
glade_base_editor_add_properties (editor, gchild, FALSE,
"active", "group", NULL);
}
static void
glade_gtk_menu_shell_launch_editor (GObject *object, gchar *title)
{
GladeBaseEditor *editor;
GtkWidget *window;
/* Editor */
editor = glade_base_editor_new (object, NULL,
_("Normal item"), GTK_TYPE_MENU_ITEM,
_("Image item"), GTK_TYPE_IMAGE_MENU_ITEM,
_("Check item"), GTK_TYPE_CHECK_MENU_ITEM,
_("Radio item"), GTK_TYPE_RADIO_MENU_ITEM,
_("Separator item"), GTK_TYPE_SEPARATOR_MENU_ITEM,
NULL);
glade_base_editor_append_types (editor, GTK_TYPE_MENU_ITEM,
_("Normal item"), GTK_TYPE_MENU_ITEM,
_("Image item"), GTK_TYPE_IMAGE_MENU_ITEM,
_("Check item"), GTK_TYPE_CHECK_MENU_ITEM,
_("Radio item"), GTK_TYPE_RADIO_MENU_ITEM,
_("Separator item"), GTK_TYPE_SEPARATOR_MENU_ITEM,
NULL);
g_signal_connect (editor, "get-display-name", G_CALLBACK (glade_gtk_menu_shell_tool_item_get_display_name), NULL);
g_signal_connect (editor, "child-selected", G_CALLBACK (glade_gtk_menu_shell_tool_item_child_selected), NULL);
g_signal_connect (editor, "change-type", G_CALLBACK (glade_gtk_menu_shell_change_type), NULL);
g_signal_connect (editor, "build-child", G_CALLBACK (glade_gtk_menu_shell_build_child), NULL);
g_signal_connect (editor, "delete-child", G_CALLBACK (glade_gtk_menu_shell_delete_child), NULL);
g_signal_connect (editor, "move-child", G_CALLBACK (glade_gtk_menu_shell_move_child), NULL);
gtk_widget_show (GTK_WIDGET (editor));
window = glade_base_editor_pack_new_window (editor, title, NULL);
gtk_widget_show (window);
}
void
glade_gtk_menu_shell_action_activate (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *action_path)
{
if (strcmp (action_path, "launch_editor") == 0)
{
if (GTK_IS_MENU_BAR (object))
glade_gtk_menu_shell_launch_editor (object, _("Edit Menu Bar"));
else if (GTK_IS_MENU (object))
glade_gtk_menu_shell_launch_editor (object, _("Edit Menu"));
}
else
GWA_GET_CLASS (GTK_TYPE_CONTAINER)->action_activate (adaptor,
object,
action_path);
gtk_menu_shell_deactivate (GTK_MENU_SHELL (object));
}
/* ----------------------------- GtkMenuItem ------------------------------ */
/* ... shared with toolitems ... */
GladeEditable *
glade_gtk_activatable_create_editable (GladeWidgetAdaptor *adaptor,
GladeEditorPageType type)
{
GladeEditable *editable;
/* Get base editable */
editable = GWA_GET_CLASS (GTK_TYPE_CONTAINER)->create_editable (adaptor, type);
if (type == GLADE_PAGE_GENERAL)
return (GladeEditable *)glade_activatable_editor_new (adaptor, editable);
return editable;
}
void
glade_gtk_menu_item_action_activate (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *action_path)
{
GObject *obj = NULL, *shell = NULL;
GladeWidget *w = glade_widget_get_from_gobject (object);
while ((w = glade_widget_get_parent (w)))
{
obj = glade_widget_get_object (w);
if (GTK_IS_MENU_SHELL (obj)) shell = obj;
}
if (strcmp (action_path, "launch_editor") == 0)
{
if (shell)
object = shell;
if (GTK_IS_MENU_BAR (object))
glade_gtk_menu_shell_launch_editor (object, _("Edit Menu Bar"));
else if (GTK_IS_MENU (object))
glade_gtk_menu_shell_launch_editor (object, _("Edit Menu"));
}
else
GWA_GET_CLASS (GTK_TYPE_CONTAINER)->action_activate (adaptor,
object,
action_path);
if (shell)
gtk_menu_shell_deactivate (GTK_MENU_SHELL (shell));
}
GObject *
glade_gtk_menu_item_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties)
{
GladeWidgetAdaptor *adaptor;
GObject *ret_obj;
ret_obj = GWA_GET_OCLASS(GTK_TYPE_CONTAINER)->constructor
(type, n_construct_properties, construct_properties);
adaptor = GLADE_WIDGET_ADAPTOR (ret_obj);
glade_widget_adaptor_action_remove (adaptor, "add_parent");
glade_widget_adaptor_action_remove (adaptor, "remove_parent");
return ret_obj;
}
void
glade_gtk_menu_item_post_create (GladeWidgetAdaptor *adaptor,
GObject *object,
GladeCreateReason reason)
{
GladeWidget *gitem;
gitem = glade_widget_get_from_gobject (object);
if (GTK_IS_SEPARATOR_MENU_ITEM (object)) return;
if (gtk_bin_get_child (GTK_BIN (object)) == NULL)
{
GtkWidget *label = gtk_label_new ("");
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_container_add (GTK_CONTAINER (object), label);
}
}
GList *
glade_gtk_menu_item_get_children (GladeWidgetAdaptor *adaptor,
GObject *object)
{
GList *list = NULL;
GtkWidget *child;
g_return_val_if_fail (GTK_IS_MENU_ITEM (object), NULL);
if ((child = gtk_menu_item_get_submenu (GTK_MENU_ITEM (object))))
list = g_list_append (list, child);
return list;
}
void
glade_gtk_menu_item_add_child (GladeWidgetAdaptor *adaptor,
GObject *object, GObject *child)
{
g_return_if_fail (GTK_IS_MENU_ITEM (object));
g_return_if_fail (GTK_IS_MENU (child));
if (GTK_IS_SEPARATOR_MENU_ITEM (object))
{
g_warning ("You shouldn't try to add a GtkMenu to a GtkSeparatorMenuItem");
return;
}
g_object_set_data (child,
"special-child-type",
"submenu");
gtk_menu_item_set_submenu (GTK_MENU_ITEM (object), GTK_WIDGET (child));
}
void
glade_gtk_menu_item_remove_child (GladeWidgetAdaptor *adaptor,
GObject *object, GObject *child)
{
g_return_if_fail (GTK_IS_MENU_ITEM (object));
g_return_if_fail (GTK_IS_MENU (child));
gtk_menu_item_set_submenu (GTK_MENU_ITEM (object), NULL);
}
static void
glade_gtk_menu_item_set_label (GObject *object, const GValue *value)
{
GladeWidget *gitem;
GtkWidget *label;
gboolean use_underline;
gitem = glade_widget_get_from_gobject (object);
label = gtk_bin_get_child (GTK_BIN (object));
gtk_label_set_text (GTK_LABEL (label), g_value_get_string (value));
/* Update underline incase... */
glade_widget_property_get (gitem, "use-underline", &use_underline);
gtk_label_set_use_underline (GTK_LABEL (label), use_underline);
}
static void
glade_gtk_menu_item_set_use_underline (GObject *object, const GValue *value)
{
GtkWidget *label;
label = gtk_bin_get_child (GTK_BIN (object));
gtk_label_set_use_underline (GTK_LABEL (label), g_value_get_boolean (value));
}
void
glade_gtk_menu_item_set_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *id,
const GValue *value)
{
GladeWidget *gwidget = glade_widget_get_from_gobject (object);
GladeProperty *property = glade_widget_get_property (gwidget, id);
evaluate_activatable_property_sensitivity (object, id, value);
if (!strcmp (id, "use-underline"))
glade_gtk_menu_item_set_use_underline (object, value);
else if (!strcmp (id, "label"))
glade_gtk_menu_item_set_label (object, value);
else if (GPC_VERSION_CHECK (property->klass, gtk_major_version, gtk_minor_version + 1))
GWA_GET_CLASS (GTK_TYPE_CONTAINER)->set_property (adaptor, object,
id, value);
}
/* ----------------------------- GtkImageMenuItem ------------------------------ */
GList *
glade_gtk_image_menu_item_get_children (GladeWidgetAdaptor *adaptor,
GObject *object)
{
GList *list = NULL;
GtkWidget *child;
GladeWidget *gitem;
gitem = glade_widget_get_from_gobject (object);
if ((child = gtk_menu_item_get_submenu (GTK_MENU_ITEM (object))))
list = g_list_append (list, child);
return list;
}
void
glade_gtk_image_menu_item_add_child (GladeWidgetAdaptor *adaptor,
GObject *object, GObject *child)
{
g_return_if_fail (GTK_IS_MENU_ITEM (object));
if (GTK_IS_IMAGE (child))
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (object), GTK_WIDGET (child));
else
GWA_GET_CLASS (GTK_TYPE_MENU_ITEM)->add (adaptor, object, child);
}
void
glade_gtk_image_menu_item_remove_child (GladeWidgetAdaptor *adaptor,
GObject *object, GObject *child)
{
g_return_if_fail (GTK_IS_MENU_ITEM (object));
if (GTK_IS_IMAGE (child))
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (object), NULL);
else
GWA_GET_CLASS (GTK_TYPE_MENU_ITEM)->remove (adaptor, object, child);
}
static void
glade_gtk_image_menu_item_set_use_stock (GObject *object, const GValue *value)
{
GladeWidget *widget = glade_widget_get_from_gobject (object);
gboolean use_stock;
use_stock = g_value_get_boolean (value);
/* Set some things */
if (use_stock)
{
glade_widget_property_set_sensitive (widget, "stock", TRUE, NULL);
glade_widget_property_set_sensitive (widget, "accel-group", TRUE, NULL);
}
else
{
glade_widget_property_set_sensitive (widget, "stock", FALSE, NOT_SELECTED_MSG);
glade_widget_property_set_sensitive (widget, "accel-group", FALSE, NOT_SELECTED_MSG);
}
gtk_image_menu_item_set_use_stock (GTK_IMAGE_MENU_ITEM (object), use_stock);
sync_use_appearance (widget);
}
static gboolean
glade_gtk_image_menu_item_set_label (GObject *object, const GValue *value)
{
GladeWidget *gitem;
GtkWidget *label;
gboolean use_underline = FALSE, use_stock = FALSE;
const gchar *text;
gitem = glade_widget_get_from_gobject (object);
label = gtk_bin_get_child (GTK_BIN (object));
glade_widget_property_get (gitem, "use-stock", &use_stock);
glade_widget_property_get (gitem, "use-underline", &use_underline);
text = g_value_get_string (value);
/* In "use-stock" mode we dont have a GladeWidget child image */
if (use_stock)
{
GtkWidget *image;
GtkStockItem item;
image = gtk_image_new_from_stock (g_value_get_string (value), GTK_ICON_SIZE_MENU);
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (object), image);
if (use_underline)
gtk_label_set_use_underline (GTK_LABEL (label), TRUE);
/* Get the label string... */
if (text && gtk_stock_lookup (text, &item))
gtk_label_set_label (GTK_LABEL (label), item.label);
else
gtk_label_set_label (GTK_LABEL (label), text ? text : "");
return TRUE;
}
return FALSE;
}
static void
glade_gtk_image_menu_item_set_stock (GObject *object, const GValue *value)
{
GladeWidget *gitem;
gboolean use_stock = FALSE;
gitem = glade_widget_get_from_gobject (object);
glade_widget_property_get (gitem, "use-stock", &use_stock);
/* Forward the work along to the label handler... */
if (use_stock)
glade_gtk_image_menu_item_set_label (object, value);
}
void
glade_gtk_image_menu_item_set_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *id,
const GValue *value)
{
if (!strcmp (id, "stock"))
glade_gtk_image_menu_item_set_stock (object, value);
else if (!strcmp (id, "use-stock"))
glade_gtk_image_menu_item_set_use_stock (object, value);
else if (!strcmp (id, "label"))
{
if (!glade_gtk_image_menu_item_set_label (object, value))
GWA_GET_CLASS (GTK_TYPE_MENU_ITEM)->set_property (adaptor, object,
id, value);
}
else
GWA_GET_CLASS (GTK_TYPE_MENU_ITEM)->set_property (adaptor, object,
id, value);
}
static void
glade_gtk_image_menu_item_parse_finished (GladeProject *project,
GladeWidget *widget)
{
GladeWidget *gimage;
GtkWidget *image = NULL;
glade_widget_property_get (widget, "image", &image);
if (image && (gimage = glade_widget_get_from_gobject (image)))
glade_widget_lock (widget, gimage);
}
void
glade_gtk_image_menu_item_read_widget (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlNode *node)
{
GladeProperty *property;
gboolean use_stock;
gchar *label = NULL;
if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
return;
/* First chain up and read in all the normal properties.. */
GWA_GET_CLASS (GTK_TYPE_MENU_ITEM)->read_widget (adaptor, widget, node);
glade_widget_property_get (widget, "use-stock", &use_stock);
if (use_stock)
{
property = glade_widget_get_property (widget, "label");
glade_property_get (property, &label);
glade_widget_property_set (widget, "use-underline", TRUE);
glade_widget_property_set (widget, "stock", label);
glade_property_sync (property);
}
/* Update sensitivity of related properties... */
property = glade_widget_get_property (widget, "use-stock");
glade_property_sync (property);
/* Run this after the load so that image is resolved. */
g_signal_connect (G_OBJECT (widget->project), "parse-finished",
G_CALLBACK (glade_gtk_image_menu_item_parse_finished),
widget);
}
void
glade_gtk_image_menu_item_write_widget (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlContext *context,
GladeXmlNode *node)
{
GladeProperty *label_prop;
gboolean use_stock;
gchar *stock;
if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
return;
/* Make a copy of the GladeProperty, override its value if use-stock is TRUE */
label_prop = glade_widget_get_property (widget, "label");
label_prop = glade_property_dup (label_prop, widget);
glade_widget_property_get (widget, "use-stock", &use_stock);
if (use_stock)
{
glade_widget_property_get (widget, "stock", &stock);
glade_property_set (label_prop, stock);
glade_property_i18n_set_translatable (label_prop, FALSE);
}
glade_property_write (label_prop, context, node);
g_object_unref (G_OBJECT (label_prop));
/* Chain up and write all the normal properties ... */
GWA_GET_CLASS (GTK_TYPE_MENU_ITEM)->write_widget (adaptor, widget, context, node);
}
/* We need write_widget to write child images as internal, in builder, they are
* attached as a property
*/
GladeEditable *
glade_gtk_image_menu_item_create_editable (GladeWidgetAdaptor *adaptor,
GladeEditorPageType type)
{
GladeEditable *editable;
/* Get base editable */
editable = GWA_GET_CLASS (GTK_TYPE_MENU_ITEM)->create_editable (adaptor, type);
if (type == GLADE_PAGE_GENERAL)
return (GladeEditable *)glade_image_item_editor_new (adaptor, editable);
return editable;
}
/* ----------------------------- GtkRadioMenuItem ------------------------------ */
static void
glade_gtk_radio_menu_item_set_group (GObject *object, const GValue *value)
{
GObject *val;
g_return_if_fail (GTK_IS_RADIO_MENU_ITEM (object));
if ((val = g_value_get_object (value)))
{
GSList *group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (val));
if (! g_slist_find (group, GTK_RADIO_MENU_ITEM (object)))
gtk_radio_menu_item_set_group (GTK_RADIO_MENU_ITEM (object), group);
}
}
void
glade_gtk_radio_menu_item_set_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *id,
const GValue *value)
{
if (!strcmp (id, "group"))
glade_gtk_radio_menu_item_set_group (object, value);
else
GWA_GET_CLASS (GTK_TYPE_MENU_ITEM)->set_property (adaptor, object,
id, value);
}
/* ----------------------------- GtkMenuBar ------------------------------ */
static GladeWidget *
glade_gtk_menu_bar_append_new_submenu (GladeWidget *parent, GladeProject *project)
{
static GladeWidgetAdaptor *submenu_adaptor = NULL;
GladeWidget *gsubmenu;
if (submenu_adaptor == NULL)
submenu_adaptor = glade_widget_adaptor_get_by_type (GTK_TYPE_MENU);
gsubmenu = glade_widget_adaptor_create_widget (submenu_adaptor, FALSE,
"parent", parent,
"project", project,
NULL);
glade_widget_add_child (parent, gsubmenu, FALSE);
return gsubmenu;
}
static GladeWidget *
glade_gtk_menu_bar_append_new_item (GladeWidget *parent,
GladeProject *project,
const gchar *label,
gboolean use_stock)
{
static GladeWidgetAdaptor *item_adaptor = NULL, *image_item_adaptor, *separator_adaptor;
GladeWidget *gitem;
if (item_adaptor == NULL)
{
item_adaptor = glade_widget_adaptor_get_by_type (GTK_TYPE_MENU_ITEM);
image_item_adaptor = glade_widget_adaptor_get_by_type (GTK_TYPE_IMAGE_MENU_ITEM);
separator_adaptor = glade_widget_adaptor_get_by_type (GTK_TYPE_SEPARATOR_MENU_ITEM);
}
if (label)
{
gitem = glade_widget_adaptor_create_widget ((use_stock) ? image_item_adaptor : item_adaptor,
FALSE, "parent", parent,
"project", project,
NULL);
glade_widget_property_set (gitem, "use-underline", TRUE);
if (use_stock)
{
glade_widget_property_set (gitem, "use-stock", TRUE);
glade_widget_property_set (gitem, "stock", label);
}
else
glade_widget_property_set (gitem, "label", label);
}
else
{
gitem = glade_widget_adaptor_create_widget (separator_adaptor,
FALSE, "parent", parent,
"project", project,
NULL);
}
glade_widget_add_child (parent, gitem, FALSE);
return gitem;
}
void
glade_gtk_menu_bar_post_create (GladeWidgetAdaptor *adaptor,
GObject *object,
GladeCreateReason reason)
{
GladeProject *project;
GladeWidget *gmenubar, *gitem, *gsubmenu;
g_return_if_fail (GTK_IS_MENU_BAR (object));
gmenubar = glade_widget_get_from_gobject (object);
g_return_if_fail (GLADE_IS_WIDGET (gmenubar));
if (reason != GLADE_CREATE_USER) return;
project = glade_widget_get_project (gmenubar);
/* File */
gitem = glade_gtk_menu_bar_append_new_item (gmenubar, project, _("_File"), FALSE);
gsubmenu = glade_gtk_menu_bar_append_new_submenu (gitem, project);
glade_gtk_menu_bar_append_new_item (gsubmenu, project, "gtk-new", TRUE);
glade_gtk_menu_bar_append_new_item (gsubmenu, project, "gtk-open", TRUE);
glade_gtk_menu_bar_append_new_item (gsubmenu, project, "gtk-save", TRUE);
glade_gtk_menu_bar_append_new_item (gsubmenu, project, "gtk-save-as", TRUE);
glade_gtk_menu_bar_append_new_item (gsubmenu, project, NULL, FALSE);
glade_gtk_menu_bar_append_new_item (gsubmenu, project, "gtk-quit", TRUE);
/* Edit */
gitem = glade_gtk_menu_bar_append_new_item (gmenubar, project, _("_Edit"), FALSE);
gsubmenu = glade_gtk_menu_bar_append_new_submenu (gitem, project);
glade_gtk_menu_bar_append_new_item (gsubmenu, project, "gtk-cut", TRUE);
glade_gtk_menu_bar_append_new_item (gsubmenu, project, "gtk-copy", TRUE);
glade_gtk_menu_bar_append_new_item (gsubmenu, project, "gtk-paste", TRUE);
glade_gtk_menu_bar_append_new_item (gsubmenu, project, "gtk-delete", TRUE);
/* View */
gitem = glade_gtk_menu_bar_append_new_item (gmenubar, project, _("_View"), FALSE);
/* Help */
gitem = glade_gtk_menu_bar_append_new_item (gmenubar, project, _("_Help"), FALSE);
gsubmenu = glade_gtk_menu_bar_append_new_submenu (gitem, project);
glade_gtk_menu_bar_append_new_item (gsubmenu, project, "gtk-about", TRUE);
}
/* ----------------------------- GtkToolBar ------------------------------ */
/* need to unset/reset toolbar style when property is disabled/enabled */
static void
property_toolbar_style_notify_enabled (GladeProperty *property,
GParamSpec *spec,
GtkToolbar *toolbar)
{
GtkToolbarStyle style;
if (glade_property_get_enabled (property))
{
glade_property_get (property, &style);
gtk_toolbar_set_style (toolbar, style);
}
else
gtk_toolbar_unset_style (toolbar);
}
void
glade_gtk_toolbar_post_create (GladeWidgetAdaptor *adaptor,
GObject *object,
GladeCreateReason reason)
{
GladeWidget *widget;
GladeProperty *toolbar_style_property;
widget = glade_widget_get_from_gobject (object);
toolbar_style_property = glade_widget_get_property (widget, "toolbar-style");
g_signal_connect (toolbar_style_property, "notify::enabled",
G_CALLBACK (property_toolbar_style_notify_enabled),
object);
}
void
glade_gtk_toolbar_get_child_property (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *child,
const gchar *property_name,
GValue *value)
{
g_return_if_fail (GTK_IS_TOOLBAR (container));
if (GTK_IS_TOOL_ITEM (child) == FALSE) return;
if (strcmp (property_name, "position") == 0)
{
g_value_set_int (value,
gtk_toolbar_get_item_index (GTK_TOOLBAR (container),
GTK_TOOL_ITEM (child)));
}
else
{ /* Chain Up */
GWA_GET_CLASS
(GTK_TYPE_CONTAINER)->child_get_property (adaptor,
container, child,
property_name, value);
}
}
void
glade_gtk_toolbar_set_child_property (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *child,
const gchar *property_name,
GValue *value)
{
g_return_if_fail (GTK_IS_TOOLBAR (container));
g_return_if_fail (GTK_IS_TOOL_ITEM (child));
g_return_if_fail (property_name != NULL || value != NULL);
if (strcmp (property_name, "position") == 0)
{
GtkToolbar *toolbar = GTK_TOOLBAR (container);
gint position, size;
position = g_value_get_int (value);
size = gtk_toolbar_get_n_items (toolbar);
if (position >= size) position = size - 1;
g_object_ref (child);
gtk_container_remove (GTK_CONTAINER (container), GTK_WIDGET (child));
gtk_toolbar_insert (toolbar, GTK_TOOL_ITEM (child), position);
g_object_unref (child);
}
else
/* Chain Up */
GWA_GET_CLASS
(GTK_TYPE_CONTAINER)->child_set_property (adaptor,
container, child,
property_name, value);
}
void
glade_gtk_toolbar_add_child (GladeWidgetAdaptor *adaptor,
GObject *object, GObject *child)
{
GtkToolbar *toolbar;
GtkToolItem *item;
g_return_if_fail (GTK_IS_TOOLBAR (object));
g_return_if_fail (GTK_IS_TOOL_ITEM (child));
toolbar = GTK_TOOLBAR (object);
item = GTK_TOOL_ITEM (child);
gtk_toolbar_insert (toolbar, item, -1);
if (glade_util_object_is_loading (object))
{
GladeWidget *gchild = glade_widget_get_from_gobject (child);
/* Packing props arent around when parenting during a glade_widget_dup() */
if (gchild && gchild->packing_properties)
glade_widget_pack_property_set (gchild, "position",
gtk_toolbar_get_item_index (toolbar, item));
}
}
void
glade_gtk_toolbar_remove_child (GladeWidgetAdaptor *adaptor,
GObject *object, GObject *child)
{
gtk_container_remove (GTK_CONTAINER (object), GTK_WIDGET (child));
}
static void
glade_gtk_toolbar_launch_editor (GladeWidgetAdaptor *adaptor,
GObject *toolbar)
{
GladeBaseEditor *editor;
GtkWidget *window;
/* Editor */
editor = glade_base_editor_new (toolbar, NULL,
_("Button"), GTK_TYPE_TOOL_BUTTON,
_("Toggle"), GTK_TYPE_TOGGLE_TOOL_BUTTON,
_("Radio"), GTK_TYPE_RADIO_TOOL_BUTTON,
_("Menu"), GTK_TYPE_MENU_TOOL_BUTTON,
_("Custom"), GTK_TYPE_TOOL_ITEM,
_("Separator"), GTK_TYPE_SEPARATOR_TOOL_ITEM,
NULL);
glade_base_editor_append_types (editor, GTK_TYPE_MENU_TOOL_BUTTON,
_("Normal"), GTK_TYPE_MENU_ITEM,
_("Image"), GTK_TYPE_IMAGE_MENU_ITEM,
_("Check"), GTK_TYPE_CHECK_MENU_ITEM,
_("Radio"), GTK_TYPE_RADIO_MENU_ITEM,
_("Separator"), GTK_TYPE_SEPARATOR_MENU_ITEM,
NULL);
glade_base_editor_append_types (editor, GTK_TYPE_MENU_ITEM,
_("Normal"), GTK_TYPE_MENU_ITEM,
_("Image"), GTK_TYPE_IMAGE_MENU_ITEM,
_("Check"), GTK_TYPE_CHECK_MENU_ITEM,
_("Radio"), GTK_TYPE_RADIO_MENU_ITEM,
_("Separator"), GTK_TYPE_SEPARATOR_MENU_ITEM,
NULL);
g_signal_connect (editor, "get-display-name", G_CALLBACK (glade_gtk_menu_shell_tool_item_get_display_name), NULL);
g_signal_connect (editor, "child-selected", G_CALLBACK (glade_gtk_menu_shell_tool_item_child_selected), NULL);
g_signal_connect (editor, "change-type", G_CALLBACK (glade_gtk_menu_shell_change_type), NULL);
g_signal_connect (editor, "build-child", G_CALLBACK (glade_gtk_menu_shell_build_child), NULL);
g_signal_connect (editor, "delete-child", G_CALLBACK (glade_gtk_menu_shell_delete_child), NULL);
g_signal_connect (editor, "move-child", G_CALLBACK (glade_gtk_menu_shell_move_child), NULL);
gtk_widget_show (GTK_WIDGET (editor));
window = glade_base_editor_pack_new_window (editor, _("Tool Bar Editor"), NULL);
gtk_widget_show (window);
}
void
glade_gtk_toolbar_action_activate (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *action_path)
{
if (strcmp (action_path, "launch_editor") == 0)
{
glade_gtk_toolbar_launch_editor (adaptor, object);
}
else
GWA_GET_CLASS (GTK_TYPE_CONTAINER)->action_activate (adaptor,
object,
action_path);
}
/* ----------------------------- GtkToolItem ------------------------------ */
GObject *
glade_gtk_tool_item_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties)
{
GladeWidgetAdaptor *adaptor;
GObject *ret_obj;
ret_obj = GWA_GET_OCLASS(GTK_TYPE_CONTAINER)->constructor
(type, n_construct_properties, construct_properties);
adaptor = GLADE_WIDGET_ADAPTOR (ret_obj);
glade_widget_adaptor_action_remove (adaptor, "add_parent");
glade_widget_adaptor_action_remove (adaptor, "remove_parent");
return ret_obj;
}
void
glade_gtk_tool_item_post_create (GladeWidgetAdaptor *adaptor,
GObject *object,
GladeCreateReason reason)
{
g_return_if_fail (GTK_IS_TOOL_ITEM (object));
if (GTK_IS_SEPARATOR_TOOL_ITEM (object)) return;
if (reason == GLADE_CREATE_USER &&
gtk_bin_get_child (GTK_BIN (object)) == NULL)
gtk_container_add (GTK_CONTAINER (object),
glade_placeholder_new ());
}
void
glade_gtk_tool_item_set_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *id,
const GValue *value)
{
GladeWidget *gwidget = glade_widget_get_from_gobject (object);
GladeProperty *property = glade_widget_get_property (gwidget, id);
//evaluate_activatable_property_sensitivity (object, id, value);
if (GPC_VERSION_CHECK (property->klass, gtk_major_version, gtk_minor_version + 1))
GWA_GET_CLASS (GTK_TYPE_CONTAINER)->set_property (adaptor,
object,
id, value);
}
/* ----------------------------- GtkToolButton ------------------------------ */
GladeEditable *
glade_gtk_tool_button_create_editable (GladeWidgetAdaptor *adaptor,
GladeEditorPageType type)
{
GladeEditable *editable;
/* Get base editable */
editable = GWA_GET_CLASS (GTK_TYPE_TOOL_ITEM)->create_editable (adaptor, type);
if (type == GLADE_PAGE_GENERAL)
return (GladeEditable *)glade_tool_button_editor_new (adaptor, editable);
return editable;
}
static void
glade_gtk_tool_button_set_image_mode (GObject *object, const GValue *value)
{
GladeWidget *gbutton;
g_return_if_fail (GTK_IS_TOOL_BUTTON (object));
gbutton = glade_widget_get_from_gobject (object);
glade_widget_property_set_sensitive (gbutton, "stock-id", FALSE, NOT_SELECTED_MSG);
glade_widget_property_set_sensitive (gbutton, "icon-name", FALSE, NOT_SELECTED_MSG);
glade_widget_property_set_sensitive (gbutton, "icon-widget", FALSE, NOT_SELECTED_MSG);
switch (g_value_get_int (value))
{
case GLADE_TB_MODE_STOCK:
glade_widget_property_set_sensitive (gbutton, "stock-id", TRUE, NULL);
break;
case GLADE_TB_MODE_ICON:
glade_widget_property_set_sensitive (gbutton, "icon-name", TRUE, NULL);
break;
case GLADE_TB_MODE_CUSTOM:
glade_widget_property_set_sensitive (gbutton, "icon-widget", TRUE, NULL);
break;
default:
break;
}
}
static void
glade_gtk_tool_button_set_custom_label (GObject *object, const GValue *value)
{
GladeWidget *gbutton;
g_return_if_fail (GTK_IS_TOOL_BUTTON (object));
gbutton = glade_widget_get_from_gobject (object);
glade_widget_property_set_sensitive (gbutton, "label", FALSE, NOT_SELECTED_MSG);
glade_widget_property_set_sensitive (gbutton, "label-widget", FALSE, NOT_SELECTED_MSG);
if (g_value_get_boolean (value))
glade_widget_property_set_sensitive (gbutton, "label-widget", TRUE, NULL);
else
glade_widget_property_set_sensitive (gbutton, "label", TRUE, NULL);
}
static void
glade_gtk_tool_button_set_label (GObject *object, const GValue *value)
{
const gchar *label;
g_return_if_fail (GTK_IS_TOOL_BUTTON (object));
label = g_value_get_string (value);
if (label && strlen (label) == 0) label = NULL;
gtk_tool_button_set_label (GTK_TOOL_BUTTON (object), label);
}
static void
glade_gtk_tool_button_set_stock_id (GObject *object, const GValue *value)
{
const gchar *stock_id;
g_return_if_fail (GTK_IS_TOOL_BUTTON (object));
stock_id = g_value_get_string (value);
if (stock_id && strlen (stock_id) == 0) stock_id = NULL;
gtk_tool_button_set_stock_id (GTK_TOOL_BUTTON (object), stock_id);
}
static void
glade_gtk_tool_button_set_icon_name (GObject *object, const GValue *value)
{
const gchar *name;
g_return_if_fail (GTK_IS_TOOL_BUTTON (object));
name = g_value_get_string (value);
if (name && strlen (name) == 0) name = NULL;
gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (object), name);
}
void
glade_gtk_tool_button_set_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *id,
const GValue *value)
{
if (!strcmp (id, "image-mode"))
glade_gtk_tool_button_set_image_mode (object, value);
else if (!strcmp (id, "icon-name"))
glade_gtk_tool_button_set_icon_name (object, value);
else if (!strcmp (id, "stock-id"))
glade_gtk_tool_button_set_stock_id (object, value);
else if (!strcmp (id, "label"))
glade_gtk_tool_button_set_label (object, value);
else if (!strcmp (id, "custom-label"))
glade_gtk_tool_button_set_custom_label (object, value);
else
GWA_GET_CLASS (GTK_TYPE_TOOL_ITEM)->set_property (adaptor,
object,
id, value);
}
static void
glade_gtk_tool_button_parse_finished (GladeProject *project,
GladeWidget *widget)
{
gchar *stock_str = NULL, *icon_name = NULL;
gint stock_id = 0;
GtkWidget *label_widget = NULL, *image_widget = NULL;
glade_widget_property_get (widget, "stock-id", &stock_str);
glade_widget_property_get (widget, "icon-name", &icon_name);
glade_widget_property_get (widget, "icon-widget", &image_widget);
glade_widget_property_get (widget, "label-widget", &label_widget);
if (label_widget)
glade_widget_property_set (widget, "custom-label", TRUE);
else
glade_widget_property_set (widget, "custom-label", FALSE);
if (image_widget)
glade_widget_property_set (widget, "image-mode", GLADE_TB_MODE_CUSTOM);
else if (icon_name)
glade_widget_property_set (widget, "image-mode", GLADE_TB_MODE_ICON);
else if (stock_str)
{
/* Update the stock property */
stock_id = glade_utils_enum_value_from_string (GLADE_TYPE_STOCK_IMAGE, stock_str);
if (stock_id < 0)
stock_id = 0;
glade_widget_property_set (widget, "glade-stock", stock_id);
glade_widget_property_set (widget, "image-mode", GLADE_TB_MODE_STOCK);
}
else
glade_widget_property_set (widget, "image-mode", GLADE_TB_MODE_STOCK);
}
void
glade_gtk_tool_button_read_widget (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlNode *node)
{
if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
return;
/* First chain up and read in all the normal properties.. */
GWA_GET_CLASS (GTK_TYPE_TOOL_ITEM)->read_widget (adaptor, widget, node);
/* Run this after the load so that icon-widget is resolved. */
g_signal_connect (glade_widget_get_project (widget),
"parse-finished",
G_CALLBACK (glade_gtk_tool_button_parse_finished),
widget);
}
/* ----------------------------- GtkMenuToolButton ------------------------------ */
GList *
glade_gtk_menu_tool_button_get_children (GladeWidgetAdaptor *adaptor, GtkMenuToolButton *button)
{
GList *list = NULL;
GtkWidget *menu = gtk_menu_tool_button_get_menu (button);
list = glade_util_container_get_all_children (GTK_CONTAINER (button));
/* Ensure that we only return one 'menu' */
if (menu && g_list_find (list, menu) == NULL)
list = g_list_append (list, menu);
return list;
}
void
glade_gtk_menu_tool_button_add_child (GladeWidgetAdaptor *adaptor,
GObject *object,
GObject *child)
{
if (GTK_IS_MENU (child))
{
gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (object), GTK_WIDGET (child));
}
else
GWA_GET_CLASS (GTK_TYPE_TOOL_BUTTON)->add (adaptor, object, child);
}
void
glade_gtk_menu_tool_button_remove_child (GladeWidgetAdaptor *adaptor,
GObject *object,
GObject *child)
{
if (GTK_IS_MENU (child))
{
gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (object), NULL);
}
else
GWA_GET_CLASS (GTK_TYPE_TOOL_BUTTON)->remove (adaptor, object, child);
}
/* ----------------------------- GtkLabel ------------------------------ */
void
glade_gtk_label_post_create (GladeWidgetAdaptor *adaptor,
GObject *object,
GladeCreateReason reason)
{
GladeWidget *glabel = glade_widget_get_from_gobject (object);
if (reason == GLADE_CREATE_USER)
glade_widget_property_set_sensitive (glabel, "mnemonic-widget", FALSE, MNEMONIC_INSENSITIVE_MSG);
}
static void
glade_gtk_label_set_label (GObject *object, const GValue *value)
{
GladeWidget *glabel;
gboolean use_markup = FALSE, use_underline = FALSE;
glabel = glade_widget_get_from_gobject (object);
glade_widget_property_get (glabel, "use-markup", &use_markup);
if (use_markup)
gtk_label_set_markup (GTK_LABEL (object), g_value_get_string (value));
else
gtk_label_set_text (GTK_LABEL (object), g_value_get_string (value));
glade_widget_property_get (glabel, "use-underline", &use_underline);
if (use_underline)
gtk_label_set_use_underline (GTK_LABEL (object), use_underline);
}
static void
glade_gtk_label_set_attributes (GObject *object, const GValue *value)
{
GladeAttribute *gattr;
PangoAttribute *attribute;
PangoLanguage *language;
PangoAttrList *attrs = NULL;
GdkColor *color;
GList *list;
for (list = g_value_get_boxed (value); list; list = list->next)
{
gattr = list->data;
attribute = NULL;
switch (gattr->type)
{
/* PangoAttrLanguage */
case PANGO_ATTR_LANGUAGE:
if ((language = pango_language_from_string (g_value_get_string (&gattr->value))))
attribute = pango_attr_language_new (language);
break;
/* PangoAttrInt */
case PANGO_ATTR_STYLE:
attribute = pango_attr_style_new (g_value_get_enum (&(gattr->value)));
break;
case PANGO_ATTR_WEIGHT:
attribute = pango_attr_weight_new (g_value_get_enum (&(gattr->value)));
break;
case PANGO_ATTR_VARIANT:
attribute = pango_attr_variant_new (g_value_get_enum (&(gattr->value)));
break;
case PANGO_ATTR_STRETCH:
attribute = pango_attr_stretch_new (g_value_get_enum (&(gattr->value)));
break;
case PANGO_ATTR_UNDERLINE:
attribute = pango_attr_underline_new (g_value_get_boolean (&(gattr->value)));
break;
case PANGO_ATTR_STRIKETHROUGH:
attribute = pango_attr_strikethrough_new (g_value_get_boolean (&(gattr->value)));
break;
case PANGO_ATTR_GRAVITY:
attribute = pango_attr_gravity_new (g_value_get_enum (&(gattr->value)));
break;
case PANGO_ATTR_GRAVITY_HINT:
attribute = pango_attr_gravity_hint_new (g_value_get_enum (&(gattr->value)));
break;
/* PangoAttrString */
case PANGO_ATTR_FAMILY:
attribute = pango_attr_family_new (g_value_get_string (&(gattr->value)));
break;
/* PangoAttrSize */
case PANGO_ATTR_SIZE:
attribute = pango_attr_size_new (g_value_get_int (&(gattr->value)));
break;
case PANGO_ATTR_ABSOLUTE_SIZE:
attribute = pango_attr_size_new_absolute (g_value_get_int (&(gattr->value)));
break;
/* PangoAttrColor */
case PANGO_ATTR_FOREGROUND:
color = g_value_get_boxed (&(gattr->value));
attribute = pango_attr_foreground_new (color->red, color->green, color->blue);
break;
case PANGO_ATTR_BACKGROUND:
color = g_value_get_boxed (&(gattr->value));
attribute = pango_attr_background_new (color->red, color->green, color->blue);
break;
case PANGO_ATTR_UNDERLINE_COLOR:
color = g_value_get_boxed (&(gattr->value));
attribute = pango_attr_underline_color_new (color->red, color->green, color->blue);
break;
case PANGO_ATTR_STRIKETHROUGH_COLOR:
color = g_value_get_boxed (&(gattr->value));
attribute = pango_attr_strikethrough_color_new (color->red, color->green, color->blue);
break;
/* PangoAttrShape */
case PANGO_ATTR_SHAPE:
/* Unsupported for now */
break;
/* PangoAttrFloat */
case PANGO_ATTR_SCALE:
attribute = pango_attr_scale_new (g_value_get_double (&(gattr->value)));
break;
case PANGO_ATTR_INVALID:
case PANGO_ATTR_LETTER_SPACING:
case PANGO_ATTR_RISE:
case PANGO_ATTR_FALLBACK:
case PANGO_ATTR_FONT_DESC:
default:
break;
}
if (attribute)
{
if (!attrs)
attrs = pango_attr_list_new ();
pango_attr_list_insert (attrs, attribute);
}
}
gtk_label_set_attributes (GTK_LABEL (object), attrs);
}
static void
glade_gtk_label_set_content_mode (GObject *object, const GValue *value)
{
GladeLabelContentMode mode = g_value_get_int (value);
GladeWidget *glabel;
glabel = glade_widget_get_from_gobject (object);
glade_widget_property_set_sensitive (glabel, "glade-attributes", FALSE, NOT_SELECTED_MSG);
glade_widget_property_set_sensitive (glabel, "use-markup", FALSE, NOT_SELECTED_MSG);
glade_widget_property_set_sensitive (glabel, "pattern", FALSE, NOT_SELECTED_MSG);
switch (mode)
{
case GLADE_LABEL_MODE_ATTRIBUTES:
glade_widget_property_set_sensitive (glabel, "glade-attributes", TRUE, NULL);
break;
case GLADE_LABEL_MODE_MARKUP:
glade_widget_property_set_sensitive (glabel, "use-markup", TRUE, NULL);
break;
case GLADE_LABEL_MODE_PATTERN:
glade_widget_property_set_sensitive (glabel, "pattern", TRUE, NULL);
break;
default:
break;
}
}
static void
glade_gtk_label_set_use_max_width (GObject *object, const GValue *value)
{
GladeWidget *glabel;
glabel = glade_widget_get_from_gobject (object);
glade_widget_property_set_sensitive (glabel, "width-chars", FALSE, NOT_SELECTED_MSG);
glade_widget_property_set_sensitive (glabel, "max-width-chars", FALSE, NOT_SELECTED_MSG);
if (g_value_get_boolean (value))
glade_widget_property_set_sensitive (glabel, "max-width-chars", TRUE, NULL);
else
glade_widget_property_set_sensitive (glabel, "width-chars", TRUE, NULL);
}
static void
glade_gtk_label_set_wrap_mode (GObject *object, const GValue *value)
{
GladeLabelWrapMode mode = g_value_get_int (value);
GladeWidget *glabel;
glabel = glade_widget_get_from_gobject (object);
glade_widget_property_set_sensitive (glabel, "single-line-mode", FALSE, NOT_SELECTED_MSG);
glade_widget_property_set_sensitive (glabel, "wrap-mode", FALSE, NOT_SELECTED_MSG);
if (mode == GLADE_LABEL_SINGLE_LINE)
glade_widget_property_set_sensitive (glabel, "single-line-mode", TRUE, NULL);
else if (mode == GLADE_LABEL_WRAP_MODE)
glade_widget_property_set_sensitive (glabel, "wrap-mode", TRUE, NULL);
}
static void
glade_gtk_label_set_use_underline (GObject *object, const GValue *value)
{
GladeWidget *glabel;
glabel = glade_widget_get_from_gobject (object);
if (g_value_get_boolean (value))
glade_widget_property_set_sensitive (glabel, "mnemonic-widget", TRUE, NULL);
else
glade_widget_property_set_sensitive (glabel, "mnemonic-widget", FALSE, MNEMONIC_INSENSITIVE_MSG);
gtk_label_set_use_underline (GTK_LABEL (object), g_value_get_boolean (value));
}
static void
glade_gtk_label_set_ellipsize (GObject *object, const GValue *value)
{
GladeWidget *glabel;
const gchar *insensitive_msg = _("This property does not apply when Ellipsize is set.");
glabel = glade_widget_get_from_gobject (object);
if (!glade_widget_property_original_default (glabel, "ellipsize"))
glade_widget_property_set_sensitive (glabel, "angle", FALSE, insensitive_msg);
else
glade_widget_property_set_sensitive (glabel, "angle", TRUE, NULL);
gtk_label_set_ellipsize (GTK_LABEL (object), g_value_get_enum (value));
}
static void
glade_gtk_label_set_angle (GObject *object, const GValue *value)
{
GladeWidget *glabel;
const gchar *insensitive_msg = _("This property does not apply when Angle is set.");
glabel = glade_widget_get_from_gobject (object);
if (!glade_widget_property_original_default (glabel, "angle"))
glade_widget_property_set_sensitive (glabel, "ellipsize", FALSE, insensitive_msg);
else
glade_widget_property_set_sensitive (glabel, "ellipsize", TRUE, NULL);
gtk_label_set_angle (GTK_LABEL (object), g_value_get_double (value));
}
void
glade_gtk_label_set_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *id,
const GValue *value)
{
if (!strcmp (id, "label"))
glade_gtk_label_set_label (object, value);
else if (!strcmp (id, "glade-attributes"))
glade_gtk_label_set_attributes (object, value);
else if (!strcmp (id, "label-content-mode"))
glade_gtk_label_set_content_mode (object, value);
else if (!strcmp (id, "use-max-width"))
glade_gtk_label_set_use_max_width (object, value);
else if (!strcmp (id, "label-wrap-mode"))
glade_gtk_label_set_wrap_mode (object, value);
else if (!strcmp (id, "use-underline"))
glade_gtk_label_set_use_underline (object, value);
else if (!strcmp (id, "ellipsize"))
glade_gtk_label_set_ellipsize (object, value);
else if (!strcmp (id, "angle"))
glade_gtk_label_set_angle (object, value);
else
GWA_GET_CLASS (GTK_TYPE_WIDGET)->set_property (adaptor, object, id, value);
}
static void
glade_gtk_parse_attributes (GladeWidget *widget,
GladeXmlNode *node)
{
PangoAttrType attr_type;
GladeXmlNode *prop;
GladeAttribute *attr;
GList *attrs = NULL;
gchar *name, *value;
for (prop = glade_xml_node_get_children (node);
prop; prop = glade_xml_node_next (prop))
{
if (!glade_xml_node_verify (prop, GLADE_TAG_ATTRIBUTE))
continue;
if (!(name = glade_xml_get_property_string_required
(prop, GLADE_XML_TAG_NAME, NULL)))
continue;
if (!(value = glade_xml_get_property_string_required
(prop, GLADE_TAG_VALUE, NULL)))
{
/* for a while, Glade was broken and was storing
* attributes in the node contents */
if (!(value = glade_xml_get_content (prop)))
{
g_free (name);
continue;
}
}
if ((attr_type =
glade_utils_enum_value_from_string (PANGO_TYPE_ATTR_TYPE, name)) == 0)
continue;
/* Parse attribute and add to list */
if ((attr = glade_gtk_attribute_from_string (attr_type, value)) != NULL)
attrs = g_list_prepend (attrs, attr);
/* XXX deal with start/end here ... */
g_free (name);
g_free (value);
}
glade_widget_property_set (widget, "glade-attributes", g_list_reverse (attrs));
glade_attr_list_free (attrs);
}
static void
glade_gtk_label_read_attributes (GladeWidget *widget,
GladeXmlNode *node)
{
GladeXmlNode *attrs_node;
if ((attrs_node =
glade_xml_search_child (node, GLADE_TAG_ATTRIBUTES)) != NULL)
{
/* Generic attributes parsing */
glade_gtk_parse_attributes (widget, attrs_node);
}
}
void
glade_gtk_label_read_widget (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlNode *node)
{
GladeProperty *prop;
if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
return;
/* First chain up and read in all the normal properties.. */
GWA_GET_CLASS (GTK_TYPE_WIDGET)->read_widget (adaptor, widget, node);
glade_gtk_label_read_attributes (widget, node);
/* sync label property after a load... */
prop = glade_widget_get_property (widget, "label");
glade_gtk_label_set_label (widget->object, prop->value);
/* Resolve "label-content-mode" virtual control property */
if (!glade_widget_property_original_default (widget, "use-markup"))
glade_widget_property_set (widget, "label-content-mode", GLADE_LABEL_MODE_MARKUP);
else if (!glade_widget_property_original_default (widget, "pattern"))
glade_widget_property_set (widget, "label-content-mode", GLADE_LABEL_MODE_PATTERN);
else
glade_widget_property_set (widget, "label-content-mode", GLADE_LABEL_MODE_ATTRIBUTES);
/* Resolve "label-wrap-mode" virtual control property */
if (!glade_widget_property_original_default (widget, "single-line-mode"))
glade_widget_property_set (widget, "label-wrap-mode", GLADE_LABEL_SINGLE_LINE);
else if (!glade_widget_property_original_default (widget, "wrap"))
glade_widget_property_set (widget, "label-wrap-mode", GLADE_LABEL_WRAP_MODE);
else
glade_widget_property_set (widget, "label-wrap-mode", GLADE_LABEL_WRAP_FREE);
/* Resolve "use-max-width" virtual control property */
if (!glade_widget_property_original_default (widget, "max-width-chars"))
glade_widget_property_set (widget, "use-max-width", TRUE);
else
glade_widget_property_set (widget, "use-max-width", TRUE);
if (glade_widget_property_original_default (widget, "use-markup"))
glade_widget_property_set_sensitive (widget, "mnemonic-widget",
FALSE, MNEMONIC_INSENSITIVE_MSG);
}
static void
glade_gtk_label_write_attributes (GladeWidget *widget,
GladeXmlContext *context,
GladeXmlNode *node)
{
GladeXmlNode *attr_node;
GList *attrs = NULL, *l;
GladeAttribute *gattr;
gchar *attr_type;
gchar *attr_value;
if (!glade_widget_property_get (widget, "glade-attributes", &attrs) || !attrs)
return;
for (l = attrs; l; l = l->next)
{
gattr = l->data;
attr_type = glade_utils_enum_string_from_value (PANGO_TYPE_ATTR_TYPE, gattr->type);
attr_value = glade_gtk_string_from_attr (gattr);
attr_node = glade_xml_node_new (context, GLADE_TAG_ATTRIBUTE);
glade_xml_node_append_child (node, attr_node);
glade_xml_node_set_property_string (attr_node, GLADE_TAG_NAME, attr_type);
glade_xml_node_set_property_string (attr_node, GLADE_TAG_VALUE, attr_value);
}
}
void
glade_gtk_label_write_widget (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlContext *context,
GladeXmlNode *node)
{
GladeXmlNode *attrs_node;
if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
return;
/* First chain up and read in all the normal properties.. */
GWA_GET_CLASS (GTK_TYPE_WIDGET)->write_widget (adaptor, widget, context, node);
attrs_node = glade_xml_node_new (context, GLADE_TAG_ATTRIBUTES);
glade_gtk_label_write_attributes (widget, context, attrs_node);
if (!glade_xml_node_get_children (attrs_node))
glade_xml_node_delete (attrs_node);
else
glade_xml_node_append_child (node, attrs_node);
}
gchar *
glade_gtk_label_string_from_value (GladeWidgetAdaptor *adaptor,
GladePropertyClass *klass,
const GValue *value)
{
if (klass->pspec->value_type == GLADE_TYPE_ATTR_GLIST)
{
GList *l, *list = g_value_get_boxed (value);
GString *string = g_string_new ("");
gchar *str;
for (l = list; l; l = g_list_next (l))
{
GladeAttribute *attr = l->data;
/* Return something usefull at least to for the backend to compare */
gchar *attr_str = glade_gtk_string_from_attr (attr);
g_string_append_printf (string, "%d=%s ", attr->type, attr_str);
g_free (attr_str);
}
str = string->str;
g_string_free (string, FALSE);
return str;
}
else
return GWA_GET_CLASS
(GTK_TYPE_WIDGET)->string_from_value (adaptor,
klass,
value);
}
GladeEditorProperty *
glade_gtk_label_create_eprop (GladeWidgetAdaptor *adaptor,
GladePropertyClass *klass,
gboolean use_command)
{
GladeEditorProperty *eprop;
/* chain up.. */
if (klass->pspec->value_type == GLADE_TYPE_ATTR_GLIST)
{
eprop = g_object_new (GLADE_TYPE_EPROP_ATTRS,
"property-class", klass,
"use-command", use_command,
NULL);
}
else
eprop = GWA_GET_CLASS
(GTK_TYPE_WIDGET)->create_eprop (adaptor,
klass,
use_command);
return eprop;
}
GladeEditable *
glade_gtk_label_create_editable (GladeWidgetAdaptor *adaptor,
GladeEditorPageType type)
{
GladeEditable *editable;
/* Get base editable */
editable = GWA_GET_CLASS (GTK_TYPE_WIDGET)->create_editable (adaptor, type);
if (type == GLADE_PAGE_GENERAL)
return (GladeEditable *)glade_label_editor_new (adaptor, editable);
return editable;
}
/* ----------------------------- GtkTextBuffer ------------------------------ */
static void
glade_gtk_entry_buffer_changed (GtkTextBuffer *buffer,
GParamSpec *pspec,
GladeWidget *gbuffy)
{
const gchar *text_prop = NULL;
GladeProperty *prop;
gchar *text = NULL;
if (glade_widget_superuser ())
return;
g_object_get (buffer, "text", &text, NULL);
if ((prop = glade_widget_get_property (gbuffy, "text")))
{
glade_property_get (prop, &text_prop);
if (text_prop == NULL || g_strcmp0 (text, text_prop))
glade_command_set_property (prop, text);
}
g_free (text);
}
void
glade_gtk_entry_buffer_post_create (GladeWidgetAdaptor *adaptor,
GObject *object,
GladeCreateReason reason)
{
GladeWidget *gbuffy;
gbuffy = glade_widget_get_from_gobject (object);
g_signal_connect (object, "notify::text",
G_CALLBACK (glade_gtk_entry_buffer_changed),
gbuffy);
}
void
glade_gtk_entry_buffer_set_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *id,
const GValue *value)
{
GladeWidget *gwidget = glade_widget_get_from_gobject (object);
GladeProperty *property = glade_widget_get_property (gwidget, id);
if (!strcmp (id, "text"))
{
g_signal_handlers_block_by_func (object, glade_gtk_entry_buffer_changed, gwidget);
if (g_value_get_string (value))
gtk_entry_buffer_set_text (GTK_ENTRY_BUFFER (object), g_value_get_string (value), -1);
else
gtk_entry_buffer_set_text (GTK_ENTRY_BUFFER (object), "", -1);
g_signal_handlers_unblock_by_func (object, glade_gtk_entry_buffer_changed, gwidget);
}
else if (GPC_VERSION_CHECK (property->klass, gtk_major_version, gtk_minor_version + 1))
GWA_GET_CLASS (G_TYPE_OBJECT)->set_property (adaptor, object, id, value);
}
/* ----------------------------- GtkTextBuffer ------------------------------ */
static void
glade_gtk_text_buffer_changed (GtkTextBuffer *buffer, GladeWidget *gbuffy)
{
const gchar *text_prop = NULL;
GladeProperty *prop;
gchar *text = NULL;
g_object_get (buffer, "text", &text, NULL);
if ((prop = glade_widget_get_property (gbuffy, "text")))
{
glade_property_get (prop, &text_prop);
if (g_strcmp0 (text, text_prop))
glade_command_set_property (prop, text);
}
g_free (text);
}
void
glade_gtk_text_buffer_post_create (GladeWidgetAdaptor *adaptor,
GObject *object,
GladeCreateReason reason)
{
GladeWidget *gbuffy;
gbuffy = glade_widget_get_from_gobject (object);
g_signal_connect (object, "changed",
G_CALLBACK (glade_gtk_text_buffer_changed),
gbuffy);
}
void
glade_gtk_text_buffer_set_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *id,
const GValue *value)
{
GladeWidget *gwidget = glade_widget_get_from_gobject (object);
GladeProperty *property = glade_widget_get_property (gwidget, id);
if (!strcmp (id, "text"))
{
g_signal_handlers_block_by_func (object, glade_gtk_text_buffer_changed, gwidget);
if (g_value_get_string (value))
gtk_text_buffer_set_text (GTK_TEXT_BUFFER (object), g_value_get_string (value), -1);
else
gtk_text_buffer_set_text (GTK_TEXT_BUFFER (object), "", -1);
g_signal_handlers_unblock_by_func (object, glade_gtk_text_buffer_changed, gwidget);
}
else if (GPC_VERSION_CHECK (property->klass, gtk_major_version, gtk_minor_version + 1))
GWA_GET_CLASS (G_TYPE_OBJECT)->set_property (adaptor, object, id, value);
}
/* ----------------------------- GtkTextView ------------------------------ */
static gboolean
glade_gtk_text_view_stop_double_click (GtkWidget *widget,
GdkEventButton *event,
gpointer user_data)
{
/* Return True if the event is double or triple click */
return (event->type == GDK_2BUTTON_PRESS ||
event->type == GDK_3BUTTON_PRESS);
}
void
glade_gtk_text_view_post_create (GladeWidgetAdaptor *adaptor,
GObject *object,
GladeCreateReason reason)
{
GladeWidget *gtext;
gtext = glade_widget_get_from_gobject (object);
/* This makes gtk_text_view_set_buffer() stop complaing */
gtk_drag_dest_set (GTK_WIDGET (object), 0, NULL, 0, 0);
/* Glade hangs when a TextView gets a double click. So we stop them */
g_signal_connect (object, "button-press-event",
G_CALLBACK (glade_gtk_text_view_stop_double_click),
NULL);
}
void
glade_gtk_text_view_set_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *property_name,
const GValue *value)
{
if (strcmp (property_name, "buffer") == 0)
{
if (!g_value_get_object (value))
return;
}
GWA_GET_CLASS (GTK_TYPE_CONTAINER)->set_property (adaptor,
object,
property_name,
value);
}
/* ----------------------------- GtkComboBox ------------------------------ */
void
glade_gtk_combo_box_post_create (GladeWidgetAdaptor *adaptor,
GObject *object,
GladeCreateReason reason)
{
GladeWidget *widget = glade_widget_get_from_gobject (object);
if (gtk_combo_box_get_has_entry (GTK_COMBO_BOX (object)))
glade_widget_adaptor_create_internal
(widget, G_OBJECT (gtk_bin_get_child (GTK_BIN (object))),
"entry", "comboboxentry", FALSE, reason);
}
void
glade_gtk_combo_box_set_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *id,
const GValue *value)
{
if (!strcmp (id, "entry-text-column"))
{
/* Avoid warnings */
if (g_value_get_int (value) >= 0)
GWA_GET_CLASS (GTK_TYPE_CONTAINER)->set_property (adaptor,
object,
id, value);
}
else if (!strcmp (id, "text-column"))
{
if (g_value_get_int (value) >= 0)
gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (object),
g_value_get_int (value));
}
else
GWA_GET_CLASS (GTK_TYPE_CONTAINER)->set_property (adaptor,
object,
id, value);
}
GList *glade_gtk_cell_layout_get_children (GladeWidgetAdaptor *adaptor, GObject *container);
GList *
glade_gtk_combo_box_get_children (GladeWidgetAdaptor *adaptor, GtkComboBox *combo)
{
GList *list = NULL;
list = glade_gtk_cell_layout_get_children (adaptor, G_OBJECT (combo));
/* return the internal entry.
*
* FIXME: for recent gtk+ we have no comboboxentry
* but a "has-entry" property instead
*/
if (gtk_combo_box_get_has_entry (combo))
list = g_list_append (list, gtk_bin_get_child (GTK_BIN (combo)));
return list;
}
GObject *
glade_gtk_combo_box_get_internal_child (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *name)
{
GObject *child = NULL;
g_return_val_if_fail (GTK_IS_COMBO_BOX (object), NULL);
if (gtk_combo_box_get_has_entry (GTK_COMBO_BOX (object)) && strcmp ("entry", name) == 0)
child = G_OBJECT (gtk_bin_get_child (GTK_BIN (object)));
return child;
}
/* ----------------------------- GtkSpinButton ------------------------------ */
static void
glade_gtk_spin_button_set_adjustment (GObject *object, const GValue *value)
{
GObject *adjustment;
GtkAdjustment *adj;
g_return_if_fail (GTK_IS_SPIN_BUTTON (object));
adjustment = g_value_get_object (value);
if (adjustment && GTK_IS_ADJUSTMENT (adjustment))
{
adj = GTK_ADJUSTMENT (adjustment);
if (gtk_adjustment_get_page_size (adj) > 0)
{
GladeWidget *gadj = glade_widget_get_from_gobject (adj);
/* Silently set any spin-button adjustment page size to 0 */
glade_widget_property_set (gadj, "page-size", 0.0F);
gtk_adjustment_set_page_size (adj, 0);
}
gtk_spin_button_set_adjustment (GTK_SPIN_BUTTON (object), adj);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (object),
gtk_adjustment_get_value (adj));
}
}
void
glade_gtk_spin_button_set_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *id,
const GValue *value)
{
if (!strcmp (id, "adjustment"))
glade_gtk_spin_button_set_adjustment (object, value);
else
GWA_GET_CLASS (GTK_TYPE_ENTRY)->set_property (adaptor,
object,
id, value);
}
/* ------------------------------ GtkAssistant ------------------------------ */
static void
glade_gtk_assistant_append_new_page (GladeWidget *parent,
GladeProject *project,
const gchar *label,
GtkAssistantPageType type)
{
static GladeWidgetAdaptor *adaptor = NULL;
GladeWidget *page;
if (adaptor == NULL)
adaptor = glade_widget_adaptor_get_by_type (GTK_TYPE_LABEL);
page = glade_widget_adaptor_create_widget (adaptor, FALSE,
"parent", parent,
"project", project,
NULL);
glade_widget_add_child (parent, page, FALSE);
glade_widget_property_set (page, "label", label);
glade_widget_pack_property_set (page, "page-type", type);
}
/*
GtkAssistant is a very weird widget, why is it derived from GtkWindow
instead of GtkNotebook I do not know!
If there is no GTK_ASSISTANT_PAGE_CONFIRM, GtkAssistant abort when trying to
update its navigation buttons!
*/
static void
glade_gtk_assistant_update_page_type (GtkAssistant *assistant)
{
gint i, current, pages;
GtkWidget *page;
current = gtk_assistant_get_current_page (assistant);
pages = gtk_assistant_get_n_pages (assistant) - 1;
if (pages < 0) return;
/* Last Page */
page = gtk_assistant_get_nth_page (assistant, pages);
gtk_assistant_set_page_type (assistant, page, GTK_ASSISTANT_PAGE_CONFIRM);
/* First page */
page = gtk_assistant_get_nth_page (assistant, 0);
gtk_assistant_set_page_type (assistant, page, GTK_ASSISTANT_PAGE_INTRO);
/* In betwen pages */
for (i = 1; i < pages; i++)
{
page = gtk_assistant_get_nth_page (assistant, i);
gtk_assistant_set_page_type (assistant, page, GTK_ASSISTANT_PAGE_CONTENT);
}
/* Now we have set page-type in every page, force button update */
for (i = 0; i <= pages; i++)
{
page = gtk_assistant_get_nth_page (assistant, i);
gtk_assistant_set_page_complete (assistant, page, TRUE);
gtk_assistant_set_current_page (assistant, i);
gtk_assistant_update_buttons_state (assistant);
}
if (current >= 0) gtk_assistant_set_current_page (assistant, current);
}
static gint
glade_gtk_assistant_get_page (GtkAssistant *assistant, GtkWidget *page)
{
gint i, pages = gtk_assistant_get_n_pages (assistant);
for (i = 0; i < pages; i++)
if (gtk_assistant_get_nth_page (assistant, i) == page)
return i;
return -1;
}
static void
glade_gtk_assistant_update_position (GtkAssistant *assistant)
{
gint i, pages = gtk_assistant_get_n_pages (assistant);
for (i = 0; i < pages; i++)
{
GtkWidget *page = gtk_assistant_get_nth_page (assistant, i);
GladeWidget *gpage = glade_widget_get_from_gobject (G_OBJECT (page));
if (gpage) glade_widget_pack_property_set (gpage, "position", i);
}
}
static void
glade_gtk_assistant_parse_finished (GladeProject *project,
GObject *object)
{
GtkAssistant *assistant = GTK_ASSISTANT (object);
gint pages = gtk_assistant_get_n_pages (assistant);
if (pages)
{
/* also sets pages "complete" and thus allows navigation under glade */
glade_gtk_assistant_update_page_type (assistant);
gtk_assistant_set_current_page (assistant, 0);
glade_widget_property_set (glade_widget_get_from_gobject (object),
"n-pages", pages);
}
}
void
glade_gtk_assistant_post_create (GladeWidgetAdaptor *adaptor,
GObject *object,
GladeCreateReason reason)
{
GladeWidget *parent = glade_widget_get_from_gobject (object);
GladeProject *project = glade_widget_get_project (parent);
if (reason == GLADE_CREATE_LOAD)
{
g_signal_connect (project, "parse-finished",
G_CALLBACK (glade_gtk_assistant_parse_finished),
object);
return;
}
if (reason == GLADE_CREATE_USER)
{
glade_gtk_assistant_append_new_page (parent, project,
_("Introduction page"),
GTK_ASSISTANT_PAGE_INTRO);
glade_gtk_assistant_append_new_page (parent, project,
_("Content page"),
GTK_ASSISTANT_PAGE_CONTENT);
glade_gtk_assistant_append_new_page (parent, project,
_("Confirmation page"),
GTK_ASSISTANT_PAGE_CONFIRM);
gtk_assistant_set_current_page (GTK_ASSISTANT (object), 0);
glade_widget_property_set (parent, "n-pages", 3);
}
}
void
glade_gtk_assistant_add_child (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *child)
{
GtkAssistant *assistant = GTK_ASSISTANT (container);
GtkWidget *widget = GTK_WIDGET (child);
gtk_assistant_append_page (assistant, widget);
}
void
glade_gtk_assistant_remove_child (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *child)
{
GtkAssistant *assistant = GTK_ASSISTANT (container);
GladeWidget *gassistant = glade_widget_get_from_gobject (container);
gtk_container_remove (GTK_CONTAINER (container), GTK_WIDGET (child));
glade_widget_property_set (gassistant, "n-pages",
gtk_assistant_get_n_pages (assistant));
}
void
glade_gtk_assistant_replace_child (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *current,
GObject *new_object)
{
GtkAssistant *assistant = GTK_ASSISTANT (container);
GtkWidget *page = GTK_WIDGET (new_object), *old_page = GTK_WIDGET (current);
gint pos = glade_gtk_assistant_get_page (assistant, old_page);
gboolean set_current = gtk_assistant_get_current_page (assistant) == pos;
gtk_container_remove (GTK_CONTAINER (container), old_page);
gtk_assistant_insert_page (assistant, page, pos);
glade_gtk_assistant_update_page_type (assistant);
if (set_current) gtk_assistant_set_current_page (assistant, pos);
}
gboolean
glade_gtk_assistant_verify_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *property_name,
const GValue *value)
{
if (strcmp (property_name, "n-pages") == 0)
return g_value_get_int (value) >=
gtk_assistant_get_n_pages (GTK_ASSISTANT (object));
/* Chain Up */
if (GWA_GET_CLASS (GTK_TYPE_WINDOW)->verify_property == NULL)
return TRUE;
return GWA_GET_CLASS (GTK_TYPE_WINDOW)->verify_property (adaptor,
object,
property_name,
value);
}
void
glade_gtk_assistant_set_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *property_name,
const GValue *value)
{
if (strcmp (property_name, "n-pages") == 0)
{
GtkAssistant *assistant = GTK_ASSISTANT (object);
gint size, i;
for (i = gtk_assistant_get_n_pages (GTK_ASSISTANT (object)),
size = g_value_get_int (value); i < size; i++)
gtk_assistant_append_page (assistant, glade_placeholder_new ());
glade_gtk_assistant_update_page_type (assistant);
return;
}
/* Chain Up */
GWA_GET_CLASS (GTK_TYPE_WINDOW)->set_property (adaptor,
object,
property_name,
value);
}
void
glade_gtk_assistant_get_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *property_name,
GValue *value)
{
if (strcmp (property_name, "n-pages") == 0)
{
g_value_set_int (value,
gtk_assistant_get_n_pages (GTK_ASSISTANT (object)));
return;
}
/* Chain Up */
GWA_GET_CLASS (GTK_TYPE_WINDOW)->get_property (adaptor,
object,
property_name,
value);
}
void
glade_gtk_assistant_set_child_property (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *child,
const gchar *property_name,
const GValue *value)
{
if (strcmp (property_name, "position") == 0)
{
GtkAssistant *assistant = GTK_ASSISTANT (container);
GtkWidget *widget = GTK_WIDGET (child);
gint pos, size;
gboolean set_current;
if ((pos = g_value_get_int (value)) < 0) return;
if (pos == glade_gtk_assistant_get_page (assistant, widget))
return;
set_current = gtk_assistant_get_current_page (assistant) ==
glade_gtk_assistant_get_page (assistant, widget);
size = gtk_assistant_get_n_pages (assistant);
g_object_ref (child);
gtk_container_remove (GTK_CONTAINER (container), widget);
gtk_assistant_insert_page (assistant, widget, pos);
g_object_unref (child);
if (set_current) gtk_assistant_set_current_page (assistant, pos);
glade_gtk_assistant_update_page_type (assistant);
glade_gtk_assistant_update_position (assistant);
return;
}
/* Chain Up */
GWA_GET_CLASS (GTK_TYPE_WINDOW)->child_set_property (adaptor,
container,
child,
property_name,
value);
}
void
glade_gtk_assistant_get_child_property (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *child,
const gchar *property_name,
GValue *value)
{
if (strcmp (property_name, "position") == 0)
{
gint pos;
pos = glade_gtk_assistant_get_page (GTK_ASSISTANT (container),
GTK_WIDGET (child));
if (pos >= 0) g_value_set_int (value, pos);
return;
}
/* Chain Up */
GWA_GET_CLASS (GTK_TYPE_WINDOW)->child_get_property (adaptor,
container,
child,
property_name,
value);
}
/*--------------------------- GtkRadioButton ---------------------------------*/
void
glade_gtk_radio_button_set_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *property_name,
const GValue *value)
{
if (strcmp (property_name, "group") == 0)
{
GtkRadioButton *radio = g_value_get_object (value);
/* g_object_set () on this property produces a bogus warning,
* so we better use the API GtkRadioButton provides.
*/
gtk_radio_button_set_group (GTK_RADIO_BUTTON (object),
radio ? gtk_radio_button_get_group (radio) : NULL);
return;
}
/* Chain Up */
GWA_GET_CLASS (GTK_TYPE_CHECK_BUTTON)->set_property (adaptor,
object,
property_name,
value);
}
/*--------------------------- GtkSizeGroup ---------------------------------*/
gboolean
glade_gtk_size_group_depends (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeWidget *another)
{
if (GTK_IS_WIDGET (another->object))
return TRUE;
return GWA_GET_CLASS (G_TYPE_OBJECT)->depends (adaptor, widget, another);
}
#define GLADE_TAG_SIZEGROUP_WIDGETS "widgets"
#define GLADE_TAG_SIZEGROUP_WIDGET "widget"
static void
glade_gtk_size_group_read_widgets (GladeWidget *widget,
GladeXmlNode *node)
{
GladeXmlNode *widgets_node;
GladeProperty *property;
gchar *string = NULL;
if ((widgets_node =
glade_xml_search_child (node, GLADE_TAG_SIZEGROUP_WIDGETS)) != NULL)
{
GladeXmlNode *node;
for (node = glade_xml_node_get_children (widgets_node);
node; node = glade_xml_node_next (node))
{
gchar *widget_name, *tmp;
if (!glade_xml_node_verify (node, GLADE_TAG_SIZEGROUP_WIDGET))
continue;
widget_name = glade_xml_get_property_string_required
(node, GLADE_TAG_NAME, NULL);
if (string == NULL)
string = widget_name;
else if (widget_name != NULL)
{
tmp = g_strdup_printf ("%s%s%s", string, GPC_OBJECT_DELIMITER, widget_name);
string = (g_free (string), tmp);
g_free (widget_name);
}
}
}
if (string)
{
property = glade_widget_get_property (widget, "widgets");
g_assert (property);
/* we must synchronize this directly after loading this project
* (i.e. lookup the actual objects after they've been parsed and
* are present).
*/
g_object_set_data_full (G_OBJECT (property),
"glade-loaded-object",
string, g_free);
}
}
void
glade_gtk_size_group_read_widget (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlNode *node)
{
if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
return;
/* First chain up and read in all the normal properties.. */
GWA_GET_CLASS (G_TYPE_OBJECT)->read_widget (adaptor, widget, node);
glade_gtk_size_group_read_widgets (widget, node);
}
static void
glade_gtk_size_group_write_widgets (GladeWidget *widget,
GladeXmlContext *context,
GladeXmlNode *node)
{
GladeXmlNode *widgets_node, *widget_node;
GList *widgets = NULL, *list;
GladeWidget *awidget;
widgets_node = glade_xml_node_new (context, GLADE_TAG_SIZEGROUP_WIDGETS);
if (glade_widget_property_get (widget, "widgets", &widgets))
{
for (list = widgets; list; list = list->next)
{
awidget = glade_widget_get_from_gobject (list->data);
widget_node = glade_xml_node_new (context, GLADE_TAG_SIZEGROUP_WIDGET);
glade_xml_node_append_child (widgets_node, widget_node);
glade_xml_node_set_property_string (widget_node, GLADE_TAG_NAME, awidget->name);
}
}
if (!glade_xml_node_get_children (widgets_node))
glade_xml_node_delete (widgets_node);
else
glade_xml_node_append_child (node, widgets_node);
}
void
glade_gtk_size_group_write_widget (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlContext *context,
GladeXmlNode *node)
{
if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
return;
/* First chain up and read in all the normal properties.. */
GWA_GET_CLASS (G_TYPE_OBJECT)->write_widget (adaptor, widget, context, node);
glade_gtk_size_group_write_widgets (widget, context, node);
}
void
glade_gtk_size_group_set_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *property_name,
const GValue *value)
{
if (!strcmp (property_name, "widgets"))
{
GSList *sg_widgets, *slist;
GList *widgets, *list;
/* remove old widgets */
if ((sg_widgets = gtk_size_group_get_widgets (GTK_SIZE_GROUP (object))) != NULL)
{
/* copy since we are modifying an internal list */
sg_widgets = g_slist_copy (sg_widgets);
for (slist = sg_widgets; slist; slist = slist->next)
gtk_size_group_remove_widget (GTK_SIZE_GROUP (object), GTK_WIDGET (slist->data));
g_slist_free (sg_widgets);
}
/* add new widgets */
if ((widgets = g_value_get_boxed (value)) != NULL)
{
for (list = widgets; list; list = list->next)
gtk_size_group_add_widget (GTK_SIZE_GROUP (object), GTK_WIDGET (list->data));
}
}
else
GWA_GET_CLASS (G_TYPE_OBJECT)->set_property (adaptor, object,
property_name, value);
}
/*--------------------------- GtkIconFactory ---------------------------------*/
#define GLADE_TAG_SOURCES "sources"
#define GLADE_TAG_SOURCE "source"
#define GLADE_TAG_STOCK_ID "stock-id"
#define GLADE_TAG_FILENAME "filename"
#define GLADE_TAG_DIRECTION "direction"
#define GLADE_TAG_STATE "state"
#define GLADE_TAG_SIZE "size"
void
glade_gtk_icon_factory_post_create (GladeWidgetAdaptor *adaptor,
GObject *object,
GladeCreateReason reason)
{
gtk_icon_factory_add_default (GTK_ICON_FACTORY (object));
}
static void
glade_gtk_icon_factory_read_sources (GladeWidget *widget,
GladeXmlNode *node)
{
GladeIconSources *sources;
GtkIconSource *source;
GladeXmlNode *sources_node, *source_node;
GValue *value;
GList *list;
gchar *current_icon_name = NULL;
GdkPixbuf *pixbuf;
if ((sources_node = glade_xml_search_child (node, GLADE_TAG_SOURCES)) == NULL)
return;
sources = glade_icon_sources_new ();
/* Here we expect all icon sets to remain together in the list. */
for (source_node = glade_xml_node_get_children (sources_node); source_node;
source_node = glade_xml_node_next (source_node))
{
gchar *icon_name;
gchar *str;
if (!glade_xml_node_verify (source_node, GLADE_TAG_SOURCE))
continue;
if (!(icon_name =
glade_xml_get_property_string_required (source_node, GLADE_TAG_STOCK_ID, NULL)))
continue;
if (!(str = glade_xml_get_property_string_required (source_node, GLADE_TAG_FILENAME, NULL)))
{
g_free (icon_name);
continue;
}
if (!current_icon_name || strcmp (current_icon_name, icon_name) != 0)
current_icon_name = (g_free (current_icon_name), g_strdup (icon_name));
source = gtk_icon_source_new ();
/* Deal with the filename... */
value = glade_utils_value_from_string (GDK_TYPE_PIXBUF, str,
widget->project, widget);
pixbuf = g_value_dup_object (value);
g_value_unset (value);
g_free (value);
gtk_icon_source_set_pixbuf (source, pixbuf);
g_object_unref (G_OBJECT (pixbuf));
g_free (str);
/* Now the attributes... */
if ((str = glade_xml_get_property_string (source_node, GLADE_TAG_DIRECTION)) != NULL)
{
GtkTextDirection direction =
glade_utils_enum_value_from_string (GTK_TYPE_TEXT_DIRECTION, str);
gtk_icon_source_set_direction_wildcarded (source, FALSE);
gtk_icon_source_set_direction (source, direction);
g_free (str);
}
if ((str = glade_xml_get_property_string (source_node, GLADE_TAG_SIZE)) != NULL)
{
GtkIconSize size =
glade_utils_enum_value_from_string (GTK_TYPE_ICON_SIZE, str);
gtk_icon_source_set_size_wildcarded (source, FALSE);
gtk_icon_source_set_size (source, size);
g_free (str);
}
if ((str = glade_xml_get_property_string (source_node, GLADE_TAG_STATE)) != NULL)
{
GtkStateType state =
glade_utils_enum_value_from_string (GTK_TYPE_STATE_TYPE, str);
gtk_icon_source_set_state_wildcarded (source, FALSE);
gtk_icon_source_set_state (source, state);
g_free (str);
}
if ((list = g_hash_table_lookup (sources->sources, g_strdup (current_icon_name))) != NULL)
{
GList *new_list = g_list_append (list, source);
/* Warning: if we use g_list_prepend() the returned pointer will be different
* so we would have to replace the list pointer in the hash table.
* But before doing that we have to steal the old list pointer otherwise
* we would have to make a copy then add the new icon to finally replace the hash table
* value.
* Anyways if we choose to prepend we would have to reverse the list outside this loop
* so its better to append.
*/
if (new_list != list)
{
/* current g_list_append() returns the same pointer so this is not needed */
g_hash_table_steal (sources->sources, current_icon_name);
g_hash_table_insert (sources->sources, g_strdup (current_icon_name), new_list);
}
}
else
{
list = g_list_append (NULL, source);
g_hash_table_insert (sources->sources, g_strdup (current_icon_name), list);
}
}
if (g_hash_table_size (sources->sources) > 0)
glade_widget_property_set (widget, "sources", sources);
glade_icon_sources_free (sources);
}
void
glade_gtk_icon_factory_read_widget (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlNode *node)
{
if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
return;
/* First chain up and read in any normal properties.. */
GWA_GET_CLASS (G_TYPE_OBJECT)->read_widget (adaptor, widget, node);
glade_gtk_icon_factory_read_sources (widget, node);
}
typedef struct {
GladeXmlContext *context;
GladeXmlNode *node;
} SourceWriteTab;
static void
write_icon_sources (gchar *icon_name,
GList *sources,
SourceWriteTab *tab)
{
GladeXmlNode *source_node;
GtkIconSource *source;
GList *l;
gchar *string;
GdkPixbuf *pixbuf;
for (l = sources; l; l = l->next)
{
source = l->data;
source_node = glade_xml_node_new (tab->context, GLADE_TAG_SOURCE);
glade_xml_node_append_child (tab->node, source_node);
glade_xml_node_set_property_string (source_node, GLADE_TAG_STOCK_ID, icon_name);
if (!gtk_icon_source_get_direction_wildcarded (source))
{
GtkTextDirection direction = gtk_icon_source_get_direction (source);
string = glade_utils_enum_string_from_value (GTK_TYPE_TEXT_DIRECTION, direction);
glade_xml_node_set_property_string (source_node, GLADE_TAG_DIRECTION, string);
g_free (string);
}
if (!gtk_icon_source_get_size_wildcarded (source))
{
GtkIconSize size = gtk_icon_source_get_size (source);
string = glade_utils_enum_string_from_value (GTK_TYPE_ICON_SIZE, size);
glade_xml_node_set_property_string (source_node, GLADE_TAG_SIZE, string);
g_free (string);
}
if (!gtk_icon_source_get_state_wildcarded (source))
{
GtkStateType state = gtk_icon_source_get_state (source);
string = glade_utils_enum_string_from_value (GTK_TYPE_STATE_TYPE, state);
glade_xml_node_set_property_string (source_node, GLADE_TAG_STATE, string);
g_free (string);
}
pixbuf = gtk_icon_source_get_pixbuf (source);
string = g_object_get_data (G_OBJECT (pixbuf), "GladeFileName");
glade_xml_node_set_property_string (source_node,
GLADE_TAG_FILENAME,
string);
}
}
static void
glade_gtk_icon_factory_write_sources (GladeWidget *widget,
GladeXmlContext *context,
GladeXmlNode *node)
{
GladeXmlNode *sources_node;
GladeIconSources *sources = NULL;
SourceWriteTab tab;
glade_widget_property_get (widget, "sources", &sources);
if (!sources)
return;
sources_node = glade_xml_node_new (context, GLADE_TAG_SOURCES);
tab.context = context;
tab.node = sources_node;
g_hash_table_foreach (sources->sources, (GHFunc)write_icon_sources, &tab);
if (!glade_xml_node_get_children (sources_node))
glade_xml_node_delete (sources_node);
else
glade_xml_node_append_child (node, sources_node);
}
void
glade_gtk_icon_factory_write_widget (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlContext *context,
GladeXmlNode *node)
{
if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
return;
/* First chain up and write all the normal properties.. */
GWA_GET_CLASS (G_TYPE_OBJECT)->write_widget (adaptor, widget, context, node);
glade_gtk_icon_factory_write_sources (widget, context, node);
}
static void
apply_icon_sources (gchar *icon_name,
GList *sources,
GtkIconFactory *factory)
{
GtkIconSource *source;
GtkIconSet *set;
GList *l;
set = gtk_icon_set_new ();
for (l = sources; l; l = l->next)
{
source = gtk_icon_source_copy ((GtkIconSource *)l->data);
gtk_icon_set_add_source (set, source);
}
gtk_icon_factory_add (factory, icon_name, set);
}
static void
glade_gtk_icon_factory_set_sources (GObject *object, const GValue *value)
{
GladeIconSources *sources = g_value_get_boxed (value);
if (sources)
g_hash_table_foreach (sources->sources, (GHFunc)apply_icon_sources, object);
}
void
glade_gtk_icon_factory_set_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *property_name,
const GValue *value)
{
if (strcmp (property_name, "sources") == 0)
{
glade_gtk_icon_factory_set_sources (object, value);
}
else
/* Chain Up */
GWA_GET_CLASS (G_TYPE_OBJECT)->set_property (adaptor,
object,
property_name,
value);
}
static void
serialize_icon_sources (gchar *icon_name,
GList *sources,
GString *string)
{
GList *l;
for (l = sources; l; l = g_list_next (l))
{
GtkIconSource *source = l->data;
GdkPixbuf *pixbuf;
gchar *str;
pixbuf = gtk_icon_source_get_pixbuf (source);
str = g_object_get_data (G_OBJECT (pixbuf), "GladeFileName");
g_string_append_printf (string, "%s[%s] ", icon_name, str);
if (!gtk_icon_source_get_direction_wildcarded (source))
{
GtkTextDirection direction = gtk_icon_source_get_direction (source);
str = glade_utils_enum_string_from_value (GTK_TYPE_TEXT_DIRECTION, direction);
g_string_append_printf (string, "dir-%s ", str);
g_free (str);
}
if (!gtk_icon_source_get_size_wildcarded (source))
{
GtkIconSize size = gtk_icon_source_get_size (source);
str = glade_utils_enum_string_from_value (GTK_TYPE_ICON_SIZE, size);
g_string_append_printf (string, "size-%s ", str);
g_free (str);
}
if (!gtk_icon_source_get_state_wildcarded (source))
{
GtkStateType state = gtk_icon_source_get_state (source);
str = glade_utils_enum_string_from_value (GTK_TYPE_STATE_TYPE, state);
g_string_append_printf (string, "state-%s ", str);
g_free (str);
}
g_string_append_printf (string, "| ");
}
}
gchar *
glade_gtk_icon_factory_string_from_value (GladeWidgetAdaptor *adaptor,
GladePropertyClass *klass,
const GValue *value)
{
GString *string;
if (klass->pspec->value_type == GLADE_TYPE_ICON_SOURCES)
{
GladeIconSources *sources = g_value_get_boxed (value);
if (!sources)
return g_strdup ("");
string = g_string_new ("");
g_hash_table_foreach (sources->sources, (GHFunc)serialize_icon_sources, string);
return g_string_free (string, FALSE);
}
else
return GWA_GET_CLASS
(G_TYPE_OBJECT)->string_from_value (adaptor,
klass,
value);
}
GladeEditorProperty *
glade_gtk_icon_factory_create_eprop (GladeWidgetAdaptor *adaptor,
GladePropertyClass *klass,
gboolean use_command)
{
GladeEditorProperty *eprop;
if (klass->pspec->value_type == GLADE_TYPE_ICON_SOURCES)
eprop = g_object_new (GLADE_TYPE_EPROP_ICON_SOURCES,
"property-class", klass,
"use-command", use_command,
NULL);
else
eprop = GWA_GET_CLASS
(G_TYPE_OBJECT)->create_eprop (adaptor,
klass,
use_command);
return eprop;
}
GladeEditable *
glade_gtk_icon_factory_create_editable (GladeWidgetAdaptor *adaptor,
GladeEditorPageType type)
{
GladeEditable *editable;
/* Get base editable */
editable = GWA_GET_CLASS (G_TYPE_OBJECT)->create_editable (adaptor, type);
if (type == GLADE_PAGE_GENERAL)
return (GladeEditable *)glade_icon_factory_editor_new (adaptor, editable);
return editable;
}
/*--------------------------- GtkListStore/GtkTreeStore ---------------------------------*/
#define GLADE_TAG_COLUMNS "columns"
#define GLADE_TAG_COLUMN "column"
#define GLADE_TAG_TYPE "type"
#define GLADE_TAG_ROW "row"
#define GLADE_TAG_DATA "data"
#define GLADE_TAG_COL "col"
static gboolean
glade_gtk_cell_layout_has_renderer (GtkCellLayout *layout,
GtkCellRenderer *renderer)
{
GList *cells = gtk_cell_layout_get_cells (layout);
gboolean has_renderer;
has_renderer = (g_list_find (cells, renderer) != NULL);
g_list_free (cells);
return has_renderer;
}
static gboolean
glade_gtk_cell_renderer_sync_attributes (GObject *object)
{
GtkCellLayout *layout;
GtkCellRenderer *cell;
GladeWidget *widget = glade_widget_get_from_gobject (object);
GladeWidget *gmodel;
GladeProperty *property;
gchar *attr_prop_name;
GList *l, *column_list = NULL;
gint columns = 0;
static gint attr_len = 0;
if (!attr_len)
attr_len = strlen ("attr-");
/* Apply attributes to renderer when bound to a model in runtime */
widget = glade_widget_get_from_gobject (object);
if (widget->parent == NULL) return FALSE;
/* When creating widgets, sometimes the parent is set before parenting happens,
* here we have to be careful for that..
*/
layout = GTK_CELL_LAYOUT (widget->parent->object);
cell = GTK_CELL_RENDERER (object);
if (!glade_gtk_cell_layout_has_renderer (layout, cell))
return FALSE;
if ((gmodel = glade_cell_renderer_get_model (widget)) == NULL)
return FALSE;
glade_widget_property_get (gmodel, "columns", &column_list);
columns = g_list_length (column_list);
gtk_cell_layout_clear_attributes (layout, cell);
for (l = widget->properties; l; l = l->next)
{
property = l->data;
if (strncmp (property->klass->id, "attr-", attr_len) == 0)
{
GladeProperty *attr_prop;
gint column = g_value_get_int (property->value);
attr_prop_name = &property->klass->id[attr_len];
attr_prop = glade_widget_get_property (widget, attr_prop_name);
if (column >= 0 && column < columns)
{
GladeColumnType *column_type = (GladeColumnType *)g_list_nth_data (column_list, column);
GType column_gtype = g_type_from_name (column_type->type_name);
if (column_gtype &&
g_value_type_transformable (column_gtype, attr_prop->klass->pspec->value_type))
gtk_cell_layout_add_attribute (layout, cell, attr_prop_name, column);
}
}
}
return FALSE;
}
static gboolean
glade_gtk_cell_layout_sync_attributes (GObject *layout)
{
GladeWidget *gwidget = glade_widget_get_from_gobject (layout);
GObject *cell;
GList *children, *l;
children = glade_widget_adaptor_get_children (gwidget->adaptor, layout);
for (l = children; l; l = l->next)
{
cell = l->data;
if (!GTK_IS_CELL_RENDERER (cell))
continue;
glade_gtk_cell_renderer_sync_attributes (cell);
}
g_list_free (children);
return FALSE;
}
static void
glade_gtk_store_set_columns (GObject *object,
const GValue *value)
{
GList *l;
gint i, n;
GType *types;
for (i = 0, l = g_value_get_boxed (value), n = g_list_length (l), types = g_new (GType, n);
l; l = g_list_next (l), i++)
{
GladeColumnType *data = l->data;
if (g_type_from_name (data->type_name) != G_TYPE_INVALID)
types[i] = g_type_from_name (data->type_name);
else
types[i] = G_TYPE_POINTER;
}
if (GTK_IS_LIST_STORE (object))
gtk_list_store_set_column_types (GTK_LIST_STORE (object), n, types);
else
gtk_tree_store_set_column_types (GTK_TREE_STORE (object), n, types);
g_free (types);
}
static void
glade_gtk_store_set_data (GObject *object,
const GValue *value)
{
GladeWidget *gwidget = glade_widget_get_from_gobject (object);
GList *columns = NULL;
GNode *data_tree, *row, *iter;
gint colnum;
GtkTreeIter row_iter;
GladeModelData *data;
GType column_type;
if (GTK_IS_LIST_STORE (object))
gtk_list_store_clear (GTK_LIST_STORE (object));
else
gtk_tree_store_clear (GTK_TREE_STORE (object));
glade_widget_property_get (gwidget, "columns", &columns);
data_tree = g_value_get_boxed (value);
/* Nothing to enter without columns defined */
if (!data_tree || !columns)
return;
for (row = data_tree->children; row; row = row->next)
{
if (GTK_IS_LIST_STORE (object))
gtk_list_store_append (GTK_LIST_STORE (object), &row_iter);
else
/* (for now no child data... ) */
gtk_tree_store_append (GTK_TREE_STORE (object), &row_iter, NULL);
for (colnum = 0, iter = row->children; iter;
colnum++, iter = iter->next)
{
data = iter->data;
if (!g_list_nth (columns, colnum))
break;
/* Abort if theres a type mismatch, the widget's being rebuilt
* and a sync will come soon with the right values
*/
column_type = gtk_tree_model_get_column_type (GTK_TREE_MODEL (object), colnum);
if (G_VALUE_TYPE (&data->value) != column_type)
continue;
if (GTK_IS_LIST_STORE (object))
gtk_list_store_set_value (GTK_LIST_STORE (object),
&row_iter,
colnum, &data->value);
else
gtk_tree_store_set_value (GTK_TREE_STORE (object),
&row_iter,
colnum, &data->value);
}
}
}
void
glade_gtk_store_set_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *property_name,
const GValue *value)
{
if (strcmp (property_name, "columns") == 0)
{
glade_gtk_store_set_columns (object, value);
}
else if (strcmp (property_name, "data") == 0)
{
glade_gtk_store_set_data (object, value);
}
else
/* Chain Up */
GWA_GET_CLASS (G_TYPE_OBJECT)->set_property (adaptor,
object,
property_name,
value);
}
GladeEditorProperty *
glade_gtk_store_create_eprop (GladeWidgetAdaptor *adaptor,
GladePropertyClass *klass,
gboolean use_command)
{
GladeEditorProperty *eprop;
/* chain up.. */
if (klass->pspec->value_type == GLADE_TYPE_COLUMN_TYPE_LIST)
eprop = g_object_new (GLADE_TYPE_EPROP_COLUMN_TYPES,
"property-class", klass,
"use-command", use_command,
NULL);
else if (klass->pspec->value_type == GLADE_TYPE_MODEL_DATA_TREE)
eprop = g_object_new (GLADE_TYPE_EPROP_MODEL_DATA,
"property-class", klass,
"use-command", use_command,
NULL);
else
eprop = GWA_GET_CLASS
(G_TYPE_OBJECT)->create_eprop (adaptor,
klass,
use_command);
return eprop;
}
static void
glade_gtk_store_columns_changed (GladeProperty *property,
GValue *old_value,
GValue *new_value,
GladeWidget *store)
{
GList *l, *list, *children;
/* Reset the attributes for all cell renderers referring to this store */
for (l = store->prop_refs; l; l = l->next)
{
GladeWidget *referring_widget = GLADE_PROPERTY (l->data)->widget;
if (GTK_IS_CELL_LAYOUT (referring_widget->object))
glade_gtk_cell_layout_sync_attributes (referring_widget->object);
else if (GTK_IS_TREE_VIEW (referring_widget->object))
{
children = glade_widget_adaptor_get_children (referring_widget->adaptor,
referring_widget->object);
for (list = children; list; list = list->next)
{
/* Clear the GtkTreeViewColumns... */
if (GTK_IS_CELL_LAYOUT (list->data))
glade_gtk_cell_layout_sync_attributes (G_OBJECT (list->data));
}
g_list_free (children);
}
}
}
void
glade_gtk_store_post_create (GladeWidgetAdaptor *adaptor,
GObject *object,
GladeCreateReason reason)
{
GladeWidget *gwidget;
GladeProperty *property;
if (reason == GLADE_CREATE_REBUILD)
return;
gwidget = glade_widget_get_from_gobject (object);
property = glade_widget_get_property (gwidget, "columns");
/* Here we watch the value-changed signal on the "columns" property, we need
* to reset all the Cell Renderer attributes when the underlying "columns" change,
* the reason we do it from "value-changed" is because GladeWidget prop references
* are unavailable while rebuilding an object, and the liststore needs to be rebuilt
* in order to set the columns.
*
* This signal will be envoked after applying the new column types to the store
* and before the views get any signal to update themselves from the changed model,
* perfect time to reset the attributes.
*/
g_signal_connect (G_OBJECT (property), "value-changed",
G_CALLBACK (glade_gtk_store_columns_changed), gwidget);
}
GladeEditable *
glade_gtk_store_create_editable (GladeWidgetAdaptor *adaptor,
GladeEditorPageType type)
{
GladeEditable *editable;
/* Get base editable */
editable = GWA_GET_CLASS (G_TYPE_OBJECT)->create_editable (adaptor, type);
if (type == GLADE_PAGE_GENERAL)
return (GladeEditable *)glade_store_editor_new (adaptor, editable);
return editable;
}
gchar *
glade_gtk_store_string_from_value (GladeWidgetAdaptor *adaptor,
GladePropertyClass *klass,
const GValue *value)
{
GString *string;
if (klass->pspec->value_type == GLADE_TYPE_COLUMN_TYPE_LIST)
{
GList *l;
string = g_string_new ("");
for (l = g_value_get_boxed (value); l; l = g_list_next (l))
{
GladeColumnType *data = l->data;
g_string_append_printf (string, (g_list_next (l)) ? "%s:%s|" : "%s:%s",
data->type_name, data->column_name);
}
return g_string_free (string, FALSE);
}
else if (klass->pspec->value_type == GLADE_TYPE_MODEL_DATA_TREE)
{
GladeModelData *data;
GNode *data_tree, *row, *iter;
gint rownum;
gchar *str;
gboolean is_last;
/* Return a unique string for the backend to compare */
data_tree = g_value_get_boxed (value);
if (!data_tree || !data_tree->children)
return g_strdup ("");
string = g_string_new ("");
for (rownum = 0, row = data_tree->children; row;
rownum++, row = row->next)
{
for (iter = row->children; iter; iter = iter->next)
{
data = iter->data;
if (!G_VALUE_TYPE (&data->value) ||
G_VALUE_TYPE (&data->value) == G_TYPE_INVALID)
str = g_strdup ("(virtual)");
else if (G_VALUE_TYPE (&data->value) != G_TYPE_POINTER)
str = glade_utils_string_from_value (&data->value);
else
str = g_strdup ("(null)");
is_last = !row->next && !iter->next;
g_string_append_printf (string, "%s[%d]:%s",
data->name, rownum, str);
if (data->i18n_translatable)
g_string_append_printf (string, " translatable");
if (data->i18n_context)
g_string_append_printf (string, " i18n-context:%s", data->i18n_context);
if (data->i18n_comment)
g_string_append_printf (string, " i18n-comment:%s", data->i18n_comment);
if (!is_last)
g_string_append_printf (string, "|");
g_free (str);
}
}
return g_string_free (string, FALSE);
}
else
return GWA_GET_CLASS
(G_TYPE_OBJECT)->string_from_value (adaptor,
klass,
value);
}
static void
glade_gtk_store_write_columns (GladeWidget *widget,
GladeXmlContext *context,
GladeXmlNode *node)
{
GladeXmlNode *columns_node;
GladeProperty *prop;
GList *l;
prop = glade_widget_get_property (widget, "columns");
columns_node = glade_xml_node_new (context, GLADE_TAG_COLUMNS);
for (l = g_value_get_boxed (prop->value); l; l = g_list_next (l))
{
GladeColumnType *data = l->data;
GladeXmlNode *column_node, *comment_node;
/* Write column names in comments... */
gchar *comment = g_strdup_printf (" column-name %s ", data->column_name);
comment_node = glade_xml_node_new_comment (context, comment);
glade_xml_node_append_child (columns_node, comment_node);
g_free (comment);
column_node = glade_xml_node_new (context, GLADE_TAG_COLUMN);
glade_xml_node_append_child (columns_node, column_node);
glade_xml_node_set_property_string (column_node, GLADE_TAG_TYPE,
data->type_name);
}
if (!glade_xml_node_get_children (columns_node))
glade_xml_node_delete (columns_node);
else
glade_xml_node_append_child (node, columns_node);
}
static void
glade_gtk_store_write_data (GladeWidget *widget,
GladeXmlContext *context,
GladeXmlNode *node)
{
GladeXmlNode *data_node, *col_node, *row_node;
GList *columns = NULL;
GladeModelData *data;
GNode *data_tree = NULL, *row, *iter;
gint colnum;
glade_widget_property_get (widget, "data", &data_tree);
glade_widget_property_get (widget, "columns", &columns);
/* XXX log errors about data not fitting columns here when
* loggin is available
*/
if (!data_tree || !columns)
return;
data_node = glade_xml_node_new (context, GLADE_TAG_DATA);
for (row = data_tree->children; row; row = row->next)
{
row_node = glade_xml_node_new (context, GLADE_TAG_ROW);
glade_xml_node_append_child (data_node, row_node);
for (colnum = 0, iter = row->children; iter;
colnum++, iter = iter->next)
{
gchar *string, *column_number;
data = iter->data;
/* Skip non-serializable data */
if (G_VALUE_TYPE (&data->value) == 0 ||
G_VALUE_TYPE (&data->value) == G_TYPE_POINTER)
continue;
string = glade_utils_string_from_value (&data->value);
/* XXX Log error: data col j exceeds columns on row i */
if (!g_list_nth (columns, colnum))
break;
column_number = g_strdup_printf ("%d", colnum);
col_node = glade_xml_node_new (context, GLADE_TAG_COL);
glade_xml_node_append_child (row_node, col_node);
glade_xml_node_set_property_string (col_node, GLADE_TAG_ID,
column_number);
glade_xml_set_content (col_node, string);
if (data->i18n_translatable)
glade_xml_node_set_property_string (col_node,
GLADE_TAG_TRANSLATABLE,
GLADE_XML_TAG_I18N_TRUE);
if (data->i18n_context)
glade_xml_node_set_property_string (col_node,
GLADE_TAG_CONTEXT,
data->i18n_context);
if (data->i18n_comment)
glade_xml_node_set_property_string (col_node,
GLADE_TAG_COMMENT,
data->i18n_comment);
g_free (column_number);
g_free (string);
}
}
if (!glade_xml_node_get_children (data_node))
glade_xml_node_delete (data_node);
else
glade_xml_node_append_child (node, data_node);
}
void
glade_gtk_store_write_widget (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlContext *context,
GladeXmlNode *node)
{
if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
return;
/* First chain up and write all the normal properties.. */
GWA_GET_CLASS (G_TYPE_OBJECT)->write_widget (adaptor, widget, context, node);
glade_gtk_store_write_columns (widget, context, node);
glade_gtk_store_write_data (widget, context, node);
}
static void
glade_gtk_store_read_columns (GladeWidget *widget, GladeXmlNode *node)
{
GladeNameContext *context;
GladeXmlNode *columns_node;
GladeProperty *property;
GladeXmlNode *prop;
GList *types = NULL;
GValue value = {0,};
gchar column_name[256];
column_name[0] = '\0';
column_name[255] = '\0';
if ((columns_node = glade_xml_search_child (node, GLADE_TAG_COLUMNS)) == NULL)
return;
context = glade_name_context_new ();
for (prop = glade_xml_node_get_children_with_comments (columns_node); prop;
prop = glade_xml_node_next_with_comments (prop))
{
GladeColumnType *data;
gchar *type, *comment_str, buffer[256];
if (!glade_xml_node_verify_silent (prop, GLADE_TAG_COLUMN) &&
!glade_xml_node_is_comment (prop)) continue;
if (glade_xml_node_is_comment (prop))
{
comment_str = glade_xml_get_content (prop);
if (sscanf (comment_str, " column-name %s", buffer) == 1)
strncpy (column_name, buffer, 255);
g_free (comment_str);
continue;
}
type = glade_xml_get_property_string_required (prop, GLADE_TAG_TYPE, NULL);
data = glade_column_type_new (type, NULL);
data->type_name = g_strdup (type);
data->column_name = column_name[0] ? g_strdup (column_name) : g_ascii_strdown (type, -1);
if (glade_name_context_has_name (context, data->column_name))
{
gchar *name = glade_name_context_new_name (context, data->column_name);
g_free (data->column_name);
data->column_name = name;
}
glade_name_context_add_name (context, data->column_name);
types = g_list_prepend (types, data);
g_free (type);
column_name[0] = '\0';
}
property = glade_widget_get_property (widget, "columns");
g_value_init (&value, GLADE_TYPE_COLUMN_TYPE_LIST);
g_value_take_boxed (&value, g_list_reverse (types));
glade_property_set_value (property, &value);
g_value_unset (&value);
}
static void
glade_gtk_store_read_data (GladeWidget *widget, GladeXmlNode *node)
{
GladeXmlNode *data_node, *row_node, *col_node;
GNode *data_tree, *row, *item;
GladeModelData *data;
GValue *value;
GList *column_types = NULL;
GladeColumnType *column_type;
gint colnum;
if ((data_node = glade_xml_search_child (node, GLADE_TAG_DATA)) == NULL)
return;
/* XXX FIXME: Warn that columns werent there when parsing */
if (!glade_widget_property_get (widget, "columns", &column_types) || !column_types)
return;
/* Create root... */
data_tree = g_node_new (NULL);
for (row_node = glade_xml_node_get_children (data_node); row_node;
row_node = glade_xml_node_next (row_node))
{
gchar *value_str;
if (!glade_xml_node_verify (row_node, GLADE_TAG_ROW))
continue;
row = g_node_new (NULL);
g_node_append (data_tree, row);
/* XXX FIXME: we are assuming that the columns are listed in order */
for (colnum = 0, col_node = glade_xml_node_get_children (row_node); col_node;
col_node = glade_xml_node_next (col_node))
{
gint read_column;
if (!glade_xml_node_verify (col_node, GLADE_TAG_COL))
continue;
read_column = glade_xml_get_property_int (col_node, GLADE_TAG_ID, -1);
if (read_column < 0)
{
g_critical ("Parsed negative column id");
continue;
}
/* Catch up for gaps in the list where unserializable types are involved */
while (colnum < read_column)
{
column_type = g_list_nth_data (column_types, colnum);
data = glade_model_data_new (G_TYPE_INVALID, column_type->column_name);
item = g_node_new (data);
g_node_append (row, item);
colnum++;
}
if (!(column_type = g_list_nth_data (column_types, colnum)))
/* XXX Log this too... */
continue;
/* Ignore unloaded column types for the workspace */
if (g_type_from_name (column_type->type_name) != G_TYPE_INVALID)
{
/* XXX Do we need object properties to somehow work at load time here ??
* should we be doing this part in "finished" ? ... todo thinkso...
*/
value_str = glade_xml_get_content (col_node);
value = glade_utils_value_from_string
(g_type_from_name (column_type->type_name), value_str, widget->project, widget);
g_free (value_str);
data = glade_model_data_new (g_type_from_name (column_type->type_name),
column_type->column_name);
g_value_copy (value, &data->value);
g_value_unset (value);
g_free (value);
}
else
{
data = glade_model_data_new (G_TYPE_INVALID, column_type->column_name);
}
data->i18n_translatable = glade_xml_get_property_boolean (col_node, GLADE_TAG_TRANSLATABLE, FALSE);
data->i18n_context = glade_xml_get_property_string (col_node, GLADE_TAG_CONTEXT);
data->i18n_comment = glade_xml_get_property_string (col_node, GLADE_TAG_COMMENT);
item = g_node_new (data);
g_node_append (row, item);
/* dont increment colnum on invalid xml tags... */
colnum++;
}
}
if (data_tree->children)
glade_widget_property_set (widget, "data", data_tree);
glade_model_data_tree_free (data_tree);
}
void
glade_gtk_store_read_widget (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlNode *node)
{
if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
return;
/* First chain up and read in all the normal properties.. */
GWA_GET_CLASS (G_TYPE_OBJECT)->read_widget (adaptor, widget, node);
glade_gtk_store_read_columns (widget, node);
if (GTK_IS_LIST_STORE (widget->object))
glade_gtk_store_read_data (widget, node);
}
/*--------------------------- GtkCellRenderer ---------------------------------*/
static void glade_gtk_treeview_launch_editor (GObject *treeview);
void
glade_gtk_cell_renderer_action_activate (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *action_path)
{
if (strcmp (action_path, "launch_editor") == 0)
{
GladeWidget *w = glade_widget_get_from_gobject (object);
while ((w = glade_widget_get_parent (w)))
{
if (GTK_IS_TREE_VIEW (w->object))
{
glade_gtk_treeview_launch_editor (w->object);
break;
}
}
}
else
GWA_GET_CLASS (G_TYPE_OBJECT)->action_activate (adaptor,
object,
action_path);
}
void
glade_gtk_cell_renderer_deep_post_create (GladeWidgetAdaptor *adaptor,
GObject *object,
GladeCreateReason reason)
{
GladePropertyClass *pclass;
GladeProperty *property;
GladeWidget *widget;
GList *l;
widget = glade_widget_get_from_gobject (object);
for (l = adaptor->properties; l; l = l->next)
{
pclass = l->data;
if (strncmp (pclass->id, "use-attr-", strlen ("use-attr-")) == 0)
{
property = glade_widget_get_property (widget, pclass->id);
glade_property_sync (property);
}
}
g_idle_add ((GSourceFunc)glade_gtk_cell_renderer_sync_attributes, widget->object);
}
GladeEditorProperty *
glade_gtk_cell_renderer_create_eprop (GladeWidgetAdaptor *adaptor,
GladePropertyClass *klass,
gboolean use_command)
{
GladeEditorProperty *eprop;
if (strncmp (klass->id, "attr-", strlen ("attr-")) == 0)
eprop = g_object_new (GLADE_TYPE_EPROP_CELL_ATTRIBUTE,
"property-class", klass,
"use-command", use_command,
NULL);
else
eprop = GWA_GET_CLASS
(G_TYPE_OBJECT)->create_eprop (adaptor,
klass,
use_command);
return eprop;
}
GladeEditable *
glade_gtk_cell_renderer_create_editable (GladeWidgetAdaptor *adaptor,
GladeEditorPageType type)
{
GladeEditable *editable;
/* Get base editable */
editable = GWA_GET_CLASS (G_TYPE_OBJECT)->create_editable (adaptor, type);
if (type == GLADE_PAGE_GENERAL || type == GLADE_PAGE_COMMON)
return (GladeEditable *)glade_cell_renderer_editor_new (adaptor, type, editable);
return editable;
}
static void
glade_gtk_cell_renderer_set_use_attribute (GObject *object,
const gchar *property_name,
const GValue *value)
{
GladeWidget *widget = glade_widget_get_from_gobject (object);
gchar *attr_prop_name, *prop_msg, *attr_msg;
attr_prop_name = g_strdup_printf ("attr-%s", property_name);
prop_msg = g_strdup_printf (_("%s is set to load %s from the model"),
widget->name, property_name);
attr_msg = g_strdup_printf (_("%s is set to manipulate %s directly"),
widget->name, attr_prop_name);
glade_widget_property_set_sensitive (widget, property_name, FALSE, prop_msg);
glade_widget_property_set_sensitive (widget, attr_prop_name, FALSE, attr_msg);
if (g_value_get_boolean (value))
glade_widget_property_set_sensitive (widget, attr_prop_name, TRUE, NULL);
else
{
GladeProperty *property = glade_widget_get_property (widget, property_name);
glade_property_set_sensitive (property, TRUE, NULL);
glade_property_sync (property);
}
g_free (prop_msg);
g_free (attr_msg);
g_free (attr_prop_name);
}
static GladeProperty *
glade_gtk_cell_renderer_attribute_switch (GladeWidget *gwidget,
const gchar *property_name)
{
GladeProperty *property;
gchar *use_attr_name = g_strdup_printf ("use-attr-%s", property_name);
property = glade_widget_get_property (gwidget, use_attr_name);
g_free (use_attr_name);
return property;
}
static gboolean
glade_gtk_cell_renderer_property_enabled (GObject *object,
const gchar *property_name)
{
GladeProperty *property;
GladeWidget *gwidget = glade_widget_get_from_gobject (object);
gboolean use_attr = TRUE;
if ((property =
glade_gtk_cell_renderer_attribute_switch (gwidget, property_name)) != NULL)
glade_property_get (property, &use_attr);
return !use_attr;
}
void
glade_gtk_cell_renderer_set_property (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *property_name,
const GValue *value)
{
static gint use_attr_len = 0;
static gint attr_len = 0;
if (!attr_len)
{
use_attr_len = strlen ("use-attr-");
attr_len = strlen ("attr-");
}
if (strncmp (property_name, "use-attr-", use_attr_len) == 0)
glade_gtk_cell_renderer_set_use_attribute (object, &property_name[use_attr_len], value);
else if (strncmp (property_name, "attr-", attr_len) == 0)
glade_gtk_cell_renderer_sync_attributes (object);
else if (glade_gtk_cell_renderer_property_enabled (object, property_name))
/* Chain Up */
GWA_GET_CLASS (G_TYPE_OBJECT)->set_property (adaptor,
object,
property_name,
value);
}
static void
glade_gtk_cell_renderer_write_properties (GladeWidget *widget,
GladeXmlContext *context,
GladeXmlNode *node)
{
GladeProperty *property, *prop;
gchar *attr_name;
GList *l;
static gint attr_len = 0;
if (!attr_len)
attr_len = strlen ("attr-");
for (l = widget->properties; l; l = l->next)
{
property = l->data;
if (strncmp (property->klass->id, "attr-", attr_len) == 0)
{
gchar *use_attr_str;
gboolean use_attr = FALSE;
use_attr_str = g_strdup_printf ("use-%s", property->klass->id);
glade_widget_property_get (widget, use_attr_str, &use_attr);
attr_name = &property->klass->id[attr_len];
prop = glade_widget_get_property (widget, attr_name);
if (!use_attr && prop)
glade_property_write (prop, context, node);
g_free (use_attr_str);
}
}
}
void
glade_gtk_cell_renderer_write_widget (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlContext *context,
GladeXmlNode *node)
{
if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
return;
/* Write our normal properties, then chain up to write any other normal properties,
* then attributes
*/
glade_gtk_cell_renderer_write_properties (widget, context, node);
GWA_GET_CLASS (G_TYPE_OBJECT)->write_widget (adaptor, widget, context, node);
}
static void
glade_gtk_cell_renderer_parse_finished (GladeProject *project,
GladeWidget *widget)
{
GladeProperty *property;
GList *l;
static gint attr_len = 0, use_attr_len = 0;
/* Set "use-attr-*" everywhere that the object property is non-default
*
* We do this in the finished handler because some properties may be
* object type properties (which may be anywhere in the glade file).
*/
if (!attr_len)
{
attr_len = strlen ("attr-");
use_attr_len = strlen ("use-attr-");
}
for (l = widget->properties; l; l = l->next)
{
GladeProperty *switch_prop;
property = l->data;
if (strncmp (property->klass->id, "attr-", attr_len) != 0 &&
strncmp (property->klass->id, "use-attr-", use_attr_len) != 0 &&
(switch_prop =
glade_gtk_cell_renderer_attribute_switch (widget, property->klass->id)) != NULL)
{
if (glade_property_original_default (property))
glade_property_set (switch_prop, TRUE);
else
glade_property_set (switch_prop, FALSE);
}
}
}
void
glade_gtk_cell_renderer_read_widget (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlNode *node)
{
if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
return;
/* First chain up and read in all the properties... */
GWA_GET_CLASS (G_TYPE_OBJECT)->read_widget (adaptor, widget, node);
g_signal_connect (widget->project, "parse-finished",
G_CALLBACK (glade_gtk_cell_renderer_parse_finished),
widget);
}
/*--------------------------- GtkCellLayout ---------------------------------*/
void
glade_gtk_cell_layout_add_child (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *child)
{
GladeWidget *gmodel = NULL;
GladeWidget *grenderer = glade_widget_get_from_gobject (child);
if (GTK_IS_ICON_VIEW (container) &&
(gmodel = glade_cell_renderer_get_model (grenderer)) != NULL)
gtk_icon_view_set_model (GTK_ICON_VIEW (container), NULL);
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (container), GTK_CELL_RENDERER (child), TRUE);
if (gmodel)
gtk_icon_view_set_model (GTK_ICON_VIEW (container), GTK_TREE_MODEL (gmodel->object));
glade_gtk_cell_renderer_sync_attributes (child);
}
void
glade_gtk_cell_layout_remove_child (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *child)
{
GtkCellLayout *layout = GTK_CELL_LAYOUT (container);
GList *l, *children = gtk_cell_layout_get_cells (layout);
/* Add a reference to every cell except the one we want to remove */
for (l = children; l; l = g_list_next (l))
if (l->data != child)
g_object_ref (l->data);
else
l->data = NULL;
/* remove every cell */
gtk_cell_layout_clear (layout);
/* pack others cell renderers */
for (l = children; l; l = g_list_next (l))
{
if (l->data == NULL) continue;
gtk_cell_layout_pack_start (layout,
GTK_CELL_RENDERER (l->data), TRUE);
/* Remove our transient reference */
g_object_unref (l->data);
}
g_list_free (children);
}
GList *
glade_gtk_cell_layout_get_children (GladeWidgetAdaptor *adaptor,
GObject *container)
{
return gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (container));
}
void
glade_gtk_cell_layout_get_child_property (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *child,
const gchar *property_name,
GValue *value)
{
if (strcmp (property_name, "position") == 0)
{
GList *cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (container));
/* We have to fake it, assume we are loading and always return the last item */
g_value_set_int (value, g_list_length (cells) - 1);
g_list_free (cells);
}
else
/* Chain Up */
GWA_GET_CLASS
(GTK_TYPE_CONTAINER)->child_get_property (adaptor,
container, child,
property_name, value);
}
void
glade_gtk_cell_layout_set_child_property (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *child,
const gchar *property_name,
const GValue *value)
{
if (strcmp (property_name, "position") == 0)
{
/* Need verify on position property !!! XXX */
gtk_cell_layout_reorder (GTK_CELL_LAYOUT (container), GTK_CELL_RENDERER (child),
g_value_get_int (value));
}
else
/* Chain Up */
GWA_GET_CLASS
(GTK_TYPE_CONTAINER)->child_set_property (adaptor,
container, child,
property_name, value);
}
static void
glade_gtk_cell_renderer_read_attributes (GladeWidget *widget, GladeXmlNode *node)
{
GladeXmlNode *attrs_node;
GladeProperty *attr_prop, *use_attr_prop;
GladeXmlNode *prop;
gchar *name, *column_str, *attr_prop_name, *use_attr_name;
if ((attrs_node = glade_xml_search_child (node, GLADE_TAG_ATTRIBUTES)) == NULL)
return;
for (prop = glade_xml_node_get_children (attrs_node); prop;
prop = glade_xml_node_next (prop))
{
if (!glade_xml_node_verify_silent (prop, GLADE_TAG_ATTRIBUTE)) continue;
name = glade_xml_get_property_string_required (prop, GLADE_TAG_NAME, NULL);
column_str = glade_xml_get_content (prop);
attr_prop_name = g_strdup_printf ("attr-%s", name);
use_attr_name = g_strdup_printf ("use-attr-%s", name);
attr_prop = glade_widget_get_property (widget, attr_prop_name);
use_attr_prop = glade_widget_get_property (widget, use_attr_name);
if (attr_prop && use_attr_prop)
{
gboolean use_attribute = FALSE;
glade_property_get (use_attr_prop, &use_attribute);
if (use_attribute)
glade_property_set (attr_prop, g_ascii_strtoll (column_str, NULL, 10));
}
g_free (name);
g_free (column_str);
g_free (attr_prop_name);
g_free (use_attr_name);
}
}
void
glade_gtk_cell_layout_read_child (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlNode *node)
{
GladeXmlNode *widget_node;
GladeWidget *child_widget;
gchar *internal_name;
if (!glade_xml_node_verify (node, GLADE_XML_TAG_CHILD))
return;
internal_name = glade_xml_get_property_string (node, GLADE_XML_TAG_INTERNAL_CHILD);
if ((widget_node =
glade_xml_search_child (node, GLADE_XML_TAG_WIDGET)) != NULL)
{
if (internal_name)
g_warning ("Cell layout reading internal %s\n", internal_name);
/* Combo box is a special brand of cell-layout, it can also have the internal entry */
if ((child_widget = glade_widget_read (widget->project,
widget, widget_node,
internal_name)) != NULL)
{
/* Dont set any packing properties on internal children here,
* its possible but just not relevant for known celllayouts...
* i.e. maybe GtkTreeViewColumn will expose the internal button ?
* but no need for packing properties there either.
*/
if (!internal_name)
{
glade_widget_add_child (widget, child_widget, FALSE);
glade_gtk_cell_renderer_read_attributes (child_widget, node);
g_idle_add ((GSourceFunc)glade_gtk_cell_renderer_sync_attributes,
child_widget->object);
}
}
}
g_free (internal_name);
}
static void
glade_gtk_cell_renderer_write_attributes (GladeWidget *widget,
GladeXmlContext *context,
GladeXmlNode *node)
{
GladeProperty *property;
GladeXmlNode *attrs_node;
gchar *attr_name;
GList *l;
static gint attr_len = 0;
if (!attr_len)
attr_len = strlen ("attr-");
attrs_node = glade_xml_node_new (context, GLADE_TAG_ATTRIBUTES);
for (l = widget->properties; l; l = l->next)
{
property = l->data;
if (strncmp (property->klass->id, "attr-", attr_len) == 0)
{
GladeXmlNode *attr_node;
gchar *column_str, *use_attr_str;
gboolean use_attr = FALSE;
use_attr_str = g_strdup_printf ("use-%s", property->klass->id);
glade_widget_property_get (widget, use_attr_str, &use_attr);
if (use_attr && g_value_get_int (property->value) >= 0)
{
column_str = g_strdup_printf ("%d", g_value_get_int (property->value));
attr_name = &property->klass->id[attr_len];
attr_node = glade_xml_node_new (context, GLADE_TAG_ATTRIBUTE);
glade_xml_node_append_child (attrs_node, attr_node);
glade_xml_node_set_property_string (attr_node, GLADE_TAG_NAME,
attr_name);
glade_xml_set_content (attr_node, column_str);
g_free (column_str);
}
g_free (use_attr_str);
}
}
if (!glade_xml_node_get_children (attrs_node))
glade_xml_node_delete (attrs_node);
else
glade_xml_node_append_child (node, attrs_node);
}
void
glade_gtk_cell_layout_write_child (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlContext *context,
GladeXmlNode *node)
{
GladeXmlNode *child_node;
child_node = glade_xml_node_new (context, GLADE_XML_TAG_CHILD);
glade_xml_node_append_child (node, child_node);
/* ComboBox can have an internal entry */
if (widget->internal)
glade_xml_node_set_property_string (child_node,
GLADE_XML_TAG_INTERNAL_CHILD,
widget->internal);
/* Write out the widget */
glade_widget_write (widget, context, child_node);
glade_gtk_cell_renderer_write_attributes (widget, context, child_node);
}
static gchar *
glade_gtk_cell_layout_get_display_name (GladeBaseEditor *editor,
GladeWidget *gchild,
gpointer user_data)
{
GObject *child = glade_widget_get_object (gchild);
gchar *name;
if (GTK_IS_TREE_VIEW_COLUMN (child))
glade_widget_property_get (gchild, "title", &name);
else
name = gchild->name;
return g_strdup (name);
}
static void
glade_gtk_cell_layout_child_selected (GladeBaseEditor *editor,
GladeWidget *gchild,
gpointer data)
{
GObject *child = glade_widget_get_object (gchild);
glade_base_editor_add_label (editor, GTK_IS_TREE_VIEW_COLUMN (child) ?
_("Tree View Column") : _("Cell Renderer"));
glade_base_editor_add_default_properties (editor, gchild);
glade_base_editor_add_label (editor, GTK_IS_TREE_VIEW_COLUMN (child) ?
_("Properties") : _("Properties and Attributes"));
glade_base_editor_add_editable (editor, gchild, GLADE_PAGE_GENERAL);
if (GTK_IS_CELL_RENDERER (child))
{
glade_base_editor_add_label (editor, _("Common Properties and Attributes"));
glade_base_editor_add_editable (editor, gchild, GLADE_PAGE_COMMON);
}
}
static gboolean
glade_gtk_cell_layout_move_child (GladeBaseEditor *editor,
GladeWidget *gparent,
GladeWidget *gchild,
gpointer data)
{
GObject *parent = glade_widget_get_object (gparent);
GObject *child = glade_widget_get_object (gchild);
GList list = { 0, };
if (GTK_IS_TREE_VIEW (parent) && !GTK_IS_TREE_VIEW_COLUMN (child))
return FALSE;
if (GTK_IS_CELL_LAYOUT (parent) && !GTK_IS_CELL_RENDERER (child))
return FALSE;
if (GTK_IS_CELL_RENDERER (parent))
return FALSE;
if (gparent != glade_widget_get_parent (gchild))
{
list.data = gchild;
glade_command_dnd (&list, gparent, NULL);
}
return TRUE;
}
static void
glade_gtk_cell_layout_launch_editor (GObject *layout)
{
GladeWidget *widget = glade_widget_get_from_gobject (layout);
GladeBaseEditor *editor;
GladeEditable *layout_editor;
GtkWidget *window;
layout_editor = glade_widget_adaptor_create_editable (widget->adaptor, GLADE_PAGE_GENERAL);
layout_editor = (GladeEditable *)glade_tree_view_editor_new (widget->adaptor, layout_editor);
/* Editor */
editor = glade_base_editor_new (layout, layout_editor,
_("Text"), GTK_TYPE_CELL_RENDERER_TEXT,
_("Accelerator"), GTK_TYPE_CELL_RENDERER_ACCEL,
_("Combo"), GTK_TYPE_CELL_RENDERER_COMBO,
_("Spin"), GTK_TYPE_CELL_RENDERER_SPIN,
_("Pixbuf"), GTK_TYPE_CELL_RENDERER_PIXBUF,
_("Progress"), GTK_TYPE_CELL_RENDERER_PROGRESS,
_("Toggle"), GTK_TYPE_CELL_RENDERER_TOGGLE,
_("Spinner"), GTK_TYPE_CELL_RENDERER_SPINNER,
NULL);
g_signal_connect (editor, "get-display-name", G_CALLBACK (glade_gtk_cell_layout_get_display_name), NULL);
g_signal_connect (editor, "child-selected", G_CALLBACK (glade_gtk_cell_layout_child_selected), NULL);
g_signal_connect (editor, "move-child", G_CALLBACK (glade_gtk_cell_layout_move_child), NULL);
gtk_widget_show (GTK_WIDGET (editor));
window = glade_base_editor_pack_new_window (editor,
GTK_IS_ICON_VIEW (layout) ?
_("Icon View Editor") : _("Combo Editor"),
NULL);
gtk_widget_show (window);
}
static void
glade_gtk_cell_layout_launch_editor_action (GObject *object)
{
GladeWidget *w = glade_widget_get_from_gobject (object);
do
{
if (GTK_IS_TREE_VIEW (w->object))
{
glade_gtk_treeview_launch_editor (w->object);
break;
}
else if (GTK_IS_ICON_VIEW (w->object))
{
glade_gtk_cell_layout_launch_editor (w->object);
break;
}
else if (GTK_IS_COMBO_BOX (w->object))
{
glade_gtk_cell_layout_launch_editor (w->object);
break;
}
} while ((w = glade_widget_get_parent (w)));
}
void
glade_gtk_cell_layout_action_activate (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *action_path)
{
if (strcmp (action_path, "launch_editor") == 0)
glade_gtk_cell_layout_launch_editor_action (object);
else
GWA_GET_CLASS (G_TYPE_OBJECT)->action_activate (adaptor,
object,
action_path);
}
void
glade_gtk_cell_layout_action_activate_as_widget (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *action_path)
{
if (strcmp (action_path, "launch_editor") == 0)
glade_gtk_cell_layout_launch_editor_action (object);
else
GWA_GET_CLASS (GTK_TYPE_WIDGET)->action_activate (adaptor,
object,
action_path);
}
/*--------------------------- GtkTreeView ---------------------------------*/
static void
glade_gtk_treeview_launch_editor (GObject *treeview)
{
GladeWidget *widget = glade_widget_get_from_gobject (treeview);
GladeBaseEditor *editor;
GladeEditable *treeview_editor;
GtkWidget *window;
treeview_editor = glade_widget_adaptor_create_editable (widget->adaptor, GLADE_PAGE_GENERAL);
treeview_editor = (GladeEditable *)glade_tree_view_editor_new (widget->adaptor, treeview_editor);
/* Editor */
editor = glade_base_editor_new (treeview, treeview_editor,
_("Column"), GTK_TYPE_TREE_VIEW_COLUMN,
NULL);
glade_base_editor_append_types (editor, GTK_TYPE_TREE_VIEW_COLUMN,
_("Text"), GTK_TYPE_CELL_RENDERER_TEXT,
_("Accelerator"), GTK_TYPE_CELL_RENDERER_ACCEL,
_("Combo"), GTK_TYPE_CELL_RENDERER_COMBO,
_("Spin"), GTK_TYPE_CELL_RENDERER_SPIN,
_("Pixbuf"), GTK_TYPE_CELL_RENDERER_PIXBUF,
_("Progress"), GTK_TYPE_CELL_RENDERER_PROGRESS,
_("Toggle"), GTK_TYPE_CELL_RENDERER_TOGGLE,
_("Spinner"), GTK_TYPE_CELL_RENDERER_SPINNER,
NULL);
g_signal_connect (editor, "get-display-name", G_CALLBACK (glade_gtk_cell_layout_get_display_name), NULL);
g_signal_connect (editor, "child-selected", G_CALLBACK (glade_gtk_cell_layout_child_selected), NULL);
g_signal_connect (editor, "move-child", G_CALLBACK (glade_gtk_cell_layout_move_child), NULL);
gtk_widget_show (GTK_WIDGET (editor));
window = glade_base_editor_pack_new_window (editor, _("Tree View Editor"), NULL);
gtk_widget_show (window);
}
void
glade_gtk_treeview_action_activate (GladeWidgetAdaptor *adaptor,
GObject *object,
const gchar *action_path)
{
if (strcmp (action_path, "launch_editor") == 0)
{
glade_gtk_treeview_launch_editor (object);
}
else
GWA_GET_CLASS (GTK_TYPE_CONTAINER)->action_activate (adaptor,
object,
action_path);
}
static gint
glade_gtk_treeview_get_column_index (GtkTreeView *view,
GtkTreeViewColumn *column)
{
GtkTreeViewColumn *iter;
gint i;
for (i = 0; (iter = gtk_tree_view_get_column (view, i)) != NULL; i++)
if (iter == column)
return i;
return -1;
}
void
glade_gtk_treeview_get_child_property (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *child,
const gchar *property_name,
GValue *value)
{
if (strcmp (property_name, "position") == 0)
g_value_set_int (value,
glade_gtk_treeview_get_column_index (GTK_TREE_VIEW (container),
GTK_TREE_VIEW_COLUMN (child)));
else
/* Chain Up */
GWA_GET_CLASS
(GTK_TYPE_CONTAINER)->child_get_property (adaptor,
container, child,
property_name, value);
}
void
glade_gtk_treeview_set_child_property (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *child,
const gchar *property_name,
const GValue *value)
{
if (strcmp (property_name, "position") == 0)
{
gtk_tree_view_remove_column (GTK_TREE_VIEW (container),
GTK_TREE_VIEW_COLUMN (child));
gtk_tree_view_insert_column (GTK_TREE_VIEW (container),
GTK_TREE_VIEW_COLUMN (child),
g_value_get_int (value));
}
else
/* Chain Up */
GWA_GET_CLASS
(GTK_TYPE_CONTAINER)->child_set_property (adaptor,
container, child,
property_name, value);
}
GList *
glade_gtk_treeview_get_children (GladeWidgetAdaptor *adaptor,
GtkTreeView *view)
{
return gtk_tree_view_get_columns (view);
}
/* XXX FIXME: We should hide the actual "fixed-height-mode" setting from
* treeview editors and provide a custom control that sets all its columns
* to fixed size and then control the column's sensitivity accordingly.
*/
#define INSENSITIVE_COLUMN_SIZING_MSG \
_("Columns must have a fixed size inside a treeview with fixed height mode set")
void
glade_gtk_treeview_add_child (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *child)
{
GtkTreeView *view = GTK_TREE_VIEW (container);
GtkTreeViewColumn *column;
GladeWidget *gcolumn;
if (!GTK_IS_TREE_VIEW_COLUMN (child))
return;
if (gtk_tree_view_get_fixed_height_mode (view))
{
gcolumn = glade_widget_get_from_gobject (child);
glade_widget_property_set (gcolumn, "sizing", GTK_TREE_VIEW_COLUMN_FIXED);
glade_widget_property_set_sensitive (gcolumn, "sizing", FALSE,
INSENSITIVE_COLUMN_SIZING_MSG);
}
column = GTK_TREE_VIEW_COLUMN (child);
gtk_tree_view_append_column (view, column);
glade_gtk_cell_layout_sync_attributes (G_OBJECT (column));
}
void
glade_gtk_treeview_remove_child (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *child)
{
GtkTreeView *view = GTK_TREE_VIEW (container);
GtkTreeViewColumn *column;
if (!GTK_IS_TREE_VIEW_COLUMN (child))
return;
column = GTK_TREE_VIEW_COLUMN (child);
gtk_tree_view_remove_column (view, column);
}
void
glade_gtk_treeview_replace_child (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *current,
GObject *new_column)
{
GtkTreeView *view = GTK_TREE_VIEW (container);
GList *columns;
GtkTreeViewColumn *column;
GladeWidget *gcolumn;
gint index;
if (!GTK_IS_TREE_VIEW_COLUMN (current))
return;
column = GTK_TREE_VIEW_COLUMN (current);
columns = gtk_tree_view_get_columns (view);
index = g_list_index (columns, column);
g_list_free (columns);
gtk_tree_view_remove_column (view, column);
column = GTK_TREE_VIEW_COLUMN (new_column);
gtk_tree_view_insert_column (view, column, index);
if (gtk_tree_view_get_fixed_height_mode (view))
{
gcolumn = glade_widget_get_from_gobject (column);
glade_widget_property_set (gcolumn, "sizing", GTK_TREE_VIEW_COLUMN_FIXED);
glade_widget_property_set_sensitive (gcolumn, "sizing", FALSE,
INSENSITIVE_COLUMN_SIZING_MSG);
}
glade_gtk_cell_layout_sync_attributes (G_OBJECT (column));
}
gboolean
glade_gtk_treeview_depends (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeWidget *another)
{
if (GTK_IS_TREE_MODEL (another->object))
return TRUE;
return GWA_GET_CLASS (GTK_TYPE_CONTAINER)->depends (adaptor, widget, another);
}
/*--------------------------- GtkAdjustment ---------------------------------*/
void
glade_gtk_adjustment_write_widget (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlContext *context,
GladeXmlNode *node)
{
GladeProperty *prop;
if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
return;
/* Ensure proper order of adjustment properties by writing them here. */
prop = glade_widget_get_property (widget, "lower");
glade_property_write (prop, context, node);
prop = glade_widget_get_property (widget, "upper");
glade_property_write (prop, context, node);
prop = glade_widget_get_property (widget, "value");
glade_property_write (prop, context, node);
GWA_GET_CLASS (G_TYPE_OBJECT)->write_widget (adaptor, widget, context, node);
}
/*--------------------------- GtkAction ---------------------------------*/
void
glade_gtk_action_post_create (GladeWidgetAdaptor *adaptor,
GObject *object,
GladeCreateReason reason)
{
GladeWidget *gwidget = glade_widget_get_from_gobject (object);
if (reason == GLADE_CREATE_REBUILD)
return;
if (!gtk_action_get_name (GTK_ACTION (object)))
glade_widget_property_set (gwidget, "name", "untitled");
}
/*--------------------------- GtkActionGroup ---------------------------------*/
void
glade_gtk_action_group_add_child (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *child)
{
if (GTK_IS_ACTION (child))
{
/* Dont really add/remove actions (because name conflicts inside groups)
*/
GladeWidget *ggroup = glade_widget_get_from_gobject (container);
GladeWidget *gaction = glade_widget_get_from_gobject (child);
GList *actions = g_object_get_data (G_OBJECT (ggroup), "glade-actions");
actions = g_list_copy (actions);
actions = g_list_prepend (actions, child);
g_object_set_data_full (G_OBJECT (ggroup), "glade-actions", actions,
(GDestroyNotify)g_list_free);
glade_widget_property_set_sensitive (gaction, "accelerator", TRUE, NULL);
}
}
void
glade_gtk_action_group_remove_child (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *child)
{
if (GTK_IS_ACTION (child))
{
/* Dont really add/remove actions (because name conflicts inside groups)
*/
const gchar *insensitive_msg = _("The accelerator can only be set when inside an Action Group.");
GladeWidget *ggroup = glade_widget_get_from_gobject (container);
GladeWidget *gaction = glade_widget_get_from_gobject (child);
GList *actions = g_object_get_data (G_OBJECT (ggroup), "glade-actions");
actions = g_list_copy (actions);
actions = g_list_remove (actions, child);
g_object_set_data_full (G_OBJECT (ggroup), "glade-actions", actions,
(GDestroyNotify)g_list_free);
glade_widget_property_set_sensitive (gaction, "accelerator", FALSE, insensitive_msg);
}
}
void
glade_gtk_action_group_replace_child (GladeWidgetAdaptor *adaptor,
GObject *container,
GObject *current,
GObject *new_action)
{
glade_gtk_action_group_remove_child (adaptor, container, current);
glade_gtk_action_group_add_child (adaptor, container, new_action);
}
GList *
glade_gtk_action_group_get_children (GladeWidgetAdaptor *adaptor,
GObject *container)
{
GladeWidget *ggroup = glade_widget_get_from_gobject (container);
GList *actions = g_object_get_data (G_OBJECT (ggroup), "glade-actions");
return g_list_copy (actions);
}
void
glade_gtk_action_group_read_child (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlNode *node)
{
GladeXmlNode *widget_node;
GladeWidget *child_widget;
if (!glade_xml_node_verify (node, GLADE_XML_TAG_CHILD))
return;
if ((widget_node =
glade_xml_search_child (node, GLADE_XML_TAG_WIDGET)) != NULL)
{
if ((child_widget = glade_widget_read (widget->project,
widget, widget_node,
NULL)) != NULL)
{
glade_widget_add_child (widget, child_widget, FALSE);
/* Read in accelerator */
glade_gtk_read_accels (child_widget, node, FALSE);
}
}
}
void
glade_gtk_action_group_write_child (GladeWidgetAdaptor *adaptor,
GladeWidget *widget,
GladeXmlContext *context,
GladeXmlNode *node)
{
GladeXmlNode *child_node;
child_node = glade_xml_node_new (context, GLADE_XML_TAG_CHILD);
glade_xml_node_append_child (node, child_node);
/* Write out the widget */
glade_widget_write (widget, context, child_node);
/* Write accelerator here */
glade_gtk_write_accels (widget, context, child_node, FALSE);
}