diff -aur compiz-deskmenu/deskmenu-menu.c copy of compiz-deskmenu//deskmenu-menu.c
--- compiz-deskmenu/deskmenu-menu.c 2010-11-08 14:20:23.000000000 -0800
+++ compiz-deskmenu2/deskmenu-menu.c 2010-11-08 14:13:24.000000000 -0800
@@ -1,658 +1,671 @@
-/*
- * compiz-deskmenu 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.
- *
- * compiz-deskmenu 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, see .
- *
- * Copyright 2008 Christopher Williams
- */
-
-#include
-#include
-#include
-#include
-
-#define HAVE_WNCK 1
-
-#if HAVE_WNCK
-#include "deskmenu-wnck.h"
-#endif
-
-#include "deskmenu-menu.h"
-#include "deskmenu-glue.h"
-
-
-G_DEFINE_TYPE(Deskmenu, deskmenu, G_TYPE_OBJECT)
-
-GQuark
-deskmenu_error_quark (void)
-{
- static GQuark quark = 0;
- if (!quark)
- quark = g_quark_from_static_string ("deskmenu_error");
- return quark;
-}
-
-static void
-quit (GtkWidget *widget,
- gpointer data)
-{
- gtk_main_quit ();
-}
-
-static void
-launcher_activated (GtkWidget *widget,
- gchar *command)
-{
- GError *error = NULL;
- Deskmenu *deskmenu;
-
- deskmenu = g_object_get_data (G_OBJECT (widget), "deskmenu");
-
- if (!gdk_spawn_on_screen (gdk_screen_get_default (),
- g_get_home_dir (),
- g_strsplit (command, " ", 0),
- deskmenu->envp, G_SPAWN_SEARCH_PATH,
- NULL, NULL, NULL, &error))
- {
- GtkWidget *message = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR,
- GTK_BUTTONS_CLOSE, "%s", error->message);
- gtk_dialog_run (GTK_DIALOG (message));
- gtk_widget_destroy (message);
- }
-
-}
-
-static void
-launcher_name_exec_update (GtkWidget *label)
-{
- gchar *exec, *stdout;
- exec = g_object_get_data (G_OBJECT (label), "exec");
- if (g_spawn_command_line_sync (exec, &stdout, NULL, NULL, NULL))
- gtk_label_set_text (GTK_LABEL (label), g_strstrip(stdout));
- else
- gtk_label_set_text (GTK_LABEL (label), "execution error");
- g_free (stdout);
-}
-
-static void
-deskmenu_construct_item (Deskmenu *deskmenu)
-{
- DeskmenuItem *item = deskmenu->current_item;
- GtkWidget *menu_item;
- gchar *name, *icon, *command;
-
- switch (item->type)
- {
- case DESKMENU_ITEM_LAUNCHER:
- if (item->name_exec)
- {
- GtkWidget *label;
- GHook *hook;
-
- name = g_strstrip (item->name->str);
-
- menu_item = gtk_image_menu_item_new ();
- label = gtk_label_new_with_mnemonic (NULL);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
-
- g_object_set_data (G_OBJECT (label), "exec", g_strdup (name));
- gtk_container_add (GTK_CONTAINER (menu_item), label);
- hook = g_hook_alloc (deskmenu->show_hooks);
-
- hook->data = (gpointer) label;
- hook->func = (GHookFunc *) launcher_name_exec_update;
- g_hook_append (deskmenu->show_hooks, hook);
- }
- else
- {
- if (item->name)
- name = g_strstrip (item->name->str);
- else
- name = "";
-
- menu_item = gtk_image_menu_item_new_with_mnemonic (name);
-
- }
-
- if (item->icon)
- {
- icon = g_strstrip (item->icon->str);
- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),
- gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_MENU));
- }
-
- if (item->command)
- {
- command = g_strstrip (item->command->str);
- g_object_set_data (G_OBJECT (menu_item), "deskmenu", deskmenu);
- g_signal_connect (G_OBJECT (menu_item), "activate",
- G_CALLBACK (launcher_activated), g_strdup (command));
- }
-
- gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
- menu_item);
- break;
-
-#if HAVE_WNCK
- case DESKMENU_ITEM_WINDOWLIST:
- menu_item = gtk_menu_item_new_with_mnemonic ("_Windows");
-
- DeskmenuWindowlist *windowlist = deskmenu_windowlist_new ();
-
- gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item),
- windowlist->menu);
- gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
- menu_item);
- break;
-
- case DESKMENU_ITEM_VIEWPORTLIST:
- menu_item = gtk_menu_item_new_with_mnemonic ("_Viewports");
-
- DeskmenuVplist *vplist = deskmenu_vplist_new ();
-
- if (item->wrap
- && strcmp (g_strstrip (item->wrap->str), "true") == 0)
- vplist->wrap = TRUE;
-
- gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item),
- vplist->menu);
- gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
- menu_item);
- break;
-#endif
- case DESKMENU_ITEM_RELOAD:
- menu_item = gtk_image_menu_item_new_with_mnemonic ("_Reload");
- gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),
- gtk_image_new_from_stock (GTK_STOCK_REFRESH,
- GTK_ICON_SIZE_MENU));
- g_signal_connect (G_OBJECT (menu_item), "activate",
- G_CALLBACK (quit), NULL);
- gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
- menu_item);
- break;
-
- default:
- break;
- }
-
-}
-/* The handler functions. */
-
-static void
-start_element (GMarkupParseContext *context,
- const gchar *element_name,
- const gchar **attr_names,
- const gchar **attr_values,
- gpointer user_data,
- GError **error)
-{
- Deskmenu *deskmenu = DESKMENU (user_data);
- DeskmenuElementType element_type;
- const gchar **ncursor = attr_names, **vcursor = attr_values;
- GtkWidget *item, *menu;
-
- element_type = GPOINTER_TO_INT (g_hash_table_lookup
- (deskmenu->element_hash, element_name));
-
- if ((deskmenu->menu && !deskmenu->current_menu)
- || (!deskmenu->menu && element_type != DESKMENU_ELEMENT_MENU))
- {
- gint line_num, char_num;
- g_markup_parse_context_get_position (context, &line_num, &char_num);
- g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
- "Error on line %d char %d: Element '%s' declared outside of "
- "toplevel menu element", line_num, char_num, element_name);
- return;
- }
-
- switch (element_type)
- {
- case DESKMENU_ELEMENT_MENU:
-
- if (deskmenu->current_item != NULL)
- {
- gint line_num, char_num;
- g_markup_parse_context_get_position (context, &line_num,
- &char_num);
- g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
- "Error on line %d char %d: Element 'menu' cannot be nested "
- "inside of an item element", line_num, char_num);
- return;
- }
-
- if (!deskmenu->menu)
- {
- deskmenu->menu = gtk_menu_new ();
- g_object_set_data (G_OBJECT (deskmenu->menu), "parent menu",
- NULL);
- deskmenu->current_menu = deskmenu->menu;
- }
- else
- {
- gchar *name = NULL;
- while (*ncursor)
- {
- if (strcmp (*ncursor, "name") == 0)
- name = g_strdup (*vcursor);
- else
- g_set_error (error, G_MARKUP_ERROR,
- G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
- "Unknown attribute: %s", *ncursor);
- ncursor++;
- vcursor++;
- }
- if (name)
- item = gtk_menu_item_new_with_mnemonic (name);
- else
- item = gtk_menu_item_new_with_mnemonic ("");
- gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
- item);
- menu = gtk_menu_new ();
- g_object_set_data (G_OBJECT (menu), "parent menu",
- deskmenu->current_menu);
- deskmenu->current_menu = menu;
- gtk_menu_item_set_submenu (GTK_MENU_ITEM (item),
- deskmenu->current_menu);
- g_free (name);
- }
- break;
-
- case DESKMENU_ELEMENT_SEPARATOR:
- break; /* build it in the end function */
-
- case DESKMENU_ELEMENT_ITEM:
-
- if (deskmenu->current_item != NULL)
- {
- gint line_num, char_num;
- g_markup_parse_context_get_position (context, &line_num,
- &char_num);
- g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
- "Error on line %d char %d: Element 'item' cannot be nested "
- "inside of another item element", line_num, char_num);
- return;
- }
-
- deskmenu->current_item = g_slice_new0 (DeskmenuItem);
- while (*ncursor)
- {
- if (strcmp (*ncursor, "type") == 0)
- deskmenu->current_item->type = GPOINTER_TO_INT
- (g_hash_table_lookup (deskmenu->item_hash, *vcursor));
- else
- g_set_error (error, G_MARKUP_ERROR,
- G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
- "Unknown attribute: %s", *ncursor);
- ncursor++;
- vcursor++;
- }
- break;
-
- case DESKMENU_ELEMENT_NAME:
- while (*ncursor)
- {
- if ((strcmp (*ncursor, "mode") == 0)
- && (strcmp (*vcursor, "exec") == 0))
- deskmenu->current_item->name_exec = TRUE;
- ncursor++;
- vcursor++;
- } /* no break here to let it fall through */
- case DESKMENU_ELEMENT_ICON:
- case DESKMENU_ELEMENT_COMMAND:
- case DESKMENU_ELEMENT_WRAP:
- if (deskmenu->current_item)
- deskmenu->current_item->current_element = element_type;
- break;
-
- default:
- g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
- "Unknown element: %s", element_name);
- break;
- }
-}
-
-static void
-text (GMarkupParseContext *context,
- const gchar *text,
- gsize text_len,
- gpointer user_data,
- GError **error)
-{
- Deskmenu *deskmenu = DESKMENU (user_data);
- DeskmenuItem *item = deskmenu->current_item;
-
- if (!(item && item->current_element))
- return;
-
- switch (item->current_element)
- {
- case DESKMENU_ELEMENT_NAME:
- if (!item->name)
- item->name = g_string_new_len (text, text_len);
- else
- g_string_append_len (item->name, text, text_len);
- break;
-
- case DESKMENU_ELEMENT_ICON:
- if (!item->icon)
- item->icon = g_string_new_len (text, text_len);
- else
- g_string_append_len (item->icon, text, text_len);
- break;
-
- case DESKMENU_ELEMENT_COMMAND:
- if (!item->command)
- item->command = g_string_new_len (text, text_len);
- else
- g_string_append_len (item->command, text, text_len);
- break;
-
- case DESKMENU_ELEMENT_WRAP:
- if (!item->wrap)
- item->wrap = g_string_new_len (text, text_len);
- else
- g_string_append_len (item->wrap, text, text_len);
- break;
-
- default:
- break;
- }
-
-}
-
-static void
-end_element (GMarkupParseContext *context,
- const gchar *element_name,
- gpointer user_data,
- GError **error)
-{
-
- DeskmenuElementType element_type;
- Deskmenu *deskmenu = DESKMENU (user_data);
- GtkWidget *parent, *item;
- element_type = GPOINTER_TO_INT (g_hash_table_lookup
- (deskmenu->element_hash, element_name));
-
- switch (element_type)
- {
- case DESKMENU_ELEMENT_MENU:
-
- g_return_if_fail (deskmenu->current_item == NULL);
-
- parent = g_object_get_data (G_OBJECT (deskmenu->current_menu),
- "parent menu");
-
- deskmenu->current_menu = parent;
-
- break;
-
- case DESKMENU_ELEMENT_SEPARATOR:
- item = gtk_separator_menu_item_new ();
- gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
- item);
- break;
-
- case DESKMENU_ELEMENT_ITEM:
-
- g_return_if_fail (deskmenu->current_item != NULL);
-
- /* finally make the item ^_^ */
- deskmenu_construct_item (deskmenu);
-
- /* free data used to make it */
- if (deskmenu->current_item->name)
- g_string_free (deskmenu->current_item->name, TRUE);
- if (deskmenu->current_item->icon)
- g_string_free (deskmenu->current_item->icon, TRUE);
- if (deskmenu->current_item->command)
- g_string_free (deskmenu->current_item->command, TRUE);
- if (deskmenu->current_item->wrap)
- g_string_free (deskmenu->current_item->wrap, TRUE);
- g_slice_free (DeskmenuItem, deskmenu->current_item);
- deskmenu->current_item = NULL;
- break;
-
- default:
- break;
- }
-}
-
-/* The list of what handler does what. */
-static GMarkupParser parser = {
- start_element,
- end_element,
- text,
- NULL,
- NULL
-};
-
-
-/* Class init */
-static void
-deskmenu_class_init (DeskmenuClass *deskmenu_class)
-{
- dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (deskmenu_class),
- &dbus_glib_deskmenu_object_info);
-}
-
-/* Instance init */
-static void
-deskmenu_init (Deskmenu *deskmenu)
-{
-
- deskmenu->show_hooks = g_slice_new0 (GHookList);
-
- g_hook_list_init (deskmenu->show_hooks, sizeof (GHook));
-
-
- deskmenu->menu = NULL;
- deskmenu->current_menu = NULL;
- deskmenu->current_item = NULL;
-
- deskmenu->envp = NULL;
-
- deskmenu->item_hash = g_hash_table_new (g_str_hash, g_str_equal);
-
- g_hash_table_insert (deskmenu->item_hash, "launcher",
- GINT_TO_POINTER (DESKMENU_ITEM_LAUNCHER));
-#if HAVE_WNCK
- g_hash_table_insert (deskmenu->item_hash, "windowlist",
- GINT_TO_POINTER (DESKMENU_ITEM_WINDOWLIST));
- g_hash_table_insert (deskmenu->item_hash, "viewportlist",
- GINT_TO_POINTER (DESKMENU_ITEM_VIEWPORTLIST));
-#endif
- g_hash_table_insert (deskmenu->item_hash, "reload",
- GINT_TO_POINTER (DESKMENU_ITEM_RELOAD));
-
- deskmenu->element_hash = g_hash_table_new (g_str_hash, g_str_equal);
-
- g_hash_table_insert (deskmenu->element_hash, "menu",
- GINT_TO_POINTER (DESKMENU_ELEMENT_MENU));
- g_hash_table_insert (deskmenu->element_hash, "separator",
- GINT_TO_POINTER (DESKMENU_ELEMENT_SEPARATOR));
- g_hash_table_insert (deskmenu->element_hash, "item",
- GINT_TO_POINTER (DESKMENU_ELEMENT_ITEM));
- g_hash_table_insert (deskmenu->element_hash, "name",
- GINT_TO_POINTER (DESKMENU_ELEMENT_NAME));
- g_hash_table_insert (deskmenu->element_hash, "icon",
- GINT_TO_POINTER (DESKMENU_ELEMENT_ICON));
- g_hash_table_insert (deskmenu->element_hash, "command",
- GINT_TO_POINTER (DESKMENU_ELEMENT_COMMAND));
- g_hash_table_insert (deskmenu->element_hash, "wrap",
- GINT_TO_POINTER (DESKMENU_ELEMENT_WRAP));
-
-}
-
-static void
-deskmenu_parse_file (Deskmenu *deskmenu,
- gchar *configpath)
-{
- GError *error = NULL;
- gboolean success = FALSE;
- gchar *text;
- gsize length;
-
- if (!configpath)
- configpath = g_build_path (G_DIR_SEPARATOR_S,
- g_get_user_config_dir (),
- "compiz",
- "deskmenu",
- "menu.xml",
- NULL);
-
- GMarkupParseContext *context = g_markup_parse_context_new (&parser,
- 0, deskmenu, NULL);
-
- if (!g_file_get_contents (configpath, &text, &length, NULL))
- {
- const gchar* const *cursor = g_get_system_config_dirs ();
- gchar *path = NULL;
- while (*cursor)
- {
- g_free (configpath);
- g_free (path);
- path = g_strdup (*cursor);
- configpath = g_build_path (G_DIR_SEPARATOR_S,
- path,
- "compiz",
- "deskmenu",
- "menu.xml",
- NULL);
-
- if (g_file_get_contents (configpath, &text, &length, NULL))
- {
- success = TRUE;
- g_free (path);
- break;
- }
- cursor++;
- }
- }
- else
- {
- success = TRUE;
- }
-
- if (!success)
- {
- g_printerr ("Couldn't find a menu file\n");
- exit (1);
- }
-
- if (!g_markup_parse_context_parse (context, text, length, &error)
- || !g_markup_parse_context_end_parse (context, &error))
- {
- g_printerr ("Parse of %s failed with message: %s \n",
- configpath, error->message);
- g_error_free (error);
- exit (1);
- }
-
- g_free(text);
- g_free (configpath);
- g_markup_parse_context_free (context);
-
- gtk_widget_show_all (deskmenu->menu);
-}
-
-/* The show method */
-gboolean
-deskmenu_show (Deskmenu *deskmenu,
- gchar **env,
- GError **error)
-{
- g_hook_list_invoke (deskmenu->show_hooks, FALSE);
-
- if (deskmenu->envp)
- g_strfreev (deskmenu->envp);
-
- deskmenu->envp = g_strdupv (env);
-
- gtk_menu_popup (GTK_MENU (deskmenu->menu),
- NULL, NULL, NULL, NULL,
- 0, 0);
- return TRUE;
-}
-
-/* The reload method */
-gboolean
-deskmenu_reload (Deskmenu *deskmenu,
- GError **error)
-{
- gtk_main_quit ();
- return TRUE;
-}
-
-int
-main (int argc,
- char **argv)
-{
- DBusGConnection *connection;
- GError *error = NULL;
- GObject *deskmenu;
-
- g_type_init ();
-
- gchar *filename = NULL;
- GOptionContext *context;
- GOptionEntry entries[] =
- {
- { "menu", 'm', 0, G_OPTION_ARG_FILENAME, &filename,
- "Use FILE instead of the default menu file", "FILE" },
- { NULL, 0, 0, 0, NULL, NULL, NULL }
- };
-
- context = g_option_context_new (NULL);
- g_option_context_add_main_entries (context, entries, NULL);
- g_option_context_add_group (context, gtk_get_option_group (TRUE));
- if (!g_option_context_parse (context, &argc, &argv, &error))
- {
- g_printerr ("option parsing failed: %s", error->message);
- g_error_free (error);
- exit (1);
- }
- g_option_context_free (context);
-
- /* Obtain a connection to the session bus */
- connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
- if (connection == NULL)
- {
- g_printerr ("Failed to open connection to bus: %s", error->message);
- g_error_free (error);
- exit (1);
- }
-
-#if HAVE_WNCK
- wnck_set_client_type (WNCK_CLIENT_TYPE_PAGER);
-#endif
-
- gtk_init (&argc, &argv);
-
- deskmenu = g_object_new (DESKMENU_TYPE, NULL);
-
- deskmenu_parse_file (DESKMENU (deskmenu), filename);
-
- dbus_g_connection_register_g_object (connection,
- DESKMENU_PATH_DBUS,
- deskmenu);
-
- if (!dbus_bus_request_name (dbus_g_connection_get_connection (connection),
- DESKMENU_SERVICE_DBUS,
- DBUS_NAME_FLAG_REPLACE_EXISTING,
- NULL))
- return 1;
-
- gtk_main ();
-
- return 0;
-}
-
+/*
+ * compiz-deskmenu 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.
+ *
+ * compiz-deskmenu 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, see .
+ *
+ * Copyright 2008 Christopher Williams
+ */
+
+#include
+#include
+#include
+#include
+
+#define HAVE_WNCK 1
+
+#if HAVE_WNCK
+#include "deskmenu-wnck.h"
+#endif
+
+#include "deskmenu-menu.h"
+#include "deskmenu-glue.h"
+
+
+G_DEFINE_TYPE(Deskmenu, deskmenu, G_TYPE_OBJECT)
+
+GQuark
+deskmenu_error_quark (void)
+{
+ static GQuark quark = 0;
+ if (!quark)
+ quark = g_quark_from_static_string ("deskmenu_error");
+ return quark;
+}
+
+static void
+quit (GtkWidget *widget,
+ gpointer data)
+{
+ gtk_main_quit ();
+}
+
+//This is how menu command is launched
+static void
+launcher_activated (GtkWidget *widget,
+ gchar *command)
+{
+ GError *error = NULL;
+ Deskmenu *deskmenu;
+
+ deskmenu = g_object_get_data (G_OBJECT (widget), "deskmenu");
+ //stolen from openbox
+ gchar *parse_expand_tilde(const gchar *command)
+ {
+ gchar *ret;
+ GRegex *regex;
+
+ if (!command)
+ return NULL;
+
+ regex = g_regex_new("(?:^|(?<=[ \\t]))~(?:(?=[/ \\t])|$)",
+ G_REGEX_MULTILINE | G_REGEX_RAW, 0, NULL);
+ ret = g_regex_replace_literal(regex, command, -1, 0, g_get_home_dir(), 0, NULL);
+ g_regex_unref(regex);
+
+ return ret;
+ }
+ //end stolen
+ if (!gdk_spawn_command_line_on_screen (gdk_screen_get_default (), parse_expand_tilde(command), &error))
+ {
+ GtkWidget *message = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE, "%s", error->message);
+ gtk_dialog_run (GTK_DIALOG (message));
+ gtk_widget_destroy (message);
+ }
+
+}
+
+static void
+launcher_name_exec_update (GtkWidget *label)
+{
+ gchar *exec, *stdout;
+ exec = g_object_get_data (G_OBJECT (label), "exec");
+ if (g_spawn_command_line_sync (exec, &stdout, NULL, NULL, NULL))
+ gtk_label_set_text (GTK_LABEL (label), g_strstrip(stdout));
+ else
+ gtk_label_set_text (GTK_LABEL (label), "execution error");
+ g_free (stdout);
+}
+
+static void
+deskmenu_construct_item (Deskmenu *deskmenu)
+{
+ DeskmenuItem *item = deskmenu->current_item;
+ GtkWidget *menu_item;
+ gchar *name, *icon, *command;
+
+ switch (item->type)
+ {
+ case DESKMENU_ITEM_LAUNCHER:
+ if (item->name_exec)
+ {
+ GtkWidget *label;
+ GHook *hook;
+
+ name = g_strstrip (item->name->str);
+
+ menu_item = gtk_image_menu_item_new ();
+ label = gtk_label_new_with_mnemonic (NULL);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+
+ g_object_set_data (G_OBJECT (label), "exec", g_strdup (name));
+ gtk_container_add (GTK_CONTAINER (menu_item), label);
+ hook = g_hook_alloc (deskmenu->show_hooks);
+
+ hook->data = (gpointer) label;
+ hook->func = (GHookFunc *) launcher_name_exec_update;
+ g_hook_append (deskmenu->show_hooks, hook);
+ }
+ else
+ {
+ if (item->name)
+ name = g_strstrip (item->name->str);
+ else
+ name = "";
+
+ menu_item = gtk_image_menu_item_new_with_mnemonic (name);
+
+ }
+
+ if (item->icon)
+ {
+ icon = g_strstrip (item->icon->str);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),
+ gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_MENU));
+ }
+
+ if (item->command)
+ {
+ command = g_strstrip (item->command->str);
+ g_object_set_data (G_OBJECT (menu_item), "deskmenu", deskmenu);
+ g_signal_connect (G_OBJECT (menu_item), "activate",
+ G_CALLBACK (launcher_activated), g_strdup (command));
+ }
+
+ gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
+ menu_item);
+ break;
+
+#if HAVE_WNCK
+ case DESKMENU_ITEM_WINDOWLIST:
+ menu_item = gtk_menu_item_new_with_mnemonic ("_Windows");
+
+ DeskmenuWindowlist *windowlist = deskmenu_windowlist_new ();
+
+ gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item),
+ windowlist->menu);
+ gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
+ menu_item);
+ break;
+
+ case DESKMENU_ITEM_VIEWPORTLIST:
+ menu_item = gtk_menu_item_new_with_mnemonic ("_Viewports");
+
+ DeskmenuVplist *vplist = deskmenu_vplist_new ();
+
+ if (item->wrap
+ && strcmp (g_strstrip (item->wrap->str), "true") == 0)
+ vplist->wrap = TRUE;
+
+ gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item),
+ vplist->menu);
+ gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
+ menu_item);
+ break;
+#endif
+ case DESKMENU_ITEM_RELOAD:
+ menu_item = gtk_image_menu_item_new_with_mnemonic ("_Reload");
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item),
+ gtk_image_new_from_stock (GTK_STOCK_REFRESH,
+ GTK_ICON_SIZE_MENU));
+ g_signal_connect (G_OBJECT (menu_item), "activate",
+ G_CALLBACK (quit), NULL);
+ gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
+ menu_item);
+ break;
+
+ default:
+ break;
+ }
+
+}
+/* The handler functions. */
+
+static void
+start_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attr_names,
+ const gchar **attr_values,
+ gpointer user_data,
+ GError **error)
+{
+ Deskmenu *deskmenu = DESKMENU (user_data);
+ DeskmenuElementType element_type;
+ const gchar **ncursor = attr_names, **vcursor = attr_values;
+ GtkWidget *item, *menu;
+
+ element_type = GPOINTER_TO_INT (g_hash_table_lookup
+ (deskmenu->element_hash, element_name));
+
+ if ((deskmenu->menu && !deskmenu->current_menu)
+ || (!deskmenu->menu && element_type != DESKMENU_ELEMENT_MENU))
+ {
+ gint line_num, char_num;
+ g_markup_parse_context_get_position (context, &line_num, &char_num);
+ g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
+ "Error on line %d char %d: Element '%s' declared outside of "
+ "toplevel menu element", line_num, char_num, element_name);
+ return;
+ }
+
+ switch (element_type)
+ {
+ case DESKMENU_ELEMENT_MENU:
+
+ if (deskmenu->current_item != NULL)
+ {
+ gint line_num, char_num;
+ g_markup_parse_context_get_position (context, &line_num,
+ &char_num);
+ g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
+ "Error on line %d char %d: Element 'menu' cannot be nested "
+ "inside of an item element", line_num, char_num);
+ return;
+ }
+
+ if (!deskmenu->menu)
+ {
+ deskmenu->menu = gtk_menu_new ();
+ g_object_set_data (G_OBJECT (deskmenu->menu), "parent menu",
+ NULL);
+ deskmenu->current_menu = deskmenu->menu;
+ }
+ else
+ {
+ gchar *name = NULL;
+ while (*ncursor)
+ {
+ if (strcmp (*ncursor, "name") == 0)
+ name = g_strdup (*vcursor);
+ else
+ g_set_error (error, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
+ "Unknown attribute: %s", *ncursor);
+ ncursor++;
+ vcursor++;
+ }
+ if (name)
+ item = gtk_menu_item_new_with_mnemonic (name);
+ else
+ item = gtk_menu_item_new_with_mnemonic ("");
+ gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
+ item);
+ menu = gtk_menu_new ();
+ g_object_set_data (G_OBJECT (menu), "parent menu",
+ deskmenu->current_menu);
+ deskmenu->current_menu = menu;
+ gtk_menu_item_set_submenu (GTK_MENU_ITEM (item),
+ deskmenu->current_menu);
+ g_free (name);
+ }
+ break;
+
+ case DESKMENU_ELEMENT_SEPARATOR:
+ break; /* build it in the end function */
+
+ case DESKMENU_ELEMENT_ITEM:
+
+ if (deskmenu->current_item != NULL)
+ {
+ gint line_num, char_num;
+ g_markup_parse_context_get_position (context, &line_num,
+ &char_num);
+ g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
+ "Error on line %d char %d: Element 'item' cannot be nested "
+ "inside of another item element", line_num, char_num);
+ return;
+ }
+
+ deskmenu->current_item = g_slice_new0 (DeskmenuItem);
+ while (*ncursor)
+ {
+ if (strcmp (*ncursor, "type") == 0)
+ deskmenu->current_item->type = GPOINTER_TO_INT
+ (g_hash_table_lookup (deskmenu->item_hash, *vcursor));
+ else
+ g_set_error (error, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
+ "Unknown attribute: %s", *ncursor);
+ ncursor++;
+ vcursor++;
+ }
+ break;
+
+ case DESKMENU_ELEMENT_NAME:
+ while (*ncursor)
+ {
+ if ((strcmp (*ncursor, "mode") == 0)
+ && (strcmp (*vcursor, "exec") == 0))
+ deskmenu->current_item->name_exec = TRUE;
+ ncursor++;
+ vcursor++;
+ } /* no break here to let it fall through */
+ case DESKMENU_ELEMENT_ICON:
+ case DESKMENU_ELEMENT_COMMAND:
+ case DESKMENU_ELEMENT_WRAP:
+ if (deskmenu->current_item)
+ deskmenu->current_item->current_element = element_type;
+ break;
+
+ default:
+ g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
+ "Unknown element: %s", element_name);
+ break;
+ }
+}
+
+static void
+text (GMarkupParseContext *context,
+ const gchar *text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error)
+{
+ Deskmenu *deskmenu = DESKMENU (user_data);
+ DeskmenuItem *item = deskmenu->current_item;
+
+ if (!(item && item->current_element))
+ return;
+
+ switch (item->current_element)
+ {
+ case DESKMENU_ELEMENT_NAME:
+ if (!item->name)
+ item->name = g_string_new_len (text, text_len);
+ else
+ g_string_append_len (item->name, text, text_len);
+ break;
+
+ case DESKMENU_ELEMENT_ICON:
+ if (!item->icon)
+ item->icon = g_string_new_len (text, text_len);
+ else
+ g_string_append_len (item->icon, text, text_len);
+ break;
+
+ case DESKMENU_ELEMENT_COMMAND:
+ if (!item->command)
+ item->command = g_string_new_len (text, text_len);
+ else
+ g_string_append_len (item->command, text, text_len);
+ break;
+
+ case DESKMENU_ELEMENT_WRAP:
+ if (!item->wrap)
+ item->wrap = g_string_new_len (text, text_len);
+ else
+ g_string_append_len (item->wrap, text, text_len);
+ break;
+
+ default:
+ break;
+ }
+
+}
+
+static void
+end_element (GMarkupParseContext *context,
+ const gchar *element_name,
+ gpointer user_data,
+ GError **error)
+{
+
+ DeskmenuElementType element_type;
+ Deskmenu *deskmenu = DESKMENU (user_data);
+ GtkWidget *parent, *item;
+ element_type = GPOINTER_TO_INT (g_hash_table_lookup
+ (deskmenu->element_hash, element_name));
+
+ switch (element_type)
+ {
+ case DESKMENU_ELEMENT_MENU:
+
+ g_return_if_fail (deskmenu->current_item == NULL);
+
+ parent = g_object_get_data (G_OBJECT (deskmenu->current_menu),
+ "parent menu");
+
+ deskmenu->current_menu = parent;
+
+ break;
+
+ case DESKMENU_ELEMENT_SEPARATOR:
+ item = gtk_separator_menu_item_new ();
+ gtk_menu_shell_append (GTK_MENU_SHELL (deskmenu->current_menu),
+ item);
+ break;
+
+ case DESKMENU_ELEMENT_ITEM:
+
+ g_return_if_fail (deskmenu->current_item != NULL);
+
+ /* finally make the item ^_^ */
+ deskmenu_construct_item (deskmenu);
+
+ /* free data used to make it */
+ if (deskmenu->current_item->name)
+ g_string_free (deskmenu->current_item->name, TRUE);
+ if (deskmenu->current_item->icon)
+ g_string_free (deskmenu->current_item->icon, TRUE);
+ if (deskmenu->current_item->command)
+ g_string_free (deskmenu->current_item->command, TRUE);
+ if (deskmenu->current_item->wrap)
+ g_string_free (deskmenu->current_item->wrap, TRUE);
+ g_slice_free (DeskmenuItem, deskmenu->current_item);
+ deskmenu->current_item = NULL;
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* The list of what handler does what. */
+static GMarkupParser parser = {
+ start_element,
+ end_element,
+ text,
+ NULL,
+ NULL
+};
+
+
+/* Class init */
+static void
+deskmenu_class_init (DeskmenuClass *deskmenu_class)
+{
+ dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (deskmenu_class),
+ &dbus_glib_deskmenu_object_info);
+}
+
+/* Instance init */
+static void
+deskmenu_init (Deskmenu *deskmenu)
+{
+
+ deskmenu->show_hooks = g_slice_new0 (GHookList);
+
+ g_hook_list_init (deskmenu->show_hooks, sizeof (GHook));
+
+
+ deskmenu->menu = NULL;
+ deskmenu->current_menu = NULL;
+ deskmenu->current_item = NULL;
+
+ deskmenu->envp = NULL;
+
+ deskmenu->item_hash = g_hash_table_new (g_str_hash, g_str_equal);
+
+ g_hash_table_insert (deskmenu->item_hash, "launcher",
+ GINT_TO_POINTER (DESKMENU_ITEM_LAUNCHER));
+#if HAVE_WNCK
+ g_hash_table_insert (deskmenu->item_hash, "windowlist",
+ GINT_TO_POINTER (DESKMENU_ITEM_WINDOWLIST));
+ g_hash_table_insert (deskmenu->item_hash, "viewportlist",
+ GINT_TO_POINTER (DESKMENU_ITEM_VIEWPORTLIST));
+#endif
+ g_hash_table_insert (deskmenu->item_hash, "reload",
+ GINT_TO_POINTER (DESKMENU_ITEM_RELOAD));
+
+ deskmenu->element_hash = g_hash_table_new (g_str_hash, g_str_equal);
+
+ g_hash_table_insert (deskmenu->element_hash, "menu",
+ GINT_TO_POINTER (DESKMENU_ELEMENT_MENU));
+ g_hash_table_insert (deskmenu->element_hash, "separator",
+ GINT_TO_POINTER (DESKMENU_ELEMENT_SEPARATOR));
+ g_hash_table_insert (deskmenu->element_hash, "item",
+ GINT_TO_POINTER (DESKMENU_ELEMENT_ITEM));
+ g_hash_table_insert (deskmenu->element_hash, "name",
+ GINT_TO_POINTER (DESKMENU_ELEMENT_NAME));
+ g_hash_table_insert (deskmenu->element_hash, "icon",
+ GINT_TO_POINTER (DESKMENU_ELEMENT_ICON));
+ g_hash_table_insert (deskmenu->element_hash, "command",
+ GINT_TO_POINTER (DESKMENU_ELEMENT_COMMAND));
+ g_hash_table_insert (deskmenu->element_hash, "wrap",
+ GINT_TO_POINTER (DESKMENU_ELEMENT_WRAP));
+
+}
+
+static void
+deskmenu_parse_file (Deskmenu *deskmenu,
+ gchar *configpath)
+{
+ GError *error = NULL;
+ gboolean success = FALSE;
+ gchar *text;
+ gsize length;
+
+ if (!configpath)
+ configpath = g_build_path (G_DIR_SEPARATOR_S,
+ g_get_user_config_dir (),
+ "compiz",
+ "deskmenu",
+ "menu.xml",
+ NULL);
+
+ GMarkupParseContext *context = g_markup_parse_context_new (&parser,
+ 0, deskmenu, NULL);
+
+ if (!g_file_get_contents (configpath, &text, &length, NULL))
+ {
+ const gchar* const *cursor = g_get_system_config_dirs ();
+ gchar *path = NULL;
+ while (*cursor)
+ {
+ g_free (configpath);
+ g_free (path);
+ path = g_strdup (*cursor);
+ configpath = g_build_path (G_DIR_SEPARATOR_S,
+ path,
+ "compiz",
+ "deskmenu",
+ "menu.xml",
+ NULL);
+
+ if (g_file_get_contents (configpath, &text, &length, NULL))
+ {
+ success = TRUE;
+ g_free (path);
+ break;
+ }
+ cursor++;
+ }
+ }
+ else
+ {
+ success = TRUE;
+ }
+
+ if (!success)
+ {
+ g_printerr ("Couldn't find a menu file\n");
+ exit (1);
+ }
+
+ if (!g_markup_parse_context_parse (context, text, length, &error)
+ || !g_markup_parse_context_end_parse (context, &error))
+ {
+ g_printerr ("Parse of %s failed with message: %s \n",
+ configpath, error->message);
+ g_error_free (error);
+ exit (1);
+ }
+
+ g_free(text);
+ g_free (configpath);
+ g_markup_parse_context_free (context);
+
+ gtk_widget_show_all (deskmenu->menu);
+}
+
+/* The show method */
+gboolean
+deskmenu_show (Deskmenu *deskmenu,
+ gchar **env,
+ GError **error)
+{
+ g_hook_list_invoke (deskmenu->show_hooks, FALSE);
+
+ if (deskmenu->envp)
+ g_strfreev (deskmenu->envp);
+
+ deskmenu->envp = g_strdupv (env);
+
+ gtk_menu_popup (GTK_MENU (deskmenu->menu),
+ NULL, NULL, NULL, NULL,
+ 0, 0);
+ return TRUE;
+}
+
+/* The reload method */
+gboolean
+deskmenu_reload (Deskmenu *deskmenu,
+ GError **error)
+{
+ gtk_main_quit ();
+ return TRUE;
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ DBusGConnection *connection;
+ GError *error = NULL;
+ GObject *deskmenu;
+
+ g_type_init ();
+
+ gchar *filename = NULL;
+ GOptionContext *context;
+ GOptionEntry entries[] =
+ {
+ { "menu", 'm', 0, G_OPTION_ARG_FILENAME, &filename,
+ "Use FILE instead of the default menu file", "FILE" },
+ { NULL, 0, 0, 0, NULL, NULL, NULL }
+ };
+
+ context = g_option_context_new (NULL);
+ g_option_context_add_main_entries (context, entries, NULL);
+ g_option_context_add_group (context, gtk_get_option_group (TRUE));
+ if (!g_option_context_parse (context, &argc, &argv, &error))
+ {
+ g_printerr ("option parsing failed: %s", error->message);
+ g_error_free (error);
+ exit (1);
+ }
+ g_option_context_free (context);
+
+ /* Obtain a connection to the session bus */
+ connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+ if (connection == NULL)
+ {
+ g_printerr ("Failed to open connection to bus: %s", error->message);
+ g_error_free (error);
+ exit (1);
+ }
+
+#if HAVE_WNCK
+ wnck_set_client_type (WNCK_CLIENT_TYPE_PAGER);
+#endif
+
+ gtk_init (&argc, &argv);
+
+ deskmenu = g_object_new (DESKMENU_TYPE, NULL);
+
+ deskmenu_parse_file (DESKMENU (deskmenu), filename);
+
+ dbus_g_connection_register_g_object (connection,
+ DESKMENU_PATH_DBUS,
+ deskmenu);
+
+ if (!dbus_bus_request_name (dbus_g_connection_get_connection (connection),
+ DESKMENU_SERVICE_DBUS,
+ DBUS_NAME_FLAG_REPLACE_EXISTING,
+ NULL))
+ return 1;
+
+ gtk_main ();
+
+ return 0;
+}
+