[Xfce4-commits] <xfce4-panel:devel> Make more things work in the launcher.

Nick Schermer nick at xfce.org
Thu Sep 3 21:30:04 CEST 2009


Updating branch refs/heads/devel
         to 356a39f9b587b5e8674c9742d2584fd0f1eed073 (commit)
       from 54d646a41079dc097468229c43b956a871096d2e (commit)

commit 356a39f9b587b5e8674c9742d2584fd0f1eed073
Author: Nick Schermer <nick at xfce.org>
Date:   Thu Sep 3 18:21:23 2009 +0200

    Make more things work in the launcher.
    
    Use Garcon for the launcher entries and use GIO for file
    monitoring. Also use the exo item editor for editing menu
    items.

 configure.in.in                        |    2 +-
 plugins/launcher/Makefile.am           |   10 +-
 plugins/launcher/launcher-dialog.c     |  713 +++++++++++++-------------------
 plugins/launcher/launcher-dialog.glade |  289 -------------
 plugins/launcher/launcher.c            |  423 ++++++++++++-------
 plugins/launcher/launcher.h            |    2 -
 plugins/launcher/launcher.menu         |   15 -
 7 files changed, 550 insertions(+), 904 deletions(-)

diff --git a/configure.in.in b/configure.in.in
index eeb28e5..727aeb3 100644
--- a/configure.in.in
+++ b/configure.in.in
@@ -97,7 +97,7 @@ dnl ***********************************
 dnl *** Check for required packages ***
 dnl ***********************************
 XDT_CHECK_PACKAGE([LIBXFCE4UTIL], [libxfce4util-1.0], [4.6.0])
-XDT_CHECK_PACKAGE([LIBXFCE4MENU], [libxfce4menu-0.1], [4.6.0])
+XDT_CHECK_PACKAGE([GARCON], [garcon-1], [0.0.1])
 XDT_CHECK_PACKAGE([LIBXFCE4UI], [libxfce4ui-1], [4.7.0])
 XDT_CHECK_PACKAGE([XFCONF], [libxfconf-0], [4.6.0])
 XDT_CHECK_PACKAGE([EXO], [exo-1], [0.5.0])
diff --git a/plugins/launcher/Makefile.am b/plugins/launcher/Makefile.am
index ec1c8f3..a24e6d9 100644
--- a/plugins/launcher/Makefile.am
+++ b/plugins/launcher/Makefile.am
@@ -29,7 +29,7 @@ liblauncher_la_CFLAGS = \
 	$(GTK_CFLAGS) \
 	$(LIBXFCE4UTIL_CFLAGS) \
 	$(LIBXFCE4UI_CFLAGS) \
-	$(LIBXFCE4MENU_CFLAGS) \
+	$(GARCON_CFLAGS) \
 	$(EXO_CFLAGS) \
 	$(XFCONF_CFLAGS) \
 	$(DBUS_CFLAGS) \
@@ -47,7 +47,7 @@ liblauncher_la_LIBADD = \
 	$(GTK_LIBS) \
 	$(LIBXFCE4UTIL_LIBS) \
 	$(LIBXFCE4UI_LIBS) \
-	$(LIBXFCE4MENU_LIBS) \
+	$(GARCON_LIBS) \
 	$(EXO_LIBS) \
 	$(DBUS_LIBS) \
 	$(XFCONF_LIBS)
@@ -64,12 +64,6 @@ desktop_in_files = launcher.desktop.in
 desktop_DATA = $(desktop_in_files:.desktop.in=.desktop)
 @INTLTOOL_DESKTOP_RULE@
 
-#
-# .menu file
-#
-menudir = $(sysconfdir)/xdg/menus
-menu_DATA = launcher.menu
-
 EXTRA_DIST = \
 	launcher-dialog.glade \
 	$(menu_DATA) \
diff --git a/plugins/launcher/launcher-dialog.c b/plugins/launcher/launcher-dialog.c
index 2e6bf36..a1dad25 100644
--- a/plugins/launcher/launcher-dialog.c
+++ b/plugins/launcher/launcher-dialog.c
@@ -28,12 +28,22 @@
 #include <exo/exo.h>
 #include <libxfce4ui/libxfce4ui.h>
 #include <libxfce4util/libxfce4util.h>
+#include <garcon/garcon.h>
+#include <xfconf/xfconf.h>
+
 #include <common/panel-private.h>
 
 #include "launcher.h"
 #include "launcher-dialog.h"
 #include "launcher-dialog_glade.h"
 
+#ifdef GDK_WINDOWING_X11
+#include <gdk/gdkx.h>
+#define LAUNCHER_WIDGET_XID(widget) ((gint) GDK_WINDOW_XID (GDK_WINDOW ((widget)->window)))
+#else
+#define LAUNCHER_WIDGET_XID(widget) (0)
+#endif
+
 
 
 typedef struct
@@ -41,6 +51,7 @@ typedef struct
   LauncherPlugin *plugin;
   GtkBuilder     *builder;
   guint           idle_populate_id;
+  GSList         *items;
 }
 LauncherPluginDialog;
 
@@ -54,7 +65,11 @@ enum
 
 
 
-static void launcher_dialog_items_insert_item (GtkListStore *store, GtkTreeIter *iter, XfceMenuItem *item);
+static void launcher_dialog_items_set_item (GtkTreeModel *model, GtkTreeIter *iter, GarconMenuItem *item);
+static void launcher_dialog_tree_save (LauncherPluginDialog *dialog);
+static void launcher_dialog_tree_selection_changed (GtkTreeSelection *selection, LauncherPluginDialog *dialog);
+static void launcher_dialog_items_unload (LauncherPluginDialog *dialog);
+static void launcher_dialog_items_load (LauncherPluginDialog *dialog);
 
 
 
@@ -72,7 +87,7 @@ launcher_dialog_add_visible_function (GtkTreeModel *model,
 
   /* get the search string from the item */
   text = gtk_entry_get_text (GTK_ENTRY (user_data));
-  if (G_UNLIKELY (!IS_STRING (text)))
+  if (G_UNLIKELY (exo_str_is_empty (text)))
     return TRUE;
 
   /* casefold the search text */
@@ -82,7 +97,7 @@ launcher_dialog_add_visible_function (GtkTreeModel *model,
 
   /* try the pre-build search string first */
   gtk_tree_model_get (model, iter, COL_SEARCH, &string, -1);
-  if (IS_STRING (string))
+  if (!exo_str_is_empty (string))
     {
       /* search */
       visible = (strstr (string, text_casefolded) != NULL);
@@ -91,7 +106,7 @@ launcher_dialog_add_visible_function (GtkTreeModel *model,
     {
       /* get the name */
       gtk_tree_model_get (model, iter, COL_NAME, &string, -1);
-      if (IS_STRING (string))
+      if (!exo_str_is_empty (string))
         {
           /* escape and casefold the name */
           escaped = g_markup_escape_text (string, -1);
@@ -122,42 +137,33 @@ launcher_dialog_add_visible_function (GtkTreeModel *model,
 
 
 static void
-launcher_dialog_add_store_insert (gpointer filename,
-                                  gpointer item,
-                                  gpointer user_data)
+launcher_dialog_add_store_insert_menu (GarconMenu   *menu,
+                                       GtkTreeModel *model)
 {
-  GtkListStore *store = GTK_LIST_STORE (user_data);
-  GtkTreeIter   iter;
-  const gchar  *icon_name, *name, *comment;
-  gchar        *markup;
-
-  panel_return_if_fail (XFCE_IS_MENU_ITEM (item));
-  panel_return_if_fail (GTK_IS_LIST_STORE (user_data));
-
-  /* TODO get rid of this and support absolute paths too */
-  icon_name = xfce_menu_item_get_icon_name (item);
-  if (icon_name != NULL
-      && (g_path_is_absolute (icon_name)
-          || !gtk_icon_theme_has_icon (gtk_icon_theme_get_default (), icon_name)))
-    icon_name = NULL;
-
-  /* create a good looking name */
-  comment = xfce_menu_item_get_comment (item);
-  name = xfce_menu_item_get_name (item);
-  if (IS_STRING (comment))
-    markup = g_strdup_printf ("<b>%s</b>\n%s", name, comment);
-  else
-    markup = g_strdup_printf ("<b>%s</b>", name);
+  GList       *li, *items;
+  GList       *menus;
+  GtkTreeIter  iter;
 
-  /* insert the item */
-  gtk_list_store_append (store, &iter);
-  gtk_list_store_set (store, &iter,
-                      COL_ICON, icon_name,
-                      COL_NAME, markup,
-                      COL_ITEM, item,
-                      -1);
+  panel_return_if_fail (GARCON_IS_MENU (menu));
+  panel_return_if_fail (GTK_IS_LIST_STORE (model));
 
-  g_free (markup);
+  /* insert all the items */
+  items = garcon_menu_get_items (menu);
+  for (li = items; li != NULL; li = li->next)
+    {
+      if (!garcon_menu_element_get_visible (GARCON_MENU_ELEMENT (li->data)))
+        continue;
+
+      gtk_list_store_append (GTK_LIST_STORE (model), &iter);
+      launcher_dialog_items_set_item (model, &iter, li->data);
+    }
+  g_list_free (items);
+
+  /* add the submenus */
+  menus = garcon_menu_get_menus (menu);
+  for (li = menus; li != NULL; li = li->next)
+    launcher_dialog_add_store_insert_menu (li->data, model);
+  g_list_free (menus);
 }
 
 
@@ -167,39 +173,35 @@ launcher_dialog_add_populate_model_idle (gpointer user_data)
 {
   LauncherPluginDialog *dialog = user_data;
   GObject              *store;
-  XfceMenu             *menu;
+  GarconMenu           *menu;
   GError               *error = NULL;
 
   panel_return_val_if_fail (GTK_IS_BUILDER (dialog->builder), FALSE);
 
   GDK_THREADS_ENTER ();
 
-  /* initialize the menu library */
-  xfce_menu_init (NULL);
-
   /* load our menu file */
-  menu = xfce_menu_new (SYSCONFDIR "/xdg/menus/launcher.menu", &error);
-  if (G_UNLIKELY (menu != NULL))
+  menu = garcon_menu_new_applications ();
+  if (G_UNLIKELY (menu == NULL))
+    {
+      g_message ("Failed to load the applications menu.");
+    }
+  else if (G_LIKELY (garcon_menu_load (menu, NULL, &error)))
     {
       /* start appending items in the store */
       store = gtk_builder_get_object (dialog->builder, "add-store");
 
-      /* get the item pool and insert everything in the store */
-      xfce_menu_item_pool_foreach (xfce_menu_get_item_pool (menu),
-                                   launcher_dialog_add_store_insert,
-                                   store);
-
-      /* release the menu */
-      g_object_unref (G_OBJECT (menu));
+      /* add the menu */
+      launcher_dialog_add_store_insert_menu (menu, GTK_TREE_MODEL (store));
     }
   else
     {
-      /* TODO */
+      g_message ("Failed to load the applications menu: %s.", error->message);
       g_error_free (error);
     }
 
-  /* shutdown menu library */
-  xfce_menu_shutdown ();
+  if (G_LIKELY (menu != NULL))
+    g_object_unref (G_OBJECT (menu));
 
   GDK_THREADS_LEAVE ();
 
@@ -254,15 +256,96 @@ launcher_dialog_add_selection_changed (GtkTreeSelection     *selection,
 
 
 
+static void
+launcher_dialog_add_response (GtkWidget            *widget,
+                              gint                  response_id,
+                              LauncherPluginDialog *dialog)
+{
+  GObject          *treeview, *store;
+  GtkTreeSelection *selection;
+  GtkTreeModel     *item_model, *add_model;
+  GtkTreeIter       iter, sibling, tmp;
+  GarconMenuItem   *item;
+  GList            *list, *li;
+
+  panel_return_if_fail (GTK_IS_DIALOG (widget));
+  panel_return_if_fail (XFCE_IS_LAUNCHER_PLUGIN (dialog->plugin));
+
+  if (response_id != 0)
+    {
+      /* add all the selected rows in the add dialog */
+      treeview = gtk_builder_get_object (dialog->builder, "add-treeview");
+      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
+      list = gtk_tree_selection_get_selected_rows (selection, &add_model);
+
+      /* append after the selected item in the item dialog */
+      treeview = gtk_builder_get_object (dialog->builder, "item-treeview");
+      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
+      item_model = gtk_tree_view_get_model (GTK_TREE_VIEW (treeview));
+      if (gtk_tree_selection_get_selected (selection, NULL, &sibling))
+        gtk_list_store_insert_after (GTK_LIST_STORE (item_model),
+                                     &iter, &sibling);
+      else
+        gtk_list_store_append (GTK_LIST_STORE (item_model), &iter);
+
+      for (li = list; li != NULL; li = g_list_next (li))
+        {
+          /* get the selected file in the add dialog */
+          gtk_tree_model_get_iter (add_model, &tmp, li->data);
+          gtk_tree_model_get (add_model, &tmp, COL_ITEM, &item, -1);
+
+          /* insert the item in the item store */
+          if (G_LIKELY (item != NULL))
+            {
+              launcher_dialog_items_set_item (item_model, &iter, item);
+              g_object_unref (G_OBJECT (item));
+
+              /* select the first item */
+              if (li == list)
+                gtk_tree_selection_select_iter (selection, &iter);
+            }
+
+          /* cleanup */
+          gtk_tree_path_free (li->data);
+
+          if (g_list_next (li) != NULL)
+            {
+              /* insert a new iter after the new added item */
+              sibling = iter;
+              gtk_list_store_insert_after (GTK_LIST_STORE (item_model),
+                                           &iter, &sibling);
+            }
+        }
+
+      /* cleanup */
+      g_list_free (list);
+
+      /* write the model to xfconf */
+      launcher_dialog_tree_save (dialog);
+
+      /* update the selection */
+      launcher_dialog_tree_selection_changed (selection, dialog);
+    }
+
+  /* empty the store */
+  store = gtk_builder_get_object (dialog->builder, "add-store");
+  gtk_list_store_clear (GTK_LIST_STORE (store));
+
+  /* hide the dialog, since it's owned by gtkbuilder */
+  gtk_widget_hide (widget);
+}
+
+
+
 static gboolean
 launcher_dialog_tree_save_foreach (GtkTreeModel *model,
                                    GtkTreePath  *path,
                                    GtkTreeIter  *iter,
                                    gpointer      user_data)
 {
-  GPtrArray    *array = user_data;
-  GValue       *value;
-  XfceMenuItem *item;
+  GPtrArray      *array = user_data;
+  GValue         *value;
+  GarconMenuItem *item;
 
   /* get the desktop id of the item from the store */
   gtk_tree_model_get (model, iter, COL_ITEM, &item, -1);
@@ -271,7 +354,7 @@ launcher_dialog_tree_save_foreach (GtkTreeModel *model,
       /* create a value with the filename */
       value = g_new0 (GValue, 1);
       g_value_init (value, G_TYPE_STRING);
-      g_value_set_static_string (value, xfce_menu_item_get_filename (item));
+      g_value_take_string (value, garcon_menu_item_get_uri (item));
 
       /* put it in the array and release */
       g_ptr_array_add (array, value);
@@ -294,6 +377,7 @@ launcher_dialog_tree_save (LauncherPluginDialog *dialog)
   array = g_ptr_array_new ();
   gtk_tree_model_foreach (GTK_TREE_MODEL (store),
                           launcher_dialog_tree_save_foreach, array);
+
   g_object_set (dialog->plugin, "items", array, NULL);
   xfconf_array_free (array);
 }
@@ -307,7 +391,8 @@ launcher_dialog_tree_selection_changed (GtkTreeSelection     *selection,
   GObject      *object;
   GtkTreeModel *model;
   GtkTreeIter   iter;
-  gint          n_children = -1, position = 0;
+  gint          n_children = -1;
+  gint          position = 0;
   GtkTreePath  *path;
   gboolean      sensitive;
 
@@ -354,70 +439,32 @@ launcher_dialog_tree_selection_changed (GtkTreeSelection     *selection,
 
 
 static void
-launcher_dialog_editor_populate (LauncherPluginDialog *dialog,
-                                 XfceMenuItem         *item)
-{
-  GObject     *object;
-  const gchar *path;
-
-  panel_return_if_fail (XFCE_IS_LAUNCHER_PLUGIN (dialog->plugin));
-  panel_return_if_fail (GTK_IS_BUILDER (dialog->builder));
-  panel_return_if_fail (XFCE_IS_MENU_ITEM (item));
-
-  object = gtk_builder_get_object (dialog->builder, "item-name");
-  panel_return_if_fail (GTK_IS_WIDGET (object));
-  gtk_entry_set_text (GTK_ENTRY (object),
-      xfce_menu_item_get_name (item));
-
-  object = gtk_builder_get_object (dialog->builder, "item-description");
-  panel_return_if_fail (GTK_IS_WIDGET (object));
-  gtk_entry_set_text (GTK_ENTRY (object),
-      xfce_menu_item_get_comment (item));
-
-  object = gtk_builder_get_object (dialog->builder, "item-command");
-  panel_return_if_fail (GTK_IS_WIDGET (object));
-  gtk_entry_set_text (GTK_ENTRY (object),
-      xfce_menu_item_get_command (item));
-
-  object = gtk_builder_get_object (dialog->builder, "item-working-directory");
-  panel_return_if_fail (GTK_IS_WIDGET (object));
-  path = xfce_menu_item_get_path (item);
-  gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (object),
-                                       path != NULL ? path : "");
-
-  object = gtk_builder_get_object (dialog->builder, "item-terminal");
-  panel_return_if_fail (GTK_IS_WIDGET (object));
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (object),
-      xfce_menu_item_requires_terminal (item));
-
-  object = gtk_builder_get_object (dialog->builder, "item-startup-notify");
-  panel_return_if_fail (GTK_IS_WIDGET (object));
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (object),
-      xfce_menu_item_supports_startup_notification (item));
-}
-
-
-
-static void
 launcher_dialog_item_button_clicked (GtkWidget            *button,
                                      LauncherPluginDialog *dialog)
 {
   const gchar      *name;
+  const gchar      *display_name = NULL;
   GObject          *object;
-  GtkWidget        *window;
   GObject          *treeview;
   GtkTreeSelection *selection;
   GtkTreeModel     *model;
   GtkTreeIter       iter_a, iter_b;
   GtkTreePath      *path;
-  XfceMenuItem     *item = NULL;
+  gchar            *command, *uri;
+  GdkScreen        *screen;
+  GError           *error = NULL;
+  GarconMenuItem   *item;
+  GtkWidget        *toplevel;
 
   panel_return_if_fail (GTK_IS_BUILDABLE (button));
   panel_return_if_fail (GTK_IS_BUILDER (dialog->builder));
 
   /* name of the button */
   name = gtk_buildable_get_name (GTK_BUILDABLE (button));
-  if (exo_str_is_equal (name, "item-add"))
+  if (G_UNLIKELY (name == NULL))
+    return;
+
+  if (strcmp (name, "item-add") == 0)
     {
       object = gtk_builder_get_object (dialog->builder, "dialog-add");
       launcher_dialog_add_populate_model (dialog);
@@ -431,49 +478,48 @@ launcher_dialog_item_button_clicked (GtkWidget            *button,
       if (!gtk_tree_selection_get_selected (selection, &model, &iter_a))
         return;
 
-      if (exo_str_is_equal (name, "item-delete"))
+      if (strcmp (name, "item-delete") == 0)
         {
-          /* create question dialog */
-          window = gtk_message_dialog_new (
-              GTK_WINDOW (gtk_widget_get_toplevel (button)),
-              GTK_DIALOG_DESTROY_WITH_PARENT,
-              GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
-              _("Are you sure you want to remove the selected item?"));
-          gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (window),
-              _("If you delete an item, it is permanently removed from the launcher."));
-          gtk_dialog_add_buttons (GTK_DIALOG (window),
-                                  GTK_STOCK_REMOVE, GTK_RESPONSE_ACCEPT,
-                                  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-                                  NULL);
-          gtk_dialog_set_default_response (GTK_DIALOG (window), GTK_RESPONSE_ACCEPT);
-
-          /* run the dialog */
-          if (gtk_dialog_run (GTK_DIALOG (window)) == GTK_RESPONSE_ACCEPT)
-            gtk_list_store_remove (GTK_LIST_STORE (model), &iter_a);
+          /* get item name */
+          gtk_tree_model_get (model, &iter_a, COL_ITEM, &item, -1);
+          if (G_LIKELY (item != NULL))
+            {
+              display_name = garcon_menu_item_get_name (item);
+              g_object_unref (G_OBJECT (item));
+            }
 
-          /* destroy */
-          gtk_widget_destroy (window);
+          /* ask the user */
+          toplevel = gtk_widget_get_toplevel (button);
+          if (xfce_dialog_confirm (GTK_WINDOW (toplevel), GTK_STOCK_DELETE, NULL,
+                  _("If you delete an item, it will be permanently removed"),
+                  _("Are you sure you want to remove \"%s\"?"), display_name))
+            gtk_list_store_remove (GTK_LIST_STORE (model), &iter_a);
         }
-      else if (exo_str_is_equal (name, "item-edit"))
+      else if (strcmp (name, "item-new") == 0)
+        {
+          /* TODO */
+        }
+      else if (strcmp (name, "item-edit") == 0)
         {
-          /* polulate the dialog */
           gtk_tree_model_get (model, &iter_a, COL_ITEM, &item, -1);
           if (G_UNLIKELY (item == NULL))
             return;
-          launcher_dialog_editor_populate (dialog, item);
 
-          /* show the dialog */
-          object = gtk_builder_get_object (dialog->builder, "dialog-editor");
-          panel_return_if_fail (GTK_IS_WIDGET (object));
-          gtk_widget_show (GTK_WIDGET (object));
-
-          /* create a tree path of the selected item, we use this to
-           * replace the menu item after saving */
-          path = gtk_tree_model_get_path (model, &iter_a);
-          g_object_set_data_full (G_OBJECT (object), "item-path", path,
-              (GDestroyNotify) gtk_tree_path_free);
+          screen = gtk_widget_get_screen (button);
+          uri = garcon_menu_item_get_uri (item);
+          command = g_strdup_printf ("exo-desktop-item-edit --xid=%d '%s'",
+                                     LAUNCHER_WIDGET_XID (button), uri);
+          if (!gdk_spawn_command_line_on_screen (screen, command, &error))
+            {
+              toplevel = gtk_widget_get_toplevel (button);
+              xfce_dialog_show_error (GTK_WINDOW (toplevel), error,
+                  _("Failed to open desktop item editor"));
+              g_error_free (error);
+            }
+          g_free (uri);
+          g_free (command);
         }
-      else if (exo_str_is_equal (name, "item-move-up"))
+      else if (strcmp (name, "item-move-up") == 0)
         {
           path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter_a);
           if (gtk_tree_path_prev (path)
@@ -481,13 +527,16 @@ launcher_dialog_item_button_clicked (GtkWidget            *button,
             gtk_list_store_swap (GTK_LIST_STORE (model), &iter_a, &iter_b);
           gtk_tree_path_free (path);
         }
-      else
+      else if (strcmp (name, "item-move-down") == 0)
         {
-          panel_return_if_fail (exo_str_is_equal (name, "item-move-down"));
           iter_b = iter_a;
           if (gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter_b))
             gtk_list_store_swap (GTK_LIST_STORE (model), &iter_a, &iter_b);
         }
+      else
+        {
+          panel_assert_not_reached ();
+        }
 
       /* store the new settings */
       launcher_dialog_tree_save (dialog);
@@ -518,6 +567,13 @@ launcher_dialog_response (GtkWidget            *widget,
       if (G_UNLIKELY (dialog->idle_populate_id != 0))
         g_source_remove (dialog->idle_populate_id);
 
+      /* disconnect from items-changed signal */
+      g_signal_handlers_disconnect_by_func (G_OBJECT (dialog->plugin),
+          G_CALLBACK (launcher_dialog_items_load), dialog);
+
+      /* disconnect from the menu items */
+      launcher_dialog_items_unload (dialog);
+
       /* destroy the dialog and release the builder */
       gtk_widget_destroy (widget);
       g_object_unref (G_OBJECT (dialog->builder));
@@ -532,301 +588,70 @@ launcher_dialog_response (GtkWidget            *widget,
 
 
 
-static void
-launcher_dialog_editor_icon_chooser (GtkWidget            *button,
-                                     LauncherPluginDialog *dialog)
-{
-  GtkWidget *window;
-
-  /* create icon chooser dialog */
-  window = exo_icon_chooser_dialog_new (_("Select Icon"),
-      GTK_WINDOW (gtk_widget_get_toplevel (button)),
-      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-      GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
-
-  if (gtk_dialog_run (GTK_DIALOG (window)) == GTK_RESPONSE_OK)
-    {
-
-    }
-
-  /* destroy */
-  gtk_widget_destroy (window);
-}
-
-
-
-static void
-launcher_dialog_editor_write_value (XfceRc      *rc,
-                                    GtkBuilder  *builder,
-                                    const gchar *name,
-                                    const gchar *key)
-{
-  GObject     *object;
-  const gchar *text;
-
-  panel_return_if_fail (GTK_IS_BUILDER (builder));
-
-  object = gtk_builder_get_object (builder, name);
-  panel_return_if_fail (GTK_IS_WIDGET (object));
-  text = gtk_entry_get_text (GTK_ENTRY (object));
-  if (IS_STRING (text))
-    xfce_rc_write_entry (rc, key, text);
-  else
-    xfce_rc_delete_entry (rc, key, FALSE);
-}
-
-
-
-static void
-launcher_dialog_editor_response (GtkWidget            *widget,
-                                 gint                  response_id,
-                                 LauncherPluginDialog *dialog)
+static gboolean
+launcher_dialog_item_changed_foreach (GtkTreeModel *model,
+                                      GtkTreePath  *path,
+                                      GtkTreeIter  *iter,
+                                      gpointer      user_data)
 {
-  GObject      *object;
-  GtkTreePath  *path;
-  XfceMenuItem *item = NULL;
-  gchar        *user_dir, *new_file = NULL;
-  const gchar  *filename;
-  guint         i;
-  GtkTreeModel *model;
-  GtkTreeIter   iter;
-  XfceRc       *rc;
-  const gchar  *origional_file = NULL;
-  gchar        *folder;
-
-  panel_return_if_fail (GTK_IS_DIALOG (widget));
-  panel_return_if_fail (XFCE_IS_LAUNCHER_PLUGIN (dialog->plugin));
-  panel_return_if_fail (GTK_IS_BUILDER (dialog->builder));
-
-  if (response_id == 2)
-    {
-      /* get the user directory */
-      user_dir = xfce_resource_save_location (XFCE_RESOURCE_CONFIG,
-          "xfce4" G_DIR_SEPARATOR_S "xfce4-panel" G_DIR_SEPARATOR_S, TRUE);
-      if (G_UNLIKELY (user_dir == NULL))
-        {
-          g_critical ("Failed to create the panel config directory.");
-          goto leave;
-        }
-
-      object = gtk_builder_get_object (dialog->builder, "item-treeview");
-      panel_return_if_fail (GTK_IS_WIDGET (object));
-      model = gtk_tree_view_get_model (GTK_TREE_VIEW (object));
-
-      /* get the menu item attached to the dialog */
-      path = g_object_get_data (G_OBJECT (widget), "item-path");
-      if (!gtk_tree_model_get_iter (model, &iter, path))
-        goto leave;
-      gtk_tree_model_get (model, &iter, COL_ITEM, &item, -1);
-      panel_return_if_fail (XFCE_IS_MENU_ITEM (item));
-
-      /* check if the item is already in the users directory */
-      filename = xfce_menu_item_get_filename (item);
-      if (!g_str_has_prefix (filename, user_dir))
-        {
-          /* create a unique filename for the copy */
-          for (i = 1; i < 100 /* arbitairy limit */; i++)
-            {
-              /* create the new filename */
-              new_file = g_strdup_printf ("%slauncher-%d-%d.desktop",
-                  user_dir,
-                  xfce_panel_plugin_get_unique_id (XFCE_PANEL_PLUGIN (dialog->plugin)),
-                  i++);
-
-              /* we're done if the file does not exist yet */
-              if (!g_file_test (new_file, G_FILE_TEST_IS_REGULAR))
-                break;
-
-              /* cleanup before we try again */
-              g_free (new_file);
-            }
-
-          /* remember the origional file for the forked desktop file */
-          origional_file = filename;
-
-          /* set new filename */
-          filename = new_file;
-        }
-
-      /* cleanup */
-      g_free (user_dir);
-
-      /* store the new item data */
-      rc = xfce_rc_simple_open (filename, FALSE);
-      if (G_LIKELY (rc != NULL))
-        {
-          /* write some default stuff */
-          xfce_rc_set_group (rc, "Desktop Entry");
-          xfce_rc_write_entry (rc, "Type", "Application");
-          xfce_rc_write_entry (rc, "Encoding", "UTF-8");
-
-          /* remember the origional desktop file */
-          if (G_UNLIKELY (origional_file != NULL))
-            xfce_rc_write_entry (rc, "X-XFCE-Origional", origional_file);
-
-          /* write text entries */
-          launcher_dialog_editor_write_value (rc, dialog->builder,
-                                              "item-name",
-                                              "Name");
-          launcher_dialog_editor_write_value (rc, dialog->builder,
-                                              "item-description",
-                                              "Comment");
-          launcher_dialog_editor_write_value (rc, dialog->builder,
-                                              "item-command",
-                                              "Exec");
-
-          object = gtk_builder_get_object (dialog->builder, "item-working-directory");
-          panel_return_if_fail (GTK_IS_WIDGET (object));
-          folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (object));
-          xfce_rc_write_entry (rc, "Path", folder);
-          g_free (folder);
-
-          object = gtk_builder_get_object (dialog->builder, "item-terminal");
-          panel_return_if_fail (GTK_IS_WIDGET (object));
-          xfce_rc_write_bool_entry (rc, "Terminal",
-              gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (object)));
+  GarconMenuItem *item;
+  gboolean        found;
 
-          object = gtk_builder_get_object (dialog->builder, "item-startup-notify");
-          panel_return_if_fail (GTK_IS_WIDGET (object));
-          xfce_rc_write_bool_entry (rc, "StartupNotify",
-              gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (object)));
-
-          xfce_rc_close (rc);
-        }
+  panel_return_val_if_fail (GARCON_IS_MENU_ITEM (user_data), TRUE);
 
-      /* release the menu item */
-      if (G_LIKELY (item != NULL))
-        g_object_unref (G_OBJECT (item));
+  /* check if this is the item in the model */
+  gtk_tree_model_get (model, iter, COL_ITEM, &item, -1);
+  found = item == user_data;
 
-      /* update the model */
-      item = xfce_menu_item_new (filename);
-      if (G_LIKELY (item != NULL))
-        {
-          launcher_dialog_items_insert_item (GTK_LIST_STORE (model),
-                                             &iter, item);
-          g_object_unref (G_OBJECT (item));
-        }
+  if (G_UNLIKELY (found))
+    launcher_dialog_items_set_item (model, iter, item);
 
-      /* cleanup */
-      g_free (new_file);
+  g_object_unref (G_OBJECT (item));
 
-      /* write the model to xfconf */
-      launcher_dialog_tree_save (dialog);
-    }
-
-leave:
-  /* hide the dialog, since it's owned by gtkbuilder */
-  gtk_widget_hide (widget);
-
-  /* unset the item path */
-  g_object_set_data (G_OBJECT (widget), "item-path", NULL);
+  return found;
 }
 
 
 
 static void
-launcher_dialog_add_response (GtkWidget            *widget,
-                              gint                  response_id,
+launcher_dialog_item_changed (GarconMenuItem       *item,
                               LauncherPluginDialog *dialog)
 {
-  GObject          *treeview, *store;
-  GtkTreeSelection *selection;
-  GtkTreeModel     *item_model, *add_model;
-  GtkTreeIter       iter, sibling, tmp;
-  XfceMenuItem     *item;
-  GList            *list, *li;
-
-  panel_return_if_fail (GTK_IS_DIALOG (widget));
-  panel_return_if_fail (XFCE_IS_LAUNCHER_PLUGIN (dialog->plugin));
-
-  if (response_id != 0)
-    {
-      /* add all the selected rows in the add dialog */
-      treeview = gtk_builder_get_object (dialog->builder, "add-treeview");
-      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
-      list = gtk_tree_selection_get_selected_rows (selection, &add_model);
-
-      /* append after the selected item in the item dialog */
-      treeview = gtk_builder_get_object (dialog->builder, "item-treeview");
-      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
-      item_model = gtk_tree_view_get_model (GTK_TREE_VIEW (treeview));
-      if (gtk_tree_selection_get_selected (selection, NULL, &sibling))
-        gtk_list_store_insert_after (GTK_LIST_STORE (item_model),
-                                     &iter, &sibling);
-      else
-        gtk_list_store_append (GTK_LIST_STORE (item_model), &iter);
-
-      for (li = list; li != NULL; li = g_list_next (li))
-        {
-          /* get the selected file in the add dialog */
-          gtk_tree_model_get_iter (add_model, &tmp, li->data);
-          gtk_tree_model_get (add_model, &tmp, COL_ITEM, &item, -1);
-
-          /* insert the item in the item store */
-          if (G_LIKELY (item != NULL))
-            {
-              launcher_dialog_items_insert_item (GTK_LIST_STORE (item_model),
-                                                 &iter, item);
-              g_object_unref (G_OBJECT (item));
-
-              /* select the first item */
-              if (li == list)
-                gtk_tree_selection_select_iter (selection, &iter);
-            }
-
-          /* cleanup */
-          gtk_tree_path_free (li->data);
-
-          if (g_list_next (li) != NULL)
-            {
-              /* insert a new iter after the new added item */
-              sibling = iter;
-              gtk_list_store_insert_after (GTK_LIST_STORE (item_model),
-                                           &iter, &sibling);
-            }
-        }
-
-      /* cleanup */
-      g_list_free (list);
-
-      /* write the model to xfconf */
-      launcher_dialog_tree_save (dialog);
+  GObject      *treeview;
+  GtkTreeModel *model;
 
-      /* update the selection */
-      launcher_dialog_tree_selection_changed (selection, dialog);
-    }
+  panel_return_if_fail (GARCON_IS_MENU_ITEM (item));
 
-  /* empty the store */
-  store = gtk_builder_get_object (dialog->builder, "add-store");
-  gtk_list_store_clear (GTK_LIST_STORE (store));
+  treeview = gtk_builder_get_object (dialog->builder, "item-treeview");
+  model = gtk_tree_view_get_model (GTK_TREE_VIEW (treeview));
 
-  /* hide the dialog, since it's owned by gtkbuilder */
-  gtk_widget_hide (widget);
+  /* find the item in the model and update it */
+  gtk_tree_model_foreach (model, launcher_dialog_item_changed_foreach, item);
 }
 
 
 
 static void
-launcher_dialog_items_insert_item (GtkListStore *store,
-                                   GtkTreeIter  *iter,
-                                   XfceMenuItem *item)
+launcher_dialog_items_set_item (GtkTreeModel   *model,
+                                GtkTreeIter    *iter,
+                                GarconMenuItem *item)
 {
   const gchar *name, *comment;
   gchar       *markup;
 
-  panel_return_if_fail (GTK_IS_LIST_STORE (store));
-  panel_return_if_fail (XFCE_IS_MENU_ITEM (item));
+  panel_return_if_fail (GTK_IS_LIST_STORE (model));
+  panel_return_if_fail (GARCON_IS_MENU_ITEM (item));
 
-  name = xfce_menu_item_get_name (item);
-  comment = xfce_menu_item_get_comment (item);
+  name = garcon_menu_item_get_name (item);
+  comment = garcon_menu_item_get_comment (item);
 
-  if (IS_STRING (comment))
+  if (!exo_str_is_empty (comment))
     markup = g_strdup_printf ("<b>%s</b>\n%s", name, comment);
   else
     markup = g_strdup_printf ("<b>%s</b>", name);
 
-  gtk_list_store_set (GTK_LIST_STORE (store), iter,
-                      COL_ICON, xfce_menu_item_get_icon_name (item),
+  gtk_list_store_set (GTK_LIST_STORE (model), iter,
+                      COL_ICON, garcon_menu_item_get_icon_name (item),
                       COL_NAME, markup,
                       COL_ITEM, item,
                       -1);
@@ -837,34 +662,67 @@ launcher_dialog_items_insert_item (GtkListStore *store,
 
 
 static void
+launcher_dialog_items_unload (LauncherPluginDialog *dialog)
+{
+  GSList *li;
+
+  for (li = dialog->items; li != NULL; li = li->next)
+    {
+      panel_return_if_fail (GARCON_IS_MENU_ITEM (li->data));
+      g_signal_handlers_disconnect_by_func (G_OBJECT (li->data),
+          G_CALLBACK (launcher_dialog_item_changed), dialog);
+      g_object_unref (G_OBJECT (li->data));
+    }
+
+  g_slist_free (dialog->items);
+  dialog->items = NULL;
+}
+
+
+
+static void
 launcher_dialog_items_load (LauncherPluginDialog *dialog)
 {
   GObject          *treeview;
   GtkTreeSelection *selection;
   GtkTreeModel     *model;
-  GSList           *items, *li;
+  GSList           *li;
   GtkTreeIter       iter;
+  GtkTreePath      *path;
 
   /* get the treeview */
   treeview = gtk_builder_get_object (dialog->builder, "item-treeview");
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
 
-  /* get the model and clear it */
-  model = gtk_tree_view_get_model (GTK_TREE_VIEW (treeview));
+  /* we try to preserve the current selection */
+  if (gtk_tree_selection_get_selected (selection, &model, &iter))
+    path = gtk_tree_model_get_path (model, &iter);
+  else
+    path = NULL;
+
+  /* clear the old items */
+  launcher_dialog_items_unload (dialog);
   gtk_list_store_clear (GTK_LIST_STORE (model));
 
   /* insert the launcher items */
-  items = launcher_plugin_get_items (dialog->plugin);
-  for (li = items; li != NULL; li = li->next)
+  dialog->items = launcher_plugin_get_items (dialog->plugin);
+  for (li = dialog->items; li != NULL; li = li->next)
     {
       gtk_list_store_append (GTK_LIST_STORE (model), &iter);
-      launcher_dialog_items_insert_item (GTK_LIST_STORE (model),
-                                         &iter, XFCE_MENU_ITEM (li->data));
+      launcher_dialog_items_set_item (model, &iter, GARCON_MENU_ITEM (li->data));
+      g_signal_connect (G_OBJECT (li->data), "changed",
+          G_CALLBACK (launcher_dialog_item_changed), dialog);
     }
 
-  /* select the first item */
-  if (gtk_tree_model_get_iter_first (model, &iter))
+  if (G_LIKELY (path != NULL))
     {
-      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
+      /* restore the old selection */
+      gtk_tree_selection_select_path (selection, path);
+      gtk_tree_path_free (path);
+    }
+  else if (gtk_tree_model_get_iter_first (model, &iter))
+    {
+      /* select the first item */
       gtk_tree_selection_select_iter (selection, &iter);
     }
 }
@@ -889,12 +747,13 @@ launcher_dialog_show (LauncherPlugin *plugin)
 
   builder = gtk_builder_new ();
   if (gtk_builder_add_from_string (builder, launcher_dialog_glade,
-                                   launcher_dialog_glade_length, NULL))
+                                    launcher_dialog_glade_length, NULL))
     {
       /* create structure */
       dialog = g_slice_new0 (LauncherPluginDialog);
       dialog->builder = builder;
       dialog->plugin = plugin;
+      dialog->items = NULL;
 
       /* block plugin menu */
       xfce_panel_plugin_block_menu (XFCE_PANEL_PLUGIN (plugin));
@@ -922,7 +781,7 @@ launcher_dialog_show (LauncherPlugin *plugin)
           G_CALLBACK (launcher_dialog_tree_selection_changed), dialog);
       launcher_dialog_tree_selection_changed (selection, dialog);
 
-      /* connect binding to the advanced properties */
+      /* connect bindings to the advanced properties */
       for (i = 0; i < G_N_ELEMENTS (binding_names); i++)
         {
           object = gtk_builder_get_object (builder, binding_names[i]);
@@ -931,24 +790,14 @@ launcher_dialog_show (LauncherPlugin *plugin)
                                   G_OBJECT (object), "active");
         }
 
-      /* setup responses for the other dialogs */
-      object = gtk_builder_get_object (builder, "dialog-editor");
-      g_signal_connect (G_OBJECT (object), "response",
-          G_CALLBACK (launcher_dialog_editor_response), dialog);
-      g_signal_connect (G_OBJECT (object), "delete-event",
-          G_CALLBACK (exo_noop_true), NULL);
-
+      /* setup responses for the add dialog */
       object = gtk_builder_get_object (builder, "dialog-add");
       g_signal_connect (G_OBJECT (object), "response",
           G_CALLBACK (launcher_dialog_add_response), dialog);
       g_signal_connect (G_OBJECT (object), "delete-event",
-          G_CALLBACK (exo_noop_true), NULL);
-
-      object = gtk_builder_get_object (builder, "item-icon");
-      g_signal_connect (G_OBJECT (object), "clicked",
-          G_CALLBACK (launcher_dialog_editor_icon_chooser), dialog);
+          G_CALLBACK (gtk_true), NULL);
 
-      /* enable sorting in the add dialog */
+      /* setup sorting in the add dialog */
       object = gtk_builder_get_object (builder, "add-store");
       gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (object),
                                             COL_NAME, GTK_SORT_ASCENDING);
@@ -976,6 +825,8 @@ launcher_dialog_show (LauncherPlugin *plugin)
 
       /* load the plugin items */
       launcher_dialog_items_load (dialog);
+      g_signal_connect_swapped (G_OBJECT (plugin), "items-changed",
+          G_CALLBACK (launcher_dialog_items_load), dialog);
 
       /* show the dialog */
       gtk_widget_show (GTK_WIDGET (window));
diff --git a/plugins/launcher/launcher-dialog.glade b/plugins/launcher/launcher-dialog.glade
index 93fd300..29b19f2 100644
--- a/plugins/launcher/launcher-dialog.glade
+++ b/plugins/launcher/launcher-dialog.glade
@@ -402,295 +402,6 @@
       <action-widget response="0">button2</action-widget>
     </action-widgets>
   </object>
-  <object class="XfceTitledDialog" id="dialog-editor">
-    <property name="title" translatable="yes">Edit Custom Launcher</property>
-    <property name="window_position">center-on-parent</property>
-    <property name="destroy_with_parent">True</property>
-    <property name="icon_name">applications-other</property>
-    <property name="type_hint">normal</property>
-    <property name="has_separator">False</property>
-    <child internal-child="vbox">
-      <object class="GtkVBox" id="dialog-vbox3">
-        <property name="visible">True</property>
-        <property name="spacing">2</property>
-        <child>
-          <object class="GtkTable" id="table3">
-            <property name="visible">True</property>
-            <property name="border_width">6</property>
-            <property name="n_rows">7</property>
-            <property name="n_columns">2</property>
-            <property name="column_spacing">12</property>
-            <property name="row_spacing">6</property>
-            <child>
-              <object class="GtkLabel" id="label16">
-                <property name="visible">True</property>
-                <property name="xalign">0</property>
-                <property name="label" translatable="yes">_Name:</property>
-                <property name="use_underline">True</property>
-              </object>
-              <packing>
-                <property name="x_options">GTK_FILL</property>
-                <property name="y_options">GTK_FILL</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkLabel" id="label17">
-                <property name="visible">True</property>
-                <property name="xalign">0</property>
-                <property name="label" translatable="yes">C_omment:</property>
-                <property name="use_underline">True</property>
-              </object>
-              <packing>
-                <property name="top_attach">1</property>
-                <property name="bottom_attach">2</property>
-                <property name="x_options">GTK_FILL</property>
-                <property name="y_options">GTK_FILL</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkLabel" id="label20">
-                <property name="visible">True</property>
-                <property name="xalign">0</property>
-                <property name="label" translatable="yes">_Working Directory:</property>
-                <property name="use_underline">True</property>
-              </object>
-              <packing>
-                <property name="top_attach">4</property>
-                <property name="bottom_attach">5</property>
-                <property name="x_options">GTK_FILL</property>
-                <property name="y_options">GTK_FILL</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkLabel" id="label21">
-                <property name="visible">True</property>
-              </object>
-              <packing>
-                <property name="top_attach">5</property>
-                <property name="bottom_attach">7</property>
-                <property name="x_options">GTK_FILL</property>
-                <property name="y_options">GTK_FILL</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkEntry" id="item-name">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-              </object>
-              <packing>
-                <property name="left_attach">1</property>
-                <property name="right_attach">2</property>
-                <property name="y_options">GTK_FILL</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkEntry" id="item-description">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-              </object>
-              <packing>
-                <property name="left_attach">1</property>
-                <property name="right_attach">2</property>
-                <property name="top_attach">1</property>
-                <property name="bottom_attach">2</property>
-                <property name="y_options">GTK_FILL</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkFileChooserButton" id="item-working-directory">
-                <property name="visible">True</property>
-                <property name="action">select-folder</property>
-                <property name="title" translatable="yes">Select a Working Directory</property>
-              </object>
-              <packing>
-                <property name="left_attach">1</property>
-                <property name="right_attach">2</property>
-                <property name="top_attach">4</property>
-                <property name="bottom_attach">5</property>
-                <property name="y_options">GTK_FILL</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkCheckButton" id="item-terminal">
-                <property name="label" translatable="yes">Run in _terminal</property>
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">False</property>
-                <property name="use_underline">True</property>
-                <property name="draw_indicator">True</property>
-              </object>
-              <packing>
-                <property name="left_attach">1</property>
-                <property name="right_attach">2</property>
-                <property name="top_attach">5</property>
-                <property name="bottom_attach">6</property>
-                <property name="y_options">GTK_FILL</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkCheckButton" id="item-startup-notify">
-                <property name="label" translatable="yes">Use _statup notification</property>
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">False</property>
-                <property name="use_underline">True</property>
-                <property name="draw_indicator">True</property>
-              </object>
-              <packing>
-                <property name="left_attach">1</property>
-                <property name="right_attach">2</property>
-                <property name="top_attach">6</property>
-                <property name="bottom_attach">7</property>
-                <property name="y_options">GTK_FILL</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkLabel" id="label2">
-                <property name="visible">True</property>
-                <property name="xalign">0</property>
-                <property name="label" translatable="yes">Comm_and:</property>
-                <property name="use_underline">True</property>
-              </object>
-              <packing>
-                <property name="top_attach">2</property>
-                <property name="bottom_attach">3</property>
-                <property name="x_options">GTK_FILL</property>
-                <property name="y_options">GTK_FILL</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkLabel" id="label3">
-                <property name="visible">True</property>
-                <property name="xalign">0</property>
-                <property name="label" translatable="yes">_Icon:</property>
-                <property name="use_underline">True</property>
-              </object>
-              <packing>
-                <property name="top_attach">3</property>
-                <property name="bottom_attach">4</property>
-                <property name="x_options">GTK_FILL</property>
-                <property name="y_options">GTK_FILL</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkHBox" id="hbox3">
-                <property name="visible">True</property>
-                <property name="spacing">6</property>
-                <child>
-                  <object class="GtkEntry" id="item-command">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                  </object>
-                  <packing>
-                    <property name="position">0</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkButton" id="item-open">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">True</property>
-                    <child>
-                      <object class="GtkImage" id="image5">
-                        <property name="visible">True</property>
-                        <property name="stock">gtk-open</property>
-                        <property name="icon-size">1</property>
-                      </object>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="position">1</property>
-                  </packing>
-                </child>
-              </object>
-              <packing>
-                <property name="left_attach">1</property>
-                <property name="right_attach">2</property>
-                <property name="top_attach">2</property>
-                <property name="bottom_attach">3</property>
-                <property name="y_options">GTK_FILL</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkAlignment" id="alignment2">
-                <property name="visible">True</property>
-                <property name="xalign">0</property>
-                <property name="xscale">0</property>
-                <child>
-                  <object class="GtkButton" id="item-icon">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="receives_default">True</property>
-                    <child>
-                      <object class="GtkImage" id="image6">
-                        <property name="visible">True</property>
-                        <property name="stock">gtk-missing-image</property>
-                        <property name="icon-size">5</property>
-                      </object>
-                    </child>
-                  </object>
-                </child>
-              </object>
-              <packing>
-                <property name="left_attach">1</property>
-                <property name="right_attach">2</property>
-                <property name="top_attach">3</property>
-                <property name="bottom_attach">4</property>
-                <property name="y_options">GTK_FILL</property>
-              </packing>
-            </child>
-          </object>
-          <packing>
-            <property name="position">1</property>
-          </packing>
-        </child>
-        <child internal-child="action_area">
-          <object class="GtkHButtonBox" id="dialog-action_area3">
-            <property name="visible">True</property>
-            <property name="layout_style">end</property>
-            <child>
-              <object class="GtkButton" id="button3">
-                <property name="label">gtk-cancel</property>
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">True</property>
-                <property name="use_stock">True</property>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">False</property>
-                <property name="position">0</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkButton" id="button4">
-                <property name="label">gtk-save</property>
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">True</property>
-                <property name="use_stock">True</property>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">False</property>
-                <property name="position">1</property>
-              </packing>
-            </child>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="pack_type">end</property>
-            <property name="position">0</property>
-          </packing>
-        </child>
-      </object>
-    </child>
-    <action-widgets>
-      <action-widget response="0">button3</action-widget>
-      <action-widget response="2">button4</action-widget>
-    </action-widgets>
-  </object>
   <object class="XfceTitledDialog" id="dialog-add">
     <property name="title" translatable="yes">Add New Item</property>
     <property name="window_position">center-on-parent</property>
diff --git a/plugins/launcher/launcher.c b/plugins/launcher/launcher.c
index 717da90..743fc1f 100644
--- a/plugins/launcher/launcher.c
+++ b/plugins/launcher/launcher.c
@@ -26,10 +26,13 @@
 #endif
 
 #include <exo/exo.h>
-
 #include <dbus/dbus-glib.h>
 #include <libxfce4util/libxfce4util.h>
 #include <libxfce4ui/libxfce4ui.h>
+#include <garcon/garcon.h>
+#include <xfconf/xfconf.h>
+
+#include <libxfce4panel/libxfce4panel.h>
 #include <common/panel-private.h>
 #include <common/panel-xfconf.h>
 
@@ -66,8 +69,8 @@ static void launcher_plugin_pack_widgets (LauncherPlugin *plugin);
 static GdkPixbuf *launcher_plugin_tooltip_pixbuf (GdkScreen *screen, const gchar *icon_name);
 
 static void launcher_plugin_menu_deactivate (GtkWidget *menu, LauncherPlugin *plugin);
-static gboolean launcher_plugin_menu_item_released (GtkMenuItem *widget, GdkEventButton *event, XfceMenuItem *item);
-static void launcher_plugin_menu_item_drag_data_received (GtkWidget *widget,GdkDragContext *context, gint x,gint y,GtkSelectionData *data, guint info, guint drag_time, XfceMenuItem *item);
+static gboolean launcher_plugin_menu_item_released (GtkMenuItem *widget, GdkEventButton *event, GarconMenuItem *item);
+static void launcher_plugin_menu_item_drag_data_received (GtkWidget *widget,GdkDragContext *context, gint x,gint y,GtkSelectionData *data, guint info, guint drag_time, GarconMenuItem *item);
 static void launcher_plugin_menu_construct (LauncherPlugin *plugin);
 static void launcher_plugin_menu_popup_destroyed (gpointer user_data);
 static gboolean launcher_plugin_menu_popup (gpointer user_data);
@@ -88,13 +91,13 @@ static gboolean launcher_plugin_arrow_press_event (GtkWidget *button, GdkEventBu
 static gboolean launcher_plugin_arrow_drag_motion(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint drag_time, LauncherPlugin *plugin);
 static void launcher_plugin_arrow_drag_leave (GtkWidget *widget, GdkDragContext *context, guint drag_time, LauncherPlugin *plugin);
 
-static gboolean launcher_plugin_item_query_tooltip (GtkWidget *widget, gint x, gint y, gboolean keyboard_mode, GtkTooltip *tooltip, XfceMenuItem *item);
+static gboolean launcher_plugin_item_query_tooltip (GtkWidget *widget, gint x, gint y, gboolean keyboard_mode, GtkTooltip *tooltip, GarconMenuItem *item);
 
-static gboolean launcher_plugin_item_exec_on_screen (XfceMenuItem *item, guint32 event_time, GdkScreen *screen, GSList *uri_list);
-static void launcher_plugin_item_exec (XfceMenuItem *item, guint32 event_time, GdkScreen *screen, GSList *uri_list);
-static void launcher_plugin_item_exec_from_clipboard (XfceMenuItem *item, guint32 event_time, GdkScreen *screen);
+static gboolean launcher_plugin_item_exec_on_screen (GarconMenuItem *item, guint32 event_time, GdkScreen *screen, GSList *uri_list);
+static void launcher_plugin_item_exec (GarconMenuItem *item, guint32 event_time, GdkScreen *screen, GSList *uri_list);
+static void launcher_plugin_item_exec_from_clipboard (GarconMenuItem *item, guint32 event_time, GdkScreen *screen);
 static void launcher_plugin_exec_append_quoted (GString *string, const gchar *unquoted);
-static gboolean launcher_plugin_exec_parse (XfceMenuItem *item, GSList *uri_list, gint *argc, gchar ***argv, GError **error);
+static gboolean launcher_plugin_exec_parse (GarconMenuItem *item, GSList *uri_list, gint *argc, gchar ***argv, GError **error);
 static GSList *launcher_plugin_uri_list_extract (GtkSelectionData *data);
 static void launcher_plugin_uri_list_free (GSList *uri_list);
 
@@ -138,6 +141,11 @@ enum
   PROP_ARROW_POSITION
 };
 
+enum
+{
+  ITEMS_CHANGED,
+  LAST_SIGNAL
+};
 
 
 /* define the plugin */
@@ -146,17 +154,18 @@ XFCE_PANEL_DEFINE_PLUGIN_RESIDENT (LauncherPlugin, launcher_plugin)
 
 
 /* quark to attach the plugin to menu items */
-GQuark launcher_plugin_quark = 0;
+GQuark       launcher_plugin_quark = 0;
+static guint launcher_signals[LAST_SIGNAL];
 
 
 
 /* target types for dropping in the launcher plugin */
 static const GtkTargetEntry drop_targets[] =
 {
-    { "text/uri-list", 0, 0, },
-    { "STRING", 0, 0 },
-    { "UTF8_STRING", 0, 0 },
-    { "text/plain", 0, 0 },
+  { "text/uri-list", 0, 0, },
+  { "STRING", 0, 0 },
+  { "UTF8_STRING", 0, 0 },
+  { "text/plain", 0, 0 },
 };
 
 
@@ -229,6 +238,14 @@ launcher_plugin_class_init (LauncherPluginClass *klass)
                                                              DEFAULT_MENU_ICON_SIZE,
                                                              EXO_PARAM_READABLE));
 
+  launcher_signals[ITEMS_CHANGED] =
+    g_signal_new (g_intern_static_string ("items-changed"),
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_FIRST,
+                  0, NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+
   /* initialize the quark */
   launcher_plugin_quark = g_quark_from_static_string ("xfce-launcher-plugin");
 }
@@ -266,7 +283,7 @@ launcher_plugin_init (LauncherPlugin *plugin)
   xfce_panel_plugin_add_action_widget (XFCE_PANEL_PLUGIN (plugin), plugin->button);
   gtk_widget_set_has_tooltip (plugin->button, TRUE);
   gtk_drag_dest_set (plugin->button, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
-                     drop_targets, G_N_ELEMENTS (drop_targets), DK_ACTION_COPY);
+                     drop_targets, G_N_ELEMENTS (drop_targets), GDK_ACTION_COPY);
   g_signal_connect (G_OBJECT (plugin->button), "button-press-event",
       G_CALLBACK (launcher_plugin_button_press_event), plugin);
   g_signal_connect (G_OBJECT (plugin->button), "button-release-event",
@@ -327,8 +344,8 @@ launcher_plugin_get_property (GObject    *object,
           {
             tmp = g_new0 (GValue, 1);
             g_value_init (tmp, G_TYPE_STRING);
-            panel_return_if_fail (XFCE_IS_MENU_ITEM (li->data));
-            g_value_set_string (tmp, xfce_menu_item_get_filename (li->data));
+            panel_return_if_fail (GARCON_IS_MENU_ITEM (li->data));
+            g_value_take_string (tmp, garcon_menu_item_get_uri (li->data));
             g_ptr_array_add (array, tmp);
           }
         g_value_set_boxed (value, array);
@@ -360,6 +377,77 @@ launcher_plugin_get_property (GObject    *object,
 
 
 
+static gboolean
+launcher_plugin_looks_like_an_uri (const gchar *string)
+{
+  const gchar *s = string;
+
+  /* <scheme> starts with an alpha character */
+  if (g_ascii_isalpha (*s))
+    {
+      /* <scheme> continues with (alpha | digit | "+" | "-" | ".")* */
+      for (++s; g_ascii_isalnum (*s) || *s == '+' || *s == '-' || *s == '.'; ++s);
+
+      /* <scheme> must be followed by ":" */
+      return (*s == ':');
+    }
+
+  return FALSE;
+}
+
+
+
+static void
+launcher_plugin_file_changed (GFileMonitor     *monitor,
+                              GFile            *file,
+                              GFile            *other_file,
+                              GFileMonitorEvent event_type,
+                              gpointer          user_data)
+{
+  GarconMenuItem *item = GARCON_MENU_ITEM (user_data);
+  GError         *error = NULL;
+
+  /* only update on the last event */
+  if (event_type != G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT)
+    return;
+
+  /* reload the item */
+  if (!garcon_menu_item_reload (item, &error))
+    {
+      g_critical ("Failed to reload a menu item: %s.", error->message);
+      g_error_free (error);
+    }
+}
+
+
+
+static void
+launcher_plugin_item_changed (GarconMenuItem *item,
+                              LauncherPlugin *plugin)
+{
+  GSList *li;
+
+  panel_return_if_fail (GARCON_IS_MENU_ITEM (item));
+  panel_return_if_fail (XFCE_IS_LAUNCHER_PLUGIN (plugin));
+
+  /* find the item */
+  li = g_slist_find (plugin->items, item);
+  if (G_LIKELY (li != NULL))
+    {
+      /* update the button or destroy the menu */
+      if (plugin->items == li)
+        launcher_plugin_button_update (plugin);
+      else
+        launcher_plugin_menu_destroy (plugin);
+    }
+  else
+    {
+      panel_assert_not_reached ();
+    }
+}
+
+
+
 static void
 launcher_plugin_set_property (GObject      *object,
                               guint         prop_id,
@@ -369,10 +457,13 @@ launcher_plugin_set_property (GObject      *object,
   LauncherPlugin *plugin = XFCE_LAUNCHER_PLUGIN (object);
   GPtrArray      *array;
   guint           i;
-  XfceMenuItem   *item;
+  GarconMenuItem *item;
   const GValue   *tmp;
-  const gchar    *filename;
-  XfceMenu       *menu = NULL;
+  const gchar    *str;
+  GSList         *li, *items = NULL;
+  gchar          *uri;
+  GFile          *gfile;
+  GFileMonitor   *monitor;
 
   /* destroy the menu, all the setting changes need this */
   launcher_plugin_menu_destroy (plugin);
@@ -380,67 +471,83 @@ launcher_plugin_set_property (GObject      *object,
   switch (prop_id)
     {
       case PROP_ITEMS:
-        /* free items */
-        if (plugin->items != NULL)
-          {
-            g_slist_foreach (plugin->items, (GFunc) g_object_unref, NULL);
-            g_slist_free (plugin->items);
-            plugin->items = NULL;
-          }
-
-        /* load new items fromt the filenames */
+        /* load new items from the uris */
         array = g_value_get_boxed (value);
         if (G_LIKELY (array != NULL))
           {
             for (i = 0; i < array->len; i++)
               {
-                /* get the filename from the array */
+                /* get the uri from the array */
                 tmp = g_ptr_array_index (array, i);
                 panel_return_if_fail (G_VALUE_HOLDS_STRING (tmp));
-                filename = g_value_get_string (tmp);
+                str = g_value_get_string (tmp);
+                if (G_UNLIKELY (exo_str_is_empty (str)))
+                  continue;
                 item = NULL;
 
-                /* either load the file directly or look in the item
-                 * pool for the desktop id */
-                if (G_LIKELY (g_path_is_absolute (filename)))
+                /* maybe we can find the item in the existing list */
+                for (li = plugin->items; item == NULL && li != NULL; li = g_slist_next (li))
                   {
-                    /* load the file */
-                    item = xfce_menu_item_new (filename);
-                    if (G_LIKELY (item != NULL))
-                      plugin->items = g_slist_append (plugin->items, item);
+                    uri = garcon_menu_item_get_uri (GARCON_MENU_ITEM (li->data));
+                    if (exo_str_is_equal (str, uri))
+                      {
+                        /* move the item to the new list */
+                        item = GARCON_MENU_ITEM (li->data);
+                        plugin->items = g_slist_delete_link (plugin->items, li);
+                      }
+                    g_free (uri);
                   }
-                else
+
+                /* try to create a new item */
+                if (G_LIKELY (item == NULL))
                   {
-                    if (G_LIKELY (menu == NULL))
+                    if (G_LIKELY (launcher_plugin_looks_like_an_uri (str)))
+                      {
+                        item = garcon_menu_item_new_for_uri (str);
+                      }
+                    else if (g_path_is_absolute (str))
+                      {
+                        item = garcon_menu_item_new_for_path (str);
+                      }
+                    else
                       {
-                        /* initialize the menu library and load the menu */
-                        xfce_menu_init (NULL);
-                        menu = xfce_menu_new (SYSCONFDIR "/xdg/menus/launcher.menu", /* TODO */ NULL);
+                        /* TODO, lookup in item pool using garcon */
                       }
+                  }
 
-                    /* lookup the (hopefully) desktop id in the pool */
-                    if (G_LIKELY (menu != NULL))
+                /* append the item and start file monitoring */
+                if (G_LIKELY (item != NULL))
+                  {
+                    items = g_slist_append (items, item);
+                    g_signal_connect (G_OBJECT (item), "changed",
+                        G_CALLBACK (launcher_plugin_item_changed), plugin);
+
+                    gfile = garcon_menu_item_get_file (item);
+                    monitor = g_file_monitor_file (gfile, G_FILE_MONITOR_NONE, NULL, NULL);
+                    g_object_unref (G_OBJECT (gfile));
+                    if (G_LIKELY (monitor != NULL))
                       {
-                        item = xfce_menu_item_pool_lookup (
-                            xfce_menu_get_item_pool (menu), filename);
-                        if (G_LIKELY (item != NULL))
-                          plugin->items = g_slist_append (plugin->items,
-                              g_object_ref (G_OBJECT (item)));
+                        g_signal_connect (G_OBJECT (monitor), "changed",
+                            G_CALLBACK (launcher_plugin_file_changed), item);
+                        g_object_weak_ref (G_OBJECT (item), (GWeakNotify) g_object_unref, monitor);
                       }
                   }
               }
+          }
 
-            /* release the menu */
-            if (G_UNLIKELY (menu != NULL))
-              {
-                /* release the menu */
-                g_object_unref (G_OBJECT (menu));
-
-                /* shutdown menu library */
-                xfce_menu_shutdown ();
-              }
+        /* release the old items */
+        if (plugin->items != NULL)
+          {
+            g_slist_foreach (plugin->items, (GFunc) g_object_unref, NULL);
+            g_slist_free (plugin->items);
           }
 
+        /* set new list */
+        plugin->items = items;
+
+        /* emit signal */
+        g_signal_emit (G_OBJECT (plugin), launcher_signals[ITEMS_CHANGED], 0);
+
         /* update the button */
         launcher_plugin_button_update (plugin);
 
@@ -482,7 +589,7 @@ launcher_plugin_set_property (GObject      *object,
       case PROP_ARROW_POSITION:
         plugin->arrow_position = g_value_get_uint (value);
 
-        update_arrow:
+update_arrow:
         /* update the arrow button visibility */
         launcher_plugin_arrow_visibility (plugin);
 
@@ -782,7 +889,7 @@ launcher_plugin_tooltip_pixbuf (GdkScreen   *screen,
 
   panel_return_val_if_fail (screen == NULL || GDK_IS_SCREEN (screen), NULL);
 
-  if (!IS_STRING (icon_name))
+  if (exo_str_is_empty (icon_name))
     return NULL;
 
   /* load directly from a file */
@@ -813,15 +920,15 @@ launcher_plugin_menu_deactivate (GtkWidget      *menu,
 
 
 static gboolean
-launcher_plugin_menu_item_released (GtkMenuItem    *widget,
-                                    GdkEventButton *event,
-                                    XfceMenuItem   *item)
+launcher_plugin_menu_item_released (GtkMenuItem      *widget,
+                                    GdkEventButton   *event,
+                                    GarconMenuItem   *item)
 {
   LauncherPlugin *plugin;
   GdkScreen      *screen;
 
   panel_return_val_if_fail (GTK_IS_MENU_ITEM (widget), FALSE);
-  panel_return_val_if_fail (XFCE_IS_MENU_ITEM (item), FALSE);
+  panel_return_val_if_fail (GARCON_IS_MENU_ITEM (item), FALSE);
 
   /* get the widget screen */
   screen = gtk_widget_get_screen (GTK_WIDGET (widget));
@@ -854,20 +961,20 @@ launcher_plugin_menu_item_released (GtkMenuItem    *widget,
 
 
 static void
-launcher_plugin_menu_item_drag_data_received (GtkWidget        *widget,
-                                              GdkDragContext   *context,
-                                              gint              x,
-                                              gint              y,
-                                              GtkSelectionData *data,
-                                              guint             info,
-                                              guint             drag_time,
-                                              XfceMenuItem     *item)
+launcher_plugin_menu_item_drag_data_received (GtkWidget          *widget,
+                                              GdkDragContext     *context,
+                                              gint                x,
+                                              gint                y,
+                                              GtkSelectionData   *data,
+                                              guint               info,
+                                              guint               drag_time,
+                                              GarconMenuItem     *item)
 {
   LauncherPlugin *plugin;
   GSList         *uri_list;
 
   panel_return_if_fail (GTK_IS_MENU_ITEM (widget));
-  panel_return_if_fail (XFCE_IS_MENU_ITEM (item));
+  panel_return_if_fail (GARCON_IS_MENU_ITEM (item));
 
   /* get the plugin */
   plugin = g_object_get_qdata (G_OBJECT (widget), launcher_plugin_quark);
@@ -902,12 +1009,12 @@ launcher_plugin_menu_item_drag_data_received (GtkWidget        *widget,
 static void
 launcher_plugin_menu_construct (LauncherPlugin *plugin)
 {
-  GtkArrowType  arrow_type;
-  guint         n;
-  XfceMenuItem *item;
-  GtkWidget    *mi, *image;
-  const gchar  *name, *icon_name;
-  GSList       *li;
+  GtkArrowType    arrow_type;
+  guint           n;
+  GarconMenuItem *item;
+  GtkWidget      *mi, *image;
+  const gchar    *name, *icon_name;
+  GSList         *li;
 
   panel_return_if_fail (XFCE_IS_LAUNCHER_PLUGIN (plugin));
   panel_return_if_fail (plugin->menu == NULL);
@@ -929,12 +1036,12 @@ launcher_plugin_menu_construct (LauncherPlugin *plugin)
         continue;
 
       /* get the item data */
-      item = XFCE_MENU_ITEM (li->data);
+      item = GARCON_MENU_ITEM (li->data);
 
       /* create the menu item */
-      name = xfce_menu_item_get_name (item);
+      name = garcon_menu_item_get_name (item);
       mi = gtk_image_menu_item_new_with_label (
-          IS_STRING (name) ? name : _("Unnamed Item"));
+          exo_str_is_empty (name) ? _("Unnamed Item") : name);
       g_object_set_qdata (G_OBJECT (mi), launcher_plugin_quark, plugin);
       gtk_widget_show (mi);
       gtk_drag_dest_set (mi, GTK_DEST_DEFAULT_ALL, drop_targets,
@@ -961,8 +1068,8 @@ launcher_plugin_menu_construct (LauncherPlugin *plugin)
         gtk_menu_shell_prepend (GTK_MENU_SHELL (plugin->menu), mi);
 
       /* set the icon if one is set */
-      icon_name = xfce_menu_item_get_icon_name (item);
-      if (IS_STRING (icon_name)
+      icon_name = garcon_menu_item_get_icon_name (item);
+      if (!exo_str_is_empty (icon_name)
           && plugin->menu_icon_size != GTK_ICON_SIZE_INVALID)
         {
           image = gtk_image_new_from_icon_name (icon_name, plugin->menu_icon_size);
@@ -1055,8 +1162,8 @@ launcher_plugin_menu_destroy (LauncherPlugin *plugin)
 static void
 launcher_plugin_button_update (LauncherPlugin *plugin)
 {
-  XfceMenuItem *item = NULL;
-  const gchar  *icon_name;
+  GarconMenuItem *item = NULL;
+  const gchar    *icon_name;
 
   panel_return_if_fail (XFCE_IS_LAUNCHER_PLUGIN (plugin));
 
@@ -1069,32 +1176,28 @@ launcher_plugin_button_update (LauncherPlugin *plugin)
 
   /* get first item */
   if (G_LIKELY (plugin->items != NULL))
-    item = XFCE_MENU_ITEM (plugin->items->data);
+    item = GARCON_MENU_ITEM (plugin->items->data);
 
   if (G_UNLIKELY (plugin->show_label))
     {
       panel_return_if_fail (GTK_IS_LABEL (plugin->child));
       gtk_label_set_text (GTK_LABEL (plugin->child),
-          item != NULL ? xfce_menu_item_get_name (item) : _("No items"));
+          item != NULL ? garcon_menu_item_get_name (item) : _("No items"));
     }
   else if (G_LIKELY (item != NULL))
     {
       panel_return_if_fail (XFCE_IS_PANEL_IMAGE (plugin->child));
 
-      icon_name = xfce_menu_item_get_icon_name (item);
-      if (!IS_STRING (icon_name))
-        {
-fallback_image:
-          icon_name = GTK_STOCK_MISSING_IMAGE;
-        }
+      icon_name = garcon_menu_item_get_icon_name (item);
       xfce_panel_image_set_from_source (XFCE_PANEL_IMAGE (plugin->child),
-                                        icon_name);
+          exo_str_is_empty (icon_name) ? GTK_STOCK_MISSING_IMAGE : icon_name);
     }
   else
     {
       /* set missing image icon */
       panel_return_if_fail (XFCE_IS_PANEL_IMAGE (plugin->child));
-      goto fallback_image;
+      xfce_panel_image_set_from_source (XFCE_PANEL_IMAGE (plugin->child),
+                                        GTK_STOCK_MISSING_IMAGE);
     }
 }
 
@@ -1158,8 +1261,8 @@ launcher_plugin_button_release_event (GtkWidget      *button,
                                       GdkEventButton *event,
                                       LauncherPlugin *plugin)
 {
-  XfceMenuItem *item;
-  GdkScreen    *screen;
+  GarconMenuItem *item;
+  GdkScreen      *screen;
 
   panel_return_val_if_fail (XFCE_IS_LAUNCHER_PLUGIN (plugin), FALSE);
 
@@ -1174,7 +1277,7 @@ launcher_plugin_button_release_event (GtkWidget      *button,
     return FALSE;
 
   /* get the menu item and the screen */
-  item = XFCE_MENU_ITEM (plugin->items->data);
+  item = GARCON_MENU_ITEM (plugin->items->data);
   screen = gtk_widget_get_screen (button);
 
   /* launcher the entry */
@@ -1198,8 +1301,8 @@ launcher_plugin_button_query_tooltip (GtkWidget      *widget,
                                       GtkTooltip     *tooltip,
                                       LauncherPlugin *plugin)
 {
-  gboolean      result;
-  XfceMenuItem *item;
+  gboolean        result;
+  GarconMenuItem *item;
 
   panel_return_val_if_fail (XFCE_IS_LAUNCHER_PLUGIN (plugin), FALSE);
   panel_return_val_if_fail (plugin->disable_tooltips == FALSE, FALSE);
@@ -1211,7 +1314,7 @@ launcher_plugin_button_query_tooltip (GtkWidget      *widget,
     return FALSE;
 
   /* get the first item */
-  item = XFCE_MENU_ITEM (plugin->items->data);
+  item = GARCON_MENU_ITEM (plugin->items->data);
 
   /* handle the basic tooltip data */
   result = launcher_plugin_item_query_tooltip (widget, x, y, keyboard_mode, tooltip, item);
@@ -1221,7 +1324,7 @@ launcher_plugin_button_query_tooltip (GtkWidget      *widget,
       if (G_UNLIKELY (plugin->tooltip_cache == NULL))
         plugin->tooltip_cache =
             launcher_plugin_tooltip_pixbuf (gtk_widget_get_screen (widget),
-                                            xfce_menu_item_get_icon_name (item));
+                                            garcon_menu_item_get_icon_name (item));
 
       if (G_LIKELY (plugin->tooltip_cache != NULL))
         gtk_tooltip_set_icon (tooltip, plugin->tooltip_cache);
@@ -1255,7 +1358,7 @@ launcher_plugin_button_drag_data_received (GtkWidget        *widget,
   if (G_LIKELY (uri_list != NULL))
     {
       /* execute */
-      launcher_plugin_item_exec (XFCE_MENU_ITEM (plugin->items->data),
+      launcher_plugin_item_exec (GARCON_MENU_ITEM (plugin->items->data),
                                  gtk_get_current_event_time (),
                                  gtk_widget_get_screen (widget),
                                  uri_list);
@@ -1512,26 +1615,26 @@ launcher_plugin_arrow_drag_leave (GtkWidget      *widget,
 
 
 static gboolean
-launcher_plugin_item_query_tooltip (GtkWidget    *widget,
-                                    gint          x,
-                                    gint          y,
-                                    gboolean      keyboard_mode,
-                                    GtkTooltip   *tooltip,
-                                    XfceMenuItem *item)
+launcher_plugin_item_query_tooltip (GtkWidget      *widget,
+                                    gint            x,
+                                    gint            y,
+                                    gboolean        keyboard_mode,
+                                    GtkTooltip     *tooltip,
+                                    GarconMenuItem *item)
 {
   gchar       *markup;
   const gchar *name, *comment;
   GdkPixbuf   *pixbuf;
 
-  panel_return_val_if_fail (XFCE_IS_MENU_ITEM (item), FALSE);
+  panel_return_val_if_fail (GARCON_IS_MENU_ITEM (item), FALSE);
 
   /* require atleast an item name */
-  name = xfce_menu_item_get_name (item);
-  if (!IS_STRING (name))
+  name = garcon_menu_item_get_name (item);
+  if (exo_str_is_empty (name))
     return FALSE;
 
-  comment = xfce_menu_item_get_comment (item);
-  if (IS_STRING (comment))
+  comment = garcon_menu_item_get_comment (item);
+  if (!exo_str_is_empty (comment))
     {
       markup = g_strdup_printf ("<b>%s</b>\n%s", name, comment);
       gtk_tooltip_set_markup (tooltip, markup);
@@ -1549,7 +1652,7 @@ launcher_plugin_item_query_tooltip (GtkWidget    *widget,
   if (GTK_IS_MENU_ITEM (widget))
     {
       pixbuf = launcher_plugin_tooltip_pixbuf (gtk_widget_get_screen (widget),
-                                               xfce_menu_item_get_icon_name (item));
+                                               garcon_menu_item_get_icon_name (item));
       if (G_LIKELY (pixbuf != NULL))
         {
           gtk_tooltip_set_icon (tooltip, pixbuf);
@@ -1563,16 +1666,16 @@ launcher_plugin_item_query_tooltip (GtkWidget    *widget,
 
 
 static gboolean
-launcher_plugin_item_exec_on_screen (XfceMenuItem *item,
-                                     guint32       event_time,
-                                     GdkScreen    *screen,
-                                     GSList       *uri_list)
+launcher_plugin_item_exec_on_screen (GarconMenuItem *item,
+                                     guint32         event_time,
+                                     GdkScreen      *screen,
+                                     GSList         *uri_list)
 {
   GError    *error = NULL;
   gchar    **argv;
   gboolean   succeed = FALSE;
 
-  panel_return_val_if_fail (XFCE_IS_MENU_ITEM (item), FALSE);
+  panel_return_val_if_fail (GARCON_IS_MENU_ITEM (item), FALSE);
   panel_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
 
   /* parse the execute command */
@@ -1580,11 +1683,11 @@ launcher_plugin_item_exec_on_screen (XfceMenuItem *item,
     {
       /* launch the command on the screen */
       succeed = xfce_spawn_on_screen (screen,
-                                      xfce_menu_item_get_path (item),
+                                      garcon_menu_item_get_path (item),
                                       argv, NULL, G_SPAWN_SEARCH_PATH,
-                                      xfce_menu_item_supports_startup_notification (item),
+                                      garcon_menu_item_supports_startup_notification (item),
                                       event_time,
-                                      xfce_menu_item_get_icon_name (item),
+                                      garcon_menu_item_get_icon_name (item),
                                       &error);
 
       /* cleanup */
@@ -1596,7 +1699,7 @@ launcher_plugin_item_exec_on_screen (XfceMenuItem *item,
       /* show an error dialog */
       xfce_dialog_show_error (NULL, error,
                               _("Failed to execute command \"%s\"."),
-                              xfce_menu_item_get_command (item));
+                              garcon_menu_item_get_command (item));
 
       /* cleanup */
       g_error_free (error);
@@ -1608,21 +1711,21 @@ launcher_plugin_item_exec_on_screen (XfceMenuItem *item,
 
 
 static void
-launcher_plugin_item_exec (XfceMenuItem *item,
-                           guint32       event_time,
-                           GdkScreen    *screen,
-                           GSList       *uri_list)
+launcher_plugin_item_exec (GarconMenuItem *item,
+                           guint32         event_time,
+                           GdkScreen      *screen,
+                           GSList         *uri_list)
 {
   GSList      *li, fake;
   gboolean     proceed = TRUE;
   const gchar *command;
 
-  panel_return_if_fail (XFCE_IS_MENU_ITEM (item));
+  panel_return_if_fail (GARCON_IS_MENU_ITEM (item));
   panel_return_if_fail (GDK_IS_SCREEN (screen));
 
   /* leave when there is nothing to execute */
-  command = xfce_menu_item_get_command (item);
-  if (!IS_STRING (command))
+  command = garcon_menu_item_get_command (item);
+  if (exo_str_is_empty (command))
     return;
 
   if (G_UNLIKELY (uri_list != NULL
@@ -1649,16 +1752,16 @@ launcher_plugin_item_exec (XfceMenuItem *item,
 
 
 static void
-launcher_plugin_item_exec_from_clipboard (XfceMenuItem *item,
-                                          guint32       event_time,
-                                          GdkScreen    *screen)
+launcher_plugin_item_exec_from_clipboard (GarconMenuItem *item,
+                                          guint32         event_time,
+                                          GdkScreen      *screen)
 {
   GtkClipboard     *clipboard;
   gchar            *text = NULL;
   GSList           *uri_list;
   GtkSelectionData  data;
 
-  panel_return_if_fail (XFCE_IS_MENU_ITEM (item));
+  panel_return_if_fail (GARCON_IS_MENU_ITEM (item));
   panel_return_if_fail (GDK_IS_SCREEN (screen));
 
   /* get the primary clipboard text */
@@ -1667,7 +1770,7 @@ launcher_plugin_item_exec_from_clipboard (XfceMenuItem *item,
     text = gtk_clipboard_wait_for_text (clipboard);
 
   /* try the secondary keayboard if the text is empty */
-  if (IS_STRING (text))
+  if (!exo_str_is_empty (text))
     {
       /* get the secondary clipboard text */
       clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
@@ -1675,7 +1778,7 @@ launcher_plugin_item_exec_from_clipboard (XfceMenuItem *item,
         text = gtk_clipboard_wait_for_text (clipboard);
     }
 
-  if (IS_STRING (text))
+  if (!exo_str_is_empty (text))
     {
       /* create fake selection data */
       data.data = (guchar *) text;
@@ -1713,30 +1816,30 @@ launcher_plugin_exec_append_quoted (GString     *string,
 
 
 static gboolean
-launcher_plugin_exec_parse (XfceMenuItem   *item,
-                            GSList         *uri_list,
-                            gint           *argc,
-                            gchar        ***argv,
-                            GError        **error)
+launcher_plugin_exec_parse (GarconMenuItem   *item,
+                            GSList           *uri_list,
+                            gint             *argc,
+                            gchar          ***argv,
+                            GError          **error)
 {
   GString     *string;
   const gchar *p;
   gboolean     result;
   GSList      *li;
-  gchar       *filename;
+  gchar       *filename, *uri;
   const gchar *command, *tmp;
 
-  panel_return_val_if_fail (XFCE_IS_MENU_ITEM (item), FALSE);
+  panel_return_val_if_fail (GARCON_IS_MENU_ITEM (item), FALSE);
 
   /* get the command */
-  command = xfce_menu_item_get_command (item);
-  panel_return_val_if_fail (IS_STRING (command), FALSE);
+  command = garcon_menu_item_get_command (item);
+  panel_return_val_if_fail (!exo_str_is_empty (command), FALSE);
 
   /* allocate an empty string */
   string = g_string_sized_new (100);
 
   /* prepend terminal command if required */
-  if (xfce_menu_item_requires_terminal (item))
+  if (garcon_menu_item_requires_terminal (item))
     g_string_append (string, "exo-open --launch TerminalEmulator ");
 
   for (p = command; *p != '\0'; ++p)
@@ -1777,8 +1880,8 @@ launcher_plugin_exec_parse (XfceMenuItem   *item,
                 break;
 
               case 'i':
-                tmp = xfce_menu_item_get_icon_name (item);
-                if (IS_STRING (tmp))
+                tmp = garcon_menu_item_get_icon_name (item);
+                if (!exo_str_is_empty (tmp))
                   {
                     g_string_append (string, "--icon ");
                     launcher_plugin_exec_append_quoted (string, tmp);
@@ -1786,15 +1889,16 @@ launcher_plugin_exec_parse (XfceMenuItem   *item,
                 break;
 
               case 'c':
-                tmp = xfce_menu_item_get_name (item);
-                if (IS_STRING (tmp))
+                tmp = garcon_menu_item_get_name (item);
+                if (!exo_str_is_empty (tmp))
                   launcher_plugin_exec_append_quoted (string, tmp);
                 break;
 
               case 'k':
-                tmp = xfce_menu_item_get_filename (item);
-                if (IS_STRING (tmp))
-                  launcher_plugin_exec_append_quoted (string, tmp);
+                uri = garcon_menu_item_get_uri (item);
+                if (!exo_str_is_empty (uri))
+                  launcher_plugin_exec_append_quoted (string, uri);
+                g_free (uri);
                 break;
 
               case '%':
@@ -1840,7 +1944,7 @@ launcher_plugin_uri_list_extract (GtkSelectionData *data)
       /* create the list of uris */
       for (i = 0; array[i] != NULL; i++)
         {
-          if (IS_STRING (array[i]))
+          if (!exo_str_is_empty (array[i]))
             list = g_slist_prepend (list, array[i]);
           else
             g_free (array[i]);
@@ -1860,7 +1964,7 @@ launcher_plugin_uri_list_extract (GtkSelectionData *data)
       for (i = 0; array[i] != NULL; i++)
         {
           /* skip empty strings */
-          if (!IS_STRING (array[i]))
+          if (!!exo_str_is_empty (array[i]))
             continue;
 
           uri = NULL;
@@ -1908,5 +2012,8 @@ GSList *
 launcher_plugin_get_items (LauncherPlugin *plugin)
 {
   panel_return_val_if_fail (XFCE_IS_LAUNCHER_PLUGIN (plugin), NULL);
-  return plugin->items;
+
+  /* set extra reference and return a copy of the list */
+  g_slist_foreach (plugin->items, (GFunc) g_object_ref, NULL);
+  return g_slist_copy (plugin->items);
 }
diff --git a/plugins/launcher/launcher.h b/plugins/launcher/launcher.h
index 0f4a2c6..27199a1 100644
--- a/plugins/launcher/launcher.h
+++ b/plugins/launcher/launcher.h
@@ -21,9 +21,7 @@
 #define __LAUNCHER_H__
 
 #include <gtk/gtk.h>
-#include <xfconf/xfconf.h>
 #include <libxfce4panel/libxfce4panel.h>
-#include <libxfce4menu/libxfce4menu.h>
 
 G_BEGIN_DECLS
 
diff --git a/plugins/launcher/launcher.menu b/plugins/launcher/launcher.menu
deleted file mode 100644
index ccaafc5..0000000
--- a/plugins/launcher/launcher.menu
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN"
-  "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd">
-
-<Menu>
-  <Name>Xfce Panel Launcher</Name>
-
-  <!-- Search the default locations -->
-  <DefaultAppDirs/>
-  <DefaultDirectoryDirs/>
-
-  <Include>
-    <!-- Show all the menu items -->
-    <All />
-  </Include>
-</Menu>



More information about the Xfce4-commits mailing list