diff options
Diffstat (limited to 'lib/egg/egg-menu-merge.c')
-rw-r--r-- | lib/egg/egg-menu-merge.c | 1320 |
1 files changed, 0 insertions, 1320 deletions
diff --git a/lib/egg/egg-menu-merge.c b/lib/egg/egg-menu-merge.c deleted file mode 100644 index cc39fe9d5..000000000 --- a/lib/egg/egg-menu-merge.c +++ /dev/null @@ -1,1320 +0,0 @@ -#include <string.h> -#include "egg-menu-merge.h" -#include "eggtoolbar.h" -#include "eggseparatortoolitem.h" -#include "eggintl.h" - -#define NODE_INFO(node) ((EggMenuMergeNode *)node->data) - -typedef struct { - guint merge_id; - GQuark action_quark; -} NodeUIReference; - -static void egg_menu_merge_class_init (EggMenuMergeClass *class); -static void egg_menu_merge_init (EggMenuMerge *merge); - -static void egg_menu_merge_queue_update (EggMenuMerge *self); -static void egg_menu_merge_dirty_all (EggMenuMerge *self); - -static GNode *get_child_node (EggMenuMerge *self, GNode *parent, - const gchar *childname, - gint childname_length, - EggMenuMergeNodeType node_type, - gboolean create, gboolean top); -static GNode *egg_menu_merge_get_node (EggMenuMerge *self, - const gchar *path, - EggMenuMergeNodeType node_type, - gboolean create); -static guint egg_menu_merge_next_merge_id (EggMenuMerge *self); - -static void egg_menu_merge_node_prepend_ui_reference (EggMenuMergeNode *node, - guint merge_id, - GQuark action_quark); -static void egg_menu_merge_node_remove_ui_reference (EggMenuMergeNode *node, - guint merge_id); - -enum { - ADD_WIDGET, - REMOVE_WIDGET, - LAST_SIGNAL -}; - -static guint merge_signals[LAST_SIGNAL] = { 0 }; - -static GMemChunk *merge_node_chunk = NULL; - -GType -egg_menu_merge_get_type (void) -{ - static GtkType type = 0; - - if (!type) - { - static const GTypeInfo type_info = - { - sizeof (EggMenuMergeClass), - (GBaseInitFunc) NULL, - (GBaseFinalizeFunc) NULL, - (GClassInitFunc) egg_menu_merge_class_init, - (GClassFinalizeFunc) NULL, - NULL, - - sizeof (EggMenuMerge), - 0, /* n_preallocs */ - (GInstanceInitFunc) egg_menu_merge_init, - }; - - type = g_type_register_static (G_TYPE_OBJECT, - "EggMenuMerge", - &type_info, 0); - } - return type; -} - -static GObjectClass *parent_class = NULL; - -static void -egg_menu_merge_finalize (GObject *object) -{ - EggMenuMerge *merge; - - merge = EGG_MENU_MERGE (object); - if (merge->update_tag != 0) - { - g_source_remove(merge->update_tag); - } -} - -static void -egg_menu_merge_class_init (EggMenuMergeClass *class) -{ - GObjectClass *object_class; - - parent_class = g_type_class_peek_parent (class); - object_class = G_OBJECT_CLASS(class); - - object_class->finalize = egg_menu_merge_finalize; - - if (!merge_node_chunk) - merge_node_chunk = g_mem_chunk_create(EggMenuMergeNode, 64, - G_ALLOC_AND_FREE); - - merge_signals[ADD_WIDGET] = - g_signal_new ("add_widget", - G_OBJECT_CLASS_TYPE (class), - G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE, - G_STRUCT_OFFSET (EggMenuMergeClass, add_widget), NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, - GTK_TYPE_WIDGET); - merge_signals[REMOVE_WIDGET] = - g_signal_new ("remove_widget", - G_OBJECT_CLASS_TYPE (class), - G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE, - G_STRUCT_OFFSET (EggMenuMergeClass, remove_widget), NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, - GTK_TYPE_WIDGET); - -} - - -static void -egg_menu_merge_init (EggMenuMerge *self) -{ - guint merge_id; - GNode *node; - - self->accel_group = gtk_accel_group_new(); - - self->root_node = NULL; - self->action_groups = NULL; - - self->last_merge_id = 0; - - - merge_id = egg_menu_merge_next_merge_id(self); - node = get_child_node(self, NULL, "Root", 4, - EGG_MENU_MERGE_ROOT, TRUE, FALSE); - egg_menu_merge_node_prepend_ui_reference(NODE_INFO(node), merge_id, 0); - node = get_child_node(self, self->root_node, "popups", 6, - EGG_MENU_MERGE_POPUPS, TRUE, FALSE); - egg_menu_merge_node_prepend_ui_reference(NODE_INFO(node), merge_id, 0); -} - -EggMenuMerge * -egg_menu_merge_new (void) -{ - return g_object_new(EGG_TYPE_MENU_MERGE, NULL); -} - -void -egg_menu_merge_insert_action_group (EggMenuMerge *self, - EggActionGroup *action_group, gint pos) -{ - g_return_if_fail (EGG_IS_MENU_MERGE(self)); - g_return_if_fail (EGG_IS_ACTION_GROUP(action_group)); - g_return_if_fail (g_list_find(self->action_groups, action_group) == NULL); - - g_object_ref(action_group); - self->action_groups = g_list_insert(self->action_groups, action_group, pos); - - /* dirty all nodes, as action bindings may change */ - egg_menu_merge_dirty_all(self); -} - -void -egg_menu_merge_remove_action_group (EggMenuMerge *self, - EggActionGroup *action_group) -{ - g_return_if_fail (EGG_IS_MENU_MERGE(self)); - g_return_if_fail (EGG_IS_ACTION_GROUP(action_group)); - g_return_if_fail (g_list_find(self->action_groups, action_group) != NULL); - - self->action_groups = g_list_remove(self->action_groups, action_group); - g_object_unref(action_group); - - /* dirty all nodes, as action bindings may change */ - egg_menu_merge_dirty_all(self); -} - -GtkWidget * -egg_menu_merge_get_widget (EggMenuMerge *self, const gchar *path) -{ - GNode *node; - - /* ensure that there are no pending updates before we get the - * widget */ - egg_menu_merge_ensure_update(self); - - node = egg_menu_merge_get_node(self, path, EGG_MENU_MERGE_UNDECIDED, FALSE); - return NODE_INFO(node)->proxy; -} - -static GNode * -get_child_node(EggMenuMerge *self, GNode *parent, - const gchar *childname, gint childname_length, - EggMenuMergeNodeType node_type, - gboolean create, gboolean top) -{ - GNode *child = NULL; - - g_return_val_if_fail(parent == NULL || - (NODE_INFO(parent)->type != EGG_MENU_MERGE_MENUITEM && - NODE_INFO(parent)->type != EGG_MENU_MERGE_TOOLITEM), NULL); - - if (parent) - { - if (childname) - { - for (child = parent->children; child != NULL; child = child->next) - { - if (strlen(NODE_INFO(child)->name) == childname_length && - !strncmp(NODE_INFO(child)->name, childname, childname_length)) - { - /* if undecided about node type, set it */ - if (NODE_INFO(child)->type == EGG_MENU_MERGE_UNDECIDED) - NODE_INFO(child)->type = node_type; - return child; - } - } - } - if (!child && create) - { - EggMenuMergeNode *mnode; - - mnode = g_chunk_new0(EggMenuMergeNode, merge_node_chunk); - mnode->type = node_type; - mnode->name = g_strndup(childname, childname_length); - mnode->dirty = TRUE; - - if (top) - child = g_node_prepend_data(parent, mnode); - else - child = g_node_append_data(parent, mnode); - } - } - else - { - /* handle root node */ - if (self->root_node) - { - child = self->root_node; - if (strncmp(NODE_INFO(child)->name, childname, childname_length) !=0) - g_warning("root node name '%s' doesn't match '%s'", - childname, NODE_INFO(child)->name); - if (NODE_INFO(child)->type != EGG_MENU_MERGE_ROOT) - g_warning("base element must be of type ROOT"); - } - else if (create) - { - EggMenuMergeNode *mnode; - - mnode = g_chunk_new0(EggMenuMergeNode, merge_node_chunk); - mnode->type = node_type; - mnode->name = g_strndup(childname, childname_length); - mnode->dirty = TRUE; - - child = self->root_node = g_node_new(mnode); - } - } - - return child; -} - -static GNode * -egg_menu_merge_get_node(EggMenuMerge *self, const gchar *path, - EggMenuMergeNodeType node_type, gboolean create) -{ - const gchar *pos, *end; - GNode *parent, *node; - - end = path + strlen(path); - pos = path; - parent = node = NULL; - while (pos < end) - { - const gchar *slash; - gsize length; - - slash = strchr(pos, '/'); - if (slash) - length = slash - pos; - else - length = strlen(pos); - - node = get_child_node(self, parent, pos, length, EGG_MENU_MERGE_UNDECIDED, - create, FALSE); - if (!node) - return NULL; - - pos += length + 1; /* move past the node name and the slash too */ - parent = node; - } - - if (NODE_INFO(node)->type == EGG_MENU_MERGE_UNDECIDED) - NODE_INFO(node)->type = node_type; - return node; -} - -static guint -egg_menu_merge_next_merge_id (EggMenuMerge *self) -{ - self->last_merge_id++; - - return self->last_merge_id; -} - -static void -egg_menu_merge_node_prepend_ui_reference (EggMenuMergeNode *node, - guint merge_id, GQuark action_quark) -{ - NodeUIReference *reference; - - reference = g_new (NodeUIReference, 1); - reference->action_quark = action_quark; - reference->merge_id = merge_id; - - /* Prepend the reference */ - node->uifiles = g_list_prepend (node->uifiles, reference); - - node->dirty = TRUE; -} - -static void -egg_menu_merge_node_remove_ui_reference (EggMenuMergeNode *node, - guint merge_id) -{ - GList *p; - - for (p = node->uifiles; p != NULL; p = p->next) - { - NodeUIReference *reference = p->data; - - if (reference->merge_id == merge_id) - { - node->uifiles = g_list_remove_link (node->uifiles, p); - node->dirty = TRUE; - g_free (reference); - - break; - } - } -} - -/* -------------------- The UI file parser -------------------- */ - -typedef enum { - STATE_START, - STATE_ROOT, - STATE_MENU, - STATE_TOOLBAR, - STATE_POPUPS, - STATE_MENUITEM, - STATE_TOOLITEM, - STATE_END -} ParseState; - -typedef struct _ParseContext ParseContext; -struct _ParseContext -{ - ParseState state; - ParseState prev_state; - - EggMenuMerge *self; - - GNode *current; - - guint merge_id; -}; - -static void -start_element_handler (GMarkupParseContext *context, - const gchar *element_name, - const gchar **attribute_names, - const gchar **attribute_values, - gpointer user_data, - GError **error) -{ - ParseContext *ctx = user_data; - EggMenuMerge *self = ctx->self; - - gint i; - const gchar *node_name; - GQuark verb_quark; - gboolean top; - - gboolean raise_error = TRUE; - gchar *error_attr = NULL; - - //g_message("starting element %s", element_name); - - /* work out a name for this node. Either the name attribute, or - * element name */ - node_name = element_name; - verb_quark = 0; - top = FALSE; - for (i = 0; attribute_names[i] != NULL; i++) - { - if (!strcmp(attribute_names[i], "name")) - { - node_name = attribute_values[i]; - } - else if (!strcmp(attribute_names[i], "verb")) - { - verb_quark = g_quark_from_string(attribute_values[i]); - } - else if (!strcmp(attribute_names[i], "pos")) - { - top = !strcmp(attribute_values[i], "top"); - } - } - /* if no verb, then set it to the node's name */ - if (verb_quark == 0) - verb_quark = g_quark_from_string(node_name); - - switch (element_name[0]) - { - case 'R': - if (ctx->state == STATE_START && !strcmp(element_name, "Root")) - { - ctx->state = STATE_ROOT; - ctx->current = self->root_node; - raise_error = FALSE; - - egg_menu_merge_node_prepend_ui_reference (NODE_INFO (ctx->current), - ctx->merge_id, verb_quark); - } - break; - case 'm': - if (ctx->state == STATE_ROOT && !strcmp(element_name, "menu")) - { - ctx->state = STATE_MENU; - ctx->current = get_child_node(self, ctx->current, - node_name, strlen(node_name), - EGG_MENU_MERGE_MENUBAR, - TRUE, FALSE); - if (NODE_INFO(ctx->current)->action_name == 0) - NODE_INFO(ctx->current)->action_name = verb_quark; - - egg_menu_merge_node_prepend_ui_reference (NODE_INFO (ctx->current), - ctx->merge_id, verb_quark); - NODE_INFO(ctx->current)->dirty = TRUE; - - raise_error = FALSE; - } - else if (ctx->state == STATE_MENU && !strcmp(element_name, "menuitem")) - { - GNode *node; - - ctx->state = STATE_MENUITEM; - node = get_child_node(self, ctx->current, - node_name, strlen(node_name), - EGG_MENU_MERGE_MENUITEM, - TRUE, top); - if (NODE_INFO(node)->action_name == 0) - NODE_INFO(node)->action_name = verb_quark; - - egg_menu_merge_node_prepend_ui_reference (NODE_INFO (node), - ctx->merge_id, verb_quark); - NODE_INFO(node)->dirty = TRUE; - - raise_error = FALSE; - } - break; - case 'd': - if (ctx->state == STATE_ROOT && !strcmp(element_name, "dockitem")) - { - ctx->state = STATE_TOOLBAR; - ctx->current = get_child_node(self, ctx->current, - node_name, strlen(node_name), - EGG_MENU_MERGE_TOOLBAR, - TRUE, FALSE); - if (NODE_INFO(ctx->current)->action_name == 0) - NODE_INFO(ctx->current)->action_name = verb_quark; - - egg_menu_merge_node_prepend_ui_reference (NODE_INFO (ctx->current), - ctx->merge_id, verb_quark); - NODE_INFO(ctx->current)->dirty = TRUE; - - raise_error = FALSE; - } - break; - case 'p': - if (ctx->state == STATE_ROOT && !strcmp(element_name, "popups")) - { - ctx->state = STATE_POPUPS; - ctx->current = get_child_node(self, ctx->current, - node_name, strlen(node_name), - EGG_MENU_MERGE_POPUPS, - TRUE, FALSE); - - egg_menu_merge_node_prepend_ui_reference (NODE_INFO (ctx->current), - ctx->merge_id, verb_quark); - NODE_INFO(ctx->current)->dirty = TRUE; - - raise_error = FALSE; - } - else if (ctx->state == STATE_POPUPS && !strcmp(element_name, "popup")) - { - ctx->state = STATE_MENU; - ctx->current = get_child_node(self, ctx->current, - node_name, strlen(node_name), - EGG_MENU_MERGE_MENU, - TRUE, FALSE); - if (NODE_INFO(ctx->current)->action_name == 0) - NODE_INFO(ctx->current)->action_name = verb_quark; - - egg_menu_merge_node_prepend_ui_reference (NODE_INFO (ctx->current), - ctx->merge_id, verb_quark); - NODE_INFO(ctx->current)->dirty = TRUE; - - raise_error = FALSE; - } - else if ((ctx->state == STATE_MENU || ctx->state == STATE_TOOLBAR) && - !strcmp(element_name, "placeholder")) - { - if (ctx->state == STATE_MENU) - ctx->current = get_child_node(self, ctx->current, - node_name, strlen(node_name), - EGG_MENU_MERGE_MENU_PLACEHOLDER, - TRUE, top); - else - ctx->current = get_child_node(self, ctx->current, - node_name, strlen(node_name), - EGG_MENU_MERGE_TOOLBAR_PLACEHOLDER, - TRUE, top); - - egg_menu_merge_node_prepend_ui_reference (NODE_INFO (ctx->current), - ctx->merge_id, verb_quark); - NODE_INFO(ctx->current)->dirty = TRUE; - - raise_error = FALSE; - } - break; - case 's': - if (ctx->state == STATE_MENU && !strcmp(element_name, "submenu")) - { - ctx->state = STATE_MENU; - ctx->current = get_child_node(self, ctx->current, - node_name, strlen(node_name), - EGG_MENU_MERGE_MENU, - TRUE, top); - if (NODE_INFO(ctx->current)->action_name == 0) - NODE_INFO(ctx->current)->action_name = verb_quark; - - egg_menu_merge_node_prepend_ui_reference (NODE_INFO (ctx->current), - ctx->merge_id, verb_quark); - NODE_INFO(ctx->current)->dirty = TRUE; - - raise_error = FALSE; - } - else if ((ctx->state == STATE_MENU || ctx->state == STATE_TOOLBAR) && - !strcmp(element_name, "separator")) - { - GNode *node; - - if (ctx->state == STATE_MENU) - ctx->state = STATE_MENUITEM; - else - ctx->state = STATE_TOOLITEM; - node = get_child_node(self, ctx->current, - node_name, strlen(node_name), - EGG_MENU_MERGE_SEPARATOR, - TRUE, top); - if (NODE_INFO(node)->action_name == 0) - NODE_INFO(node)->action_name = verb_quark; - - egg_menu_merge_node_prepend_ui_reference (NODE_INFO (node), - ctx->merge_id, verb_quark); - NODE_INFO(node)->dirty = TRUE; - - raise_error = FALSE; - } - break; - case 't': - if (ctx->state == STATE_TOOLBAR && !strcmp(element_name, "toolitem")) - { - GNode *node; - - ctx->state = STATE_TOOLITEM; - node = get_child_node(self, ctx->current, - node_name, strlen(node_name), - EGG_MENU_MERGE_TOOLITEM, - TRUE, top); - if (NODE_INFO(node)->action_name == 0) - NODE_INFO(node)->action_name = verb_quark; - - egg_menu_merge_node_prepend_ui_reference (NODE_INFO (node), - ctx->merge_id, verb_quark); - NODE_INFO(node)->dirty = TRUE; - - raise_error = FALSE; - } - break; - default: - break; - } - if (raise_error) - { - gint line_number, char_number; - - g_markup_parse_context_get_position (context, - &line_number, &char_number); - if (error_attr) - g_set_error (error, - G_MARKUP_ERROR, - G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, - _("Unknown attribute '%s' on line %d char %d"), - error_attr, - line_number, char_number); - else - g_set_error (error, - G_MARKUP_ERROR, - G_MARKUP_ERROR_UNKNOWN_ELEMENT, - _("Unknown tag '%s' on line %d char %d"), - element_name, - line_number, char_number); - } -} - -static void -end_element_handler (GMarkupParseContext *context, - const gchar *element_name, - gpointer user_data, - GError **error) -{ - ParseContext *ctx = user_data; - EggMenuMerge *self = ctx->self; - - //g_message("ending element %s (state=%d)", element_name, ctx->state); - - switch (ctx->state) - { - case STATE_START: - g_warning("shouldn't get any end tags in start state"); - /* should we GError here? */ - break; - case STATE_ROOT: - if (ctx->current != self->root_node) - g_warning("we are in STATE_ROOT, but the current node isn't the root"); - ctx->current = NULL; - ctx->state = STATE_END; - break; - case STATE_MENU: - ctx->current = ctx->current->parent; - if (NODE_INFO(ctx->current)->type == EGG_MENU_MERGE_ROOT) /* menubar */ - ctx->state = STATE_ROOT; - else if (NODE_INFO(ctx->current)->type == EGG_MENU_MERGE_POPUPS) /* popup */ - ctx->state = STATE_POPUPS; - /* else, stay in STATE_MENU state */ - break; - case STATE_TOOLBAR: - ctx->current = ctx->current->parent; - /* we conditionalise this test, in case we are closing off a - * placeholder */ - if (NODE_INFO(ctx->current)->type == EGG_MENU_MERGE_ROOT) - ctx->state = STATE_ROOT; - /* else, stay in STATE_TOOLBAR state */ - break; - case STATE_POPUPS: - ctx->current = ctx->current->parent; - ctx->state = STATE_ROOT; - break; - case STATE_MENUITEM: - ctx->state = STATE_MENU; - break; - case STATE_TOOLITEM: - ctx->state = STATE_TOOLBAR; - break; - case STATE_END: - g_warning("shouldn't get any end tags at this point"); - /* should do an error here */ - break; - } -} - -static void -cleanup (GMarkupParseContext *context, - GError *error, - gpointer user_data) -{ - ParseContext *ctx = user_data; - EggMenuMerge *self = ctx->self; - - ctx->current = NULL; - /* should also walk through the tree and get rid of nodes related to - * this UI file's tag */ - - egg_menu_merge_remove_ui (self, ctx->merge_id); -} - -static GMarkupParser ui_parser = { - start_element_handler, - end_element_handler, - NULL, - NULL, - cleanup -}; - -guint -egg_menu_merge_add_ui_from_string (EggMenuMerge *self, - const gchar *buffer, size_t length, - GError **error) -{ - ParseContext ctx = { 0 }; - GMarkupParseContext *context; - gboolean res = TRUE; - - g_return_val_if_fail(EGG_IS_MENU_MERGE(self), FALSE); - g_return_val_if_fail(buffer != NULL, FALSE); - - ctx.state = STATE_START; - ctx.self = self; - ctx.current = NULL; - ctx.merge_id = egg_menu_merge_next_merge_id (self); - - context = g_markup_parse_context_new(&ui_parser, 0, &ctx, NULL); - if (length < 0) - length = strlen(buffer); - - if (g_markup_parse_context_parse(context, buffer, length, error)) - { - if (!g_markup_parse_context_end_parse(context, error)) - res = FALSE; - } - else - res = FALSE; - - g_markup_parse_context_free (context); - - egg_menu_merge_queue_update(self); - - if (res) - return ctx.merge_id; - return 0; -} - -guint -egg_menu_merge_add_ui_from_file (EggMenuMerge *self, - const gchar *filename, - GError **error) -{ - gchar *buffer; - size_t length; - guint res; - - if (!g_file_get_contents (filename, &buffer, &length, error)) - return 0; - - res = egg_menu_merge_add_ui_from_string(self, buffer, length, error); - g_free(buffer); - - return res; -} - -static gboolean -remove_ui (GNode *node, gpointer user_data) -{ - guint merge_id = GPOINTER_TO_UINT (user_data); - - egg_menu_merge_node_remove_ui_reference (NODE_INFO (node), merge_id); - - return FALSE; /* continue */ -} - -void -egg_menu_merge_remove_ui (EggMenuMerge *self, guint merge_id) -{ - g_node_traverse(self->root_node, G_POST_ORDER, G_TRAVERSE_ALL, -1, - remove_ui, GUINT_TO_POINTER (merge_id)); - - egg_menu_merge_queue_update(self); -} - -/* -------------------- Updates -------------------- */ - - -static EggAction * -get_action_by_name (EggMenuMerge *merge, const char *action_name) -{ - GList *tmp; - - if (!action_name) - return NULL; - - /* lookup name */ - for (tmp = merge->action_groups; tmp != NULL; tmp = tmp->next) - { - EggActionGroup *action_group = tmp->data; - EggAction *action; - - action = egg_action_group_get_action (action_group, action_name); - - if (action) - return action; - } - - return NULL; -} - -static gboolean -find_menu_position (GNode *node, GtkWidget **menushell_p, gint *pos_p) -{ - GtkWidget *menushell; - gint pos; - - g_return_val_if_fail(node != NULL, FALSE); - g_return_val_if_fail(NODE_INFO(node)->type == EGG_MENU_MERGE_MENU || - NODE_INFO(node)->type == EGG_MENU_MERGE_MENU_PLACEHOLDER || - NODE_INFO(node)->type == EGG_MENU_MERGE_MENUITEM || - NODE_INFO(node)->type == EGG_MENU_MERGE_SEPARATOR, - FALSE); - - /* first sibling -- look at parent */ - if (node->prev == NULL) - { - GNode *parent; - - parent = node->parent; - switch (NODE_INFO(parent)->type) - { - case EGG_MENU_MERGE_MENUBAR: - menushell = NODE_INFO(parent)->proxy; - pos = 0; - break; - case EGG_MENU_MERGE_MENU: - menushell = NODE_INFO(parent)->proxy; - if (GTK_IS_MENU_ITEM(menushell)) - menushell = gtk_menu_item_get_submenu(GTK_MENU_ITEM(menushell)); - pos = 0; - break; - case EGG_MENU_MERGE_MENU_PLACEHOLDER: - menushell = gtk_widget_get_parent(NODE_INFO(parent)->proxy); - g_return_val_if_fail(GTK_IS_MENU_SHELL(menushell), FALSE); - pos = g_list_index(GTK_MENU_SHELL(menushell)->children, - NODE_INFO(parent)->proxy) + 1; - break; - default: - g_warning("%s: bad parent node type %d", G_STRLOC, - NODE_INFO(parent)->type); - return FALSE; - } - } - else - { - GtkWidget *prev_child; - GNode *sibling; - - sibling = node->prev; - if (NODE_INFO(sibling)->type == EGG_MENU_MERGE_MENU_PLACEHOLDER) - prev_child = NODE_INFO(sibling)->extra; /* second Separator */ - else - prev_child = NODE_INFO(sibling)->proxy; - - g_return_val_if_fail(GTK_IS_WIDGET(prev_child), FALSE); - menushell = gtk_widget_get_parent(prev_child); - g_return_val_if_fail(GTK_IS_MENU_SHELL(menushell), FALSE); - - pos = g_list_index(GTK_MENU_SHELL(menushell)->children, prev_child) + 1; - } - - if (menushell_p) - *menushell_p = menushell; - if (pos_p) - *pos_p = pos; - - return TRUE; -} - -static gboolean -find_toolbar_position (GNode *node, GtkWidget **toolbar_p, gint *pos_p) -{ - GtkWidget *toolbar; - gint pos; - - g_return_val_if_fail(node != NULL, FALSE); - g_return_val_if_fail(NODE_INFO(node)->type == EGG_MENU_MERGE_TOOLBAR || - NODE_INFO(node)->type == EGG_MENU_MERGE_TOOLBAR_PLACEHOLDER || - NODE_INFO(node)->type == EGG_MENU_MERGE_TOOLITEM || - NODE_INFO(node)->type == EGG_MENU_MERGE_SEPARATOR, - FALSE); - - /* first sibling -- look at parent */ - if (node->prev == NULL) - { - GNode *parent; - - parent = node->parent; - switch (NODE_INFO(parent)->type) - { - case EGG_MENU_MERGE_TOOLBAR: - toolbar = NODE_INFO(parent)->proxy; - pos = 0; - break; - case EGG_MENU_MERGE_TOOLBAR_PLACEHOLDER: - toolbar = gtk_widget_get_parent(NODE_INFO(parent)->proxy); - g_return_val_if_fail(EGG_IS_TOOLBAR(toolbar), FALSE); - pos = egg_toolbar_get_item_index (EGG_TOOLBAR(toolbar), - EGG_TOOL_ITEM (NODE_INFO(parent)->proxy)) + 1; - break; - default: - g_warning("%s: bad parent node type %d", G_STRLOC, - NODE_INFO(parent)->type); - return FALSE; - } - } - else - { - GtkWidget *prev_child; - GNode *sibling; - - sibling = node->prev; - if (NODE_INFO(sibling)->type == EGG_MENU_MERGE_TOOLBAR_PLACEHOLDER) - prev_child = NODE_INFO(sibling)->extra; /* second Separator */ - else - prev_child = NODE_INFO(sibling)->proxy; - - g_return_val_if_fail(GTK_IS_WIDGET(prev_child), FALSE); - toolbar = gtk_widget_get_parent(prev_child); - g_return_val_if_fail(EGG_IS_TOOLBAR(toolbar), FALSE); - - pos = egg_toolbar_get_item_index (EGG_TOOLBAR(toolbar), - EGG_TOOL_ITEM (prev_child)) + 1; - } - - if (toolbar_p) - *toolbar_p = toolbar; - if (pos_p) - *pos_p = pos; - - return TRUE; -} - -static void -update_node (EggMenuMerge *self, GNode *node) -{ - EggMenuMergeNode *info; - GNode *child; - EggAction *action; - - g_return_if_fail (node != NULL); - g_return_if_fail (NODE_INFO(node) != NULL); - - info = NODE_INFO(node); - - if (NODE_INFO(node)->dirty) - { - const gchar *action_name; - NodeUIReference *ref; - - if (info->uifiles == NULL) { - /* We may need to remove this node. - * This must be done in post order - */ - goto recurse_children; - } - - ref = info->uifiles->data; - action_name = g_quark_to_string (ref->action_quark); - action = get_action_by_name (self, action_name); - - NODE_INFO(node)->dirty = FALSE; - - /* Check if the node doesn't have an action and must have an action */ - if (action == NULL && - info->type != EGG_MENU_MERGE_MENUBAR && - info->type != EGG_MENU_MERGE_TOOLBAR && - info->type != EGG_MENU_MERGE_SEPARATOR && - info->type != EGG_MENU_MERGE_MENU_PLACEHOLDER && - info->type != EGG_MENU_MERGE_TOOLBAR_PLACEHOLDER) - { - /* FIXME: Should we warn here? */ - goto recurse_children; - } - - /* If the widget already has a proxy and the action hasn't changed, then - * we don't have to do anything. - */ - if (info->proxy != NULL && - action == info->action) - { - goto recurse_children; - } - - info->action = action; - - switch (info->type) - { - case EGG_MENU_MERGE_MENUBAR: - if (info->proxy == NULL) - { - info->proxy = gtk_menu_bar_new (); - gtk_widget_show (info->proxy); - g_signal_emit (self, merge_signals[ADD_WIDGET], 0, info->proxy); - } - break; - case EGG_MENU_MERGE_MENU: - { - GtkWidget *prev_submenu = NULL; - /* remove the proxy if it is of the wrong type ... */ - if (info->proxy && G_OBJECT_TYPE(info->proxy) != - EGG_ACTION_GET_CLASS(info->action)->menu_item_type) - { - prev_submenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(info->proxy)); - if (prev_submenu) - { - g_object_ref (prev_submenu); - gtk_menu_item_set_submenu(GTK_MENU_ITEM(info->proxy),NULL); - } - gtk_container_remove(GTK_CONTAINER(info->proxy->parent), - info->proxy); - info->proxy = NULL; - } - /* create proxy if needed ... */ - if (info->proxy == NULL) - { - GtkWidget *menushell; - gint pos; - GNode *parent; - - parent = node->parent; - - if (parent && NODE_INFO (parent)->type == EGG_MENU_MERGE_POPUPS) - { - info->proxy = gtk_menu_new(); - } - else if (find_menu_position(node, &menushell, &pos)) - { - GtkWidget *menu; - info->proxy = egg_action_create_menu_item (info->action); - menu = gtk_menu_new(); - gtk_menu_item_set_submenu(GTK_MENU_ITEM(info->proxy), menu); - gtk_menu_set_accel_group (GTK_MENU (menu), self->accel_group); - gtk_menu_shell_insert (GTK_MENU_SHELL (menushell), - info->proxy, pos); - } - } - else - { - egg_action_connect_proxy (info->action, info->proxy); - } - if (prev_submenu) - { - gtk_menu_item_set_submenu (GTK_MENU_ITEM (info->proxy), - prev_submenu); - g_object_unref (prev_submenu); - } - } - break; - case EGG_MENU_MERGE_UNDECIDED: - g_warning("found 'undecided node!"); - break; - case EGG_MENU_MERGE_ROOT: - break; - case EGG_MENU_MERGE_TOOLBAR: - if (info->proxy == NULL) - { - info->proxy = egg_toolbar_new (); - gtk_widget_show (info->proxy); - g_signal_emit (self, merge_signals[ADD_WIDGET], 0, info->proxy); - } - break; - case EGG_MENU_MERGE_MENU_PLACEHOLDER: - /* create menu items for placeholders if necessary ... */ - if (!GTK_IS_SEPARATOR_MENU_ITEM (info->proxy) || - !GTK_IS_SEPARATOR_MENU_ITEM (info->extra)) - { - if (info->proxy) - gtk_container_remove(GTK_CONTAINER(info->proxy->parent), - info->proxy); - if (info->extra) - gtk_container_remove(GTK_CONTAINER(info->extra->parent), - info->extra); - info->proxy = NULL; - info->extra = NULL; - } - if (info->proxy == NULL) - { - GtkWidget *menushell; - gint pos; - - if (find_menu_position(node, &menushell, &pos)) - { - NODE_INFO(node)->proxy = gtk_separator_menu_item_new(); - gtk_menu_shell_insert(GTK_MENU_SHELL(menushell), - NODE_INFO(node)->proxy, pos); - //gtk_widget_show(NODE_INFO(node)->proxy); - - NODE_INFO(node)->extra = gtk_separator_menu_item_new(); - gtk_menu_shell_insert(GTK_MENU_SHELL(menushell), - NODE_INFO(node)->extra, pos+1); - //gtk_widget_show(NODE_INFO(node)->extra); - } - } - break; - case EGG_MENU_MERGE_TOOLBAR_PLACEHOLDER: - /* create toolbar items for placeholders if necessary ... */ - if (!EGG_IS_SEPARATOR_TOOL_ITEM (info->proxy) || - !EGG_IS_SEPARATOR_TOOL_ITEM (info->extra)) - { - if (info->proxy) - gtk_container_remove(GTK_CONTAINER(info->proxy->parent), - info->proxy); - if (info->extra) - gtk_container_remove(GTK_CONTAINER(info->extra->parent), - info->extra); - info->proxy = NULL; - info->extra = NULL; - } - if (info->proxy == NULL) - { - GtkWidget *toolbar; - gint pos; - - if (find_toolbar_position(node, &toolbar, &pos)) - { - EggToolItem *item; - - item = egg_separator_tool_item_new(); - egg_toolbar_insert(EGG_TOOLBAR(toolbar), item, pos); - NODE_INFO(node)->proxy = GTK_WIDGET (item); - //gtk_widget_show(NODE_INFO(node)->proxy); - - item = egg_separator_tool_item_new(); - egg_toolbar_insert(EGG_TOOLBAR(toolbar), item, pos+1); - NODE_INFO(node)->extra = GTK_WIDGET (item); - //gtk_widget_show(NODE_INFO(node)->extra); - } - } - break; - case EGG_MENU_MERGE_POPUPS: - break; - case EGG_MENU_MERGE_MENUITEM: - /* remove the proxy if it is of the wrong type ... */ - if (info->proxy && G_OBJECT_TYPE(info->proxy) != - EGG_ACTION_GET_CLASS(info->action)->menu_item_type) - { - gtk_container_remove(GTK_CONTAINER(info->proxy->parent), - info->proxy); - info->proxy = NULL; - } - /* create proxy if needed ... */ - if (info->proxy == NULL) - { - GtkWidget *menushell; - gint pos; - - if (find_menu_position(node, &menushell, &pos)) - { - info->proxy = egg_action_create_menu_item (info->action); - - gtk_menu_shell_insert (GTK_MENU_SHELL (menushell), - info->proxy, pos); - } - } - else - { - gtk_menu_item_set_submenu(GTK_MENU_ITEM(info->proxy), NULL); - egg_action_connect_proxy (info->action, info->proxy); - } - break; - case EGG_MENU_MERGE_TOOLITEM: - /* remove the proxy if it is of the wrong type ... */ - if (info->proxy && G_OBJECT_TYPE(info->proxy) != - EGG_ACTION_GET_CLASS(info->action)->toolbar_item_type) - { - gtk_container_remove(GTK_CONTAINER(info->proxy->parent), - info->proxy); - info->proxy = NULL; - } - /* create proxy if needed ... */ - if (info->proxy == NULL) - { - GtkWidget *toolbar; - gint pos; - - if (find_toolbar_position(node, &toolbar, &pos)) - { - info->proxy = egg_action_create_tool_item (info->action); - - egg_toolbar_insert (EGG_TOOLBAR (toolbar), - EGG_TOOL_ITEM (info->proxy), pos); - } - } - else - { - egg_action_connect_proxy (info->action, info->proxy); - } - break; - case EGG_MENU_MERGE_SEPARATOR: - if (NODE_INFO (node->parent)->type == EGG_MENU_MERGE_TOOLBAR || - NODE_INFO (node->parent)->type == EGG_MENU_MERGE_TOOLBAR_PLACEHOLDER) - { - GtkWidget *toolbar; - gint pos; - - if (EGG_IS_SEPARATOR_TOOL_ITEM(info->proxy)) - { - gtk_container_remove(GTK_CONTAINER(info->proxy->parent), - info->proxy); - info->proxy = NULL; - } - - if (find_toolbar_position(node, &toolbar, &pos)) - { - EggToolItem *item = egg_separator_tool_item_new(); - egg_toolbar_insert (EGG_TOOLBAR (toolbar), item, pos); - info->proxy = GTK_WIDGET (item); - gtk_widget_show(info->proxy); - } - } - else - { - GtkWidget *menushell; - gint pos; - - if (GTK_IS_SEPARATOR_MENU_ITEM(info->proxy)) - { - gtk_container_remove(GTK_CONTAINER(info->proxy->parent), - info->proxy); - info->proxy = NULL; - } - - if (find_menu_position(node, &menushell, &pos)) - { - info->proxy = gtk_separator_menu_item_new(); - gtk_menu_shell_insert (GTK_MENU_SHELL (menushell), - info->proxy, pos); - gtk_widget_show(info->proxy); - } - } - break; - } - - /* if this node has a widget, but it is the wrong type, remove it */ - } - - recurse_children: - /* process children */ - child = node->children; - while (child) - { - GNode *current; - - current = child; - child = current->next; - update_node (self, current); - } - - /* handle cleanup of dead nodes */ - if (node->children == NULL && NODE_INFO(node)->uifiles == NULL) - { - if (NODE_INFO(node)->proxy) - gtk_widget_destroy(NODE_INFO(node)->proxy); - if ((NODE_INFO(node)->type == EGG_MENU_MERGE_MENU_PLACEHOLDER || - NODE_INFO(node)->type == EGG_MENU_MERGE_TOOLBAR_PLACEHOLDER) && - NODE_INFO(node)->extra) - gtk_widget_destroy(NODE_INFO(node)->extra); - g_free (NODE_INFO(node)->name); - g_chunk_free(NODE_INFO(node), merge_node_chunk); - g_node_destroy(node); - } -} - -static gboolean -do_updates(EggMenuMerge *self) -{ - /* this function needs to check through the tree for dirty nodes. - * For such nodes, it needs to do the following: - * - * 1) check if they are referenced by any loaded UI files anymore. - * In which case, the proxy widget should be destroyed, unless - * there are any subnodes. - * - * 2) lookup the action for this node again. If it is different to - * the current one (or if no previous action has been looked up), - * the proxy is reconnected to the new action (or a new proxy widget - * is created and added to the parent container). - */ - - update_node (self, self->root_node); - - self->update_tag = 0; - return FALSE; -} - -static void -egg_menu_merge_queue_update (EggMenuMerge *self) -{ - if (self->update_tag != 0) - return; - - self->update_tag = g_idle_add((GSourceFunc)do_updates, self); -} - -void -egg_menu_merge_ensure_update (EggMenuMerge *self) -{ - if (self->update_tag != 0) - { - g_source_remove(self->update_tag); - do_updates(self); - } -} - -static gboolean -dirty_traverse_func (GNode *node, gpointer data) -{ - NODE_INFO(node)->dirty = TRUE; - return FALSE; -} - -static void -egg_menu_merge_dirty_all (EggMenuMerge *self) -{ - g_node_traverse(self->root_node, G_PRE_ORDER, G_TRAVERSE_ALL, -1, - dirty_traverse_func, NULL); - egg_menu_merge_queue_update(self); -} |