← Back to team overview

ayatana-commits team mailing list archive

[Branch ~indicator-applet-developers/indicator-messages/trunk] Rev 163: Adding in the ability to take static commands from a desktop file

 

Merge authors:
  Ted Gould (ted)
Related merge proposals:
  https://code.launchpad.net/~ted/indicator-messages/static-commands/+merge/19528
  proposed by: Ted Gould (ted)
  review: Needs Fixing - Neil J. Patel (njpatel)
------------------------------------------------------------
revno: 163 [merge]
committer: Ted Gould <ted@xxxxxxxx>
branch nick: trunk
timestamp: Thu 2010-02-18 11:15:52 -0600
message:
  Adding in the ability to take static commands from a desktop file
modified:
  configure.ac
  src/launcher-menu-item.c
  src/launcher-menu-item.h
  src/messages-service.c


--
lp:indicator-messages
https://code.launchpad.net/~indicator-applet-developers/indicator-messages/trunk

Your team ayatana-commits is subscribed to branch lp:indicator-messages.
To unsubscribe from this branch go to https://code.launchpad.net/~indicator-applet-developers/indicator-messages/trunk/+edit-subscription.
=== modified file 'configure.ac'
--- configure.ac	2010-02-05 02:20:22 +0000
+++ configure.ac	2010-02-18 17:07:50 +0000
@@ -30,7 +30,7 @@
 GIO_UNIX_REQUIRED_VERSION=2.18
 PANEL_REQUIRED_VERSION=2.0.0
 INDICATE_REQUIRED_VERSION=0.3.0
-INDICATOR_REQUIRED_VERSION=0.3.0
+INDICATOR_REQUIRED_VERSION=0.3.3
 DBUSMENUGTK_REQUIRED_VERSION=0.2.2
 
 PKG_CHECK_MODULES(APPLET, gtk+-2.0 >= $GTK_REQUIRED_VERSION

=== modified file 'src/launcher-menu-item.c'
--- src/launcher-menu-item.c	2010-02-05 02:13:13 +0000
+++ src/launcher-menu-item.c	2010-02-17 19:40:20 +0000
@@ -27,6 +27,7 @@
 #include <gdk/gdk.h>
 #include <glib/gi18n.h>
 #include <gio/gdesktopappinfo.h>
+#include <libindicator/indicator-desktop-shortcuts.h>
 #include "launcher-menu-item.h"
 #include "dbus-data.h"
 
@@ -42,16 +43,21 @@
 {
 	GAppInfo * appinfo;
 	gchar * desktop;
+	IndicatorDesktopShortcuts * ids;
+	GList * shortcuts;
 };
 
 #define LAUNCHER_MENU_ITEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), LAUNCHER_MENU_ITEM_TYPE, LauncherMenuItemPrivate))
 
+#define NICK_DATA  "ids-nick-data"
+
 /* Prototypes */
 static void launcher_menu_item_class_init (LauncherMenuItemClass *klass);
 static void launcher_menu_item_init       (LauncherMenuItem *self);
 static void launcher_menu_item_dispose    (GObject *object);
 static void launcher_menu_item_finalize   (GObject *object);
 static void activate_cb (LauncherMenuItem * self, guint timestamp, gpointer data);
+static void nick_activate_cb (LauncherMenuItem * self, guint timestamp, gpointer data);
 
 
 G_DEFINE_TYPE (LauncherMenuItem, launcher_menu_item, DBUSMENU_TYPE_MENUITEM);
@@ -86,21 +92,22 @@
 	priv->appinfo = NULL;
 	priv->desktop = NULL;
 
+	priv->ids = NULL;
+	priv->shortcuts = NULL;
+
+	return;
+}
+
+static void
+func_unref (gpointer data, gpointer user_data)
+{
+	g_object_unref(G_OBJECT(data));
 	return;
 }
 
 static void
 launcher_menu_item_dispose (GObject *object)
 {
-	// LauncherMenuItem * self = LAUNCHER_MENU_ITEM(object);
-	// LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(self);
-
-	G_OBJECT_CLASS (launcher_menu_item_parent_class)->dispose (object);
-}
-
-static void
-launcher_menu_item_finalize (GObject *object)
-{
 	LauncherMenuItem * self = LAUNCHER_MENU_ITEM(object);
 	LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(self);
 
@@ -109,6 +116,26 @@
 		priv->appinfo = NULL;
 	}
 
+	if (priv->ids != NULL) {
+		g_object_unref(priv->ids);
+		priv->ids = NULL;
+	}
+
+	if (priv->shortcuts != NULL) {
+		g_list_foreach(priv->shortcuts, func_unref, NULL);
+		g_list_free(priv->shortcuts);
+		priv->shortcuts = NULL;
+	}
+
+	G_OBJECT_CLASS (launcher_menu_item_parent_class)->dispose (object);
+}
+
+static void
+launcher_menu_item_finalize (GObject *object)
+{
+	LauncherMenuItem * self = LAUNCHER_MENU_ITEM(object);
+	LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(self);
+
 	if (priv->desktop != NULL) {
 		g_free(priv->desktop);
 		priv->desktop = NULL;
@@ -127,16 +154,35 @@
 
 	LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(self);
 
+	/* Parse the desktop file we've been given. */
 	priv->appinfo = G_APP_INFO(g_desktop_app_info_new_from_filename(desktop_file));
 	priv->desktop = g_strdup(desktop_file);
 
+	/* Set the appropriate values on this menu item based on the
+	   app info that we've parsed */
 	g_debug("\tName: %s", launcher_menu_item_get_name(self));
 	dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_TYPE, LAUNCHER_MENUITEM_TYPE);
 	dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), LAUNCHER_MENUITEM_PROP_APP_NAME, launcher_menu_item_get_name(self));
 	dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), LAUNCHER_MENUITEM_PROP_APP_DESC, launcher_menu_item_get_description(self));
+	dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
 
 	g_signal_connect(G_OBJECT(self), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(activate_cb), NULL);
 
+	/* Start to build static shortcuts */
+	priv->ids = indicator_desktop_shortcuts_new(priv->desktop, "Messaging Menu");
+	const gchar ** nicks = indicator_desktop_shortcuts_get_nicks(priv->ids);
+	gint i;
+	for (i = 0; nicks[i] != NULL; i++) {
+		DbusmenuMenuitem * mi = dbusmenu_menuitem_new();
+		g_object_set_data(G_OBJECT(mi), NICK_DATA, (gpointer)nicks[i]);
+
+		dbusmenu_menuitem_property_set(mi, DBUSMENU_MENUITEM_PROP_LABEL, indicator_desktop_shortcuts_nick_get_name(priv->ids, nicks[i]));
+		g_signal_connect(G_OBJECT(mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(nick_activate_cb), self);
+
+		priv->shortcuts = g_list_append(priv->shortcuts, mi);
+	}
+
+	/* Check to see if we should be eclipsed */
 	if (priv->appinfo == NULL) {
 		launcher_menu_item_set_eclipsed(self, TRUE);
 	}
@@ -156,6 +202,27 @@
 	}
 }
 
+/* Respond to one of the shortcuts getting clicked on. */
+static void
+nick_activate_cb (LauncherMenuItem * self, guint timestamp, gpointer data)
+{
+	gchar * nick = (gchar *)g_object_get_data(G_OBJECT(self), NICK_DATA);
+	LauncherMenuItem * lmi = LAUNCHER_MENU_ITEM(data);
+
+	g_return_if_fail(nick != NULL);
+	g_return_if_fail(lmi != NULL);
+
+	LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(lmi);
+	
+	g_return_if_fail(priv->ids != NULL);
+
+	if (!indicator_desktop_shortcuts_nick_exec(priv->ids, nick)) {
+		g_warning("Unable to execute nick '%s' for desktop file '%s'", nick, priv->desktop);
+	}
+
+	return;
+}
+
 /* When the menu item is clicked on it tries to launch
    the application that is represented by the desktop file */
 static void
@@ -191,26 +258,50 @@
 	return g_app_info_get_description(priv->appinfo);
 }
 
+/* Apply the eclipse value to all the shortcuts */
+static void
+eclipse_shortcuts_cb (gpointer data, gpointer user_data)
+{
+	DbusmenuMenuitem * mi = DBUSMENU_MENUITEM(data);
+	g_return_if_fail(mi != NULL);
+
+	gboolean eclipsed = GPOINTER_TO_UINT(user_data);
+	
+	dbusmenu_menuitem_property_set_bool(mi, DBUSMENU_MENUITEM_PROP_VISIBLE, !eclipsed);
+	return;
+}
+
 /* Hides the menu item based on whether it is eclipsed
    or not. */
 void
 launcher_menu_item_set_eclipsed (LauncherMenuItem * li, gboolean eclipsed)
 {
+	g_return_if_fail(IS_LAUNCHER_MENU_ITEM(li));
+	LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(li);
+
 	g_debug("Laucher '%s' is %s", launcher_menu_item_get_name(li), eclipsed ? "now eclipsed" : "shown again");
-	dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(li), DBUSMENU_MENUITEM_PROP_VISIBLE, eclipsed ? "false" : "true");
+	dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(li), DBUSMENU_MENUITEM_PROP_VISIBLE, !eclipsed);
+
+	g_list_foreach(priv->shortcuts, eclipse_shortcuts_cb, GINT_TO_POINTER(eclipsed));
+
 	return;
 }
 
+/* Check to see if this item is eclipsed */
 gboolean
 launcher_menu_item_get_eclipsed (LauncherMenuItem * li)
 {
-	const gchar * show = dbusmenu_menuitem_property_get(DBUSMENU_MENUITEM(li), DBUSMENU_MENUITEM_PROP_VISIBLE);
-	if (show == NULL) {
-		return FALSE;
-	}
-	g_debug("Launcher check eclipse: %s", show);
-	if (!g_strcmp0(show, "false")) {
-		return TRUE;
-	}
-	return FALSE;
+	gboolean show = dbusmenu_menuitem_property_get_bool(DBUSMENU_MENUITEM(li), DBUSMENU_MENUITEM_PROP_VISIBLE);
+	g_debug("Launcher check eclipse: %s", show ? "false" : "true");
+	return !show;
+}
+
+/* Gets the shortcuts that are associated with this
+   launcher.  They're a list of DbusmenuMenuitems */
+GList *
+launcher_menu_item_get_items (LauncherMenuItem * li)
+{
+	g_return_val_if_fail(IS_LAUNCHER_MENU_ITEM(li), NULL);
+	LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(li);
+	return priv->shortcuts;
 }

=== modified file 'src/launcher-menu-item.h'
--- src/launcher-menu-item.h	2009-08-27 01:25:00 +0000
+++ src/launcher-menu-item.h	2010-02-17 17:56:03 +0000
@@ -59,6 +59,7 @@
 const gchar * launcher_menu_item_get_description (LauncherMenuItem * li);
 void launcher_menu_item_set_eclipsed (LauncherMenuItem * li, gboolean eclipsed);
 gboolean launcher_menu_item_get_eclipsed (LauncherMenuItem * li);
+GList * launcher_menu_item_get_items (LauncherMenuItem * li);
 
 G_END_DECLS
 

=== modified file 'src/messages-service.c'
--- src/messages-service.c	2010-02-09 03:54:31 +0000
+++ src/messages-service.c	2010-02-18 14:44:13 +0000
@@ -48,6 +48,8 @@
 
 static MessageServiceDbus * dbus_interface = NULL;
 
+#define DESKTOP_FILE_GROUP        "Messaging Menu"
+#define DESKTOP_FILE_KEY_DESKTOP  "DesktopFile"
 
 static void server_count_changed (AppMenuItem * appitem, guint count, gpointer data);
 static void server_name_changed (AppMenuItem * appitem, gchar * name, gpointer data);
@@ -57,9 +59,14 @@
 static void check_eclipses (AppMenuItem * ai);
 static void remove_eclipses (AppMenuItem * ai);
 static gboolean build_launcher (gpointer data);
+static gboolean build_launcher_keyfile (gpointer data);
+static void build_launcher_core (const gchar * desktop);
 static gboolean build_launchers (gpointer data);
 static gboolean blacklist_init (gpointer data);
 static gboolean blacklist_add (gpointer data);
+static gchar * desktop_file_from_keyfile (const gchar * definition_file);
+static gboolean blacklist_keyfile_add (gpointer udata);
+static void blacklist_add_core (gchar * desktop, gchar * definition);
 static gboolean blacklist_remove (gpointer data);
 static void blacklist_dir_changed (GFileMonitor * monitor, GFile * file, GFile * other_file, GFileMonitorEvent event_type, gpointer user_data);
 static void app_dir_changed (GFileMonitor * monitor, GFile * file, GFile * other_file, GFileMonitorEvent event_type, gpointer user_data);
@@ -241,7 +248,11 @@
 	while ((filename = g_dir_read_name(dir)) != NULL) {
 		g_debug("Found file: %s", filename);
 		gchar * path = g_build_filename(blacklistdir, filename, NULL);
-		g_idle_add(blacklist_add, path);
+		if (g_str_has_suffix(path, "keyfile")) {
+			g_idle_add(blacklist_keyfile_add, path);
+		} else {
+			g_idle_add(blacklist_add, path);
+		}
 	}
 
 	g_dir_close(dir);
@@ -250,6 +261,53 @@
 	return FALSE;
 }
 
+/* Parses through a keyfile to find the desktop file entry and
+   pushes them into the blacklist. */
+static gboolean
+blacklist_keyfile_add (gpointer udata)
+{
+	gchar * definition_file = (gchar *)udata;
+	gchar * desktopfile = desktop_file_from_keyfile(definition_file);
+	if (desktopfile != NULL) {
+		blacklist_add_core(desktopfile, definition_file);
+		g_free(desktopfile);
+	}
+	return FALSE;
+}
+
+/* Takes a keyfile and finds the desktop file in it for
+   us.  With some error handling. */
+static gchar *
+desktop_file_from_keyfile (const gchar * definition_file)
+{
+	GKeyFile * keyfile = g_key_file_new();
+	GError * error = NULL;
+
+	if (!g_key_file_load_from_file(keyfile, definition_file, G_KEY_FILE_NONE, &error)) {
+		g_warning("Unable to load keyfile '%s' because: %s", definition_file, error == NULL ? "unknown" : error->message);
+		g_error_free(error);
+		g_key_file_free(keyfile);
+		return NULL;
+	}
+
+	if (!g_key_file_has_group(keyfile, DESKTOP_FILE_GROUP)) {
+		g_warning("Unable to use keyfile '%s' as it has no '" DESKTOP_FILE_GROUP "' group.", definition_file);
+		g_key_file_free(keyfile);
+		return NULL;
+	}
+
+	if (!g_key_file_has_key(keyfile, DESKTOP_FILE_GROUP, DESKTOP_FILE_KEY_DESKTOP, &error)) {
+		g_warning("Unable to use keyfile '%s' as there is no key '" DESKTOP_FILE_KEY_DESKTOP "' in the group '" DESKTOP_FILE_GROUP "' because: %s", definition_file, error == NULL ? "unknown" : error->message);
+		g_error_free(error);
+		g_key_file_free(keyfile);
+		return NULL;
+	}
+
+	gchar * desktopfile = g_key_file_get_string(keyfile, DESKTOP_FILE_GROUP, DESKTOP_FILE_KEY_DESKTOP, &error);
+	g_key_file_free(keyfile);
+	return desktopfile;
+}
+
 /* Add a definition file into the black list and eclipse
    and launchers that have the same file. */
 static gboolean
@@ -268,38 +326,51 @@
 	gchar * trimdesktop = pango_trim_string(desktop);
 	g_free(desktop);
 
+	blacklist_add_core(trimdesktop, definition_file);
+	g_free(trimdesktop);
+
+	return FALSE;
+}
+
+/* This takes a desktop file and tries to add it to the black
+   list for applications in the messaging menu.  If it can,
+   then the launcher item gets marked as eclipsed and hidden
+   from the user. */
+static void
+blacklist_add_core (gchar * desktop, gchar * definition)
+{
 	/* Check for conflicts */
-	gpointer data = g_hash_table_lookup(blacklist, trimdesktop);
+	gpointer data = g_hash_table_lookup(blacklist, desktop);
 	if (data != NULL) {
 		gchar * oldfile = (gchar *)data;
-		if (!g_strcmp0(oldfile, definition_file)) {
+		if (!g_strcmp0(oldfile, definition)) {
 			g_warning("Already added file '%s'", oldfile);
 		} else {
-			g_warning("Already have desktop file '%s' in blacklist file '%s' not adding from '%s'", trimdesktop, oldfile, definition_file);
+			g_warning("Already have desktop file '%s' in blacklist file '%s' not adding from '%s'", desktop, oldfile, definition);
 		}
 
-		g_free(trimdesktop);
-		g_free(definition_file);
-		return FALSE;
+		return;
 	}
 
 	/* Actually blacklist this thing */
-	g_hash_table_insert(blacklist, trimdesktop, definition_file);
-	g_debug("Adding Blacklist item '%s' for desktop '%s'", definition_file, trimdesktop);
+	g_hash_table_insert(blacklist, desktop, definition);
+	g_debug("Adding Blacklist item '%s' for desktop '%s'", definition, desktop);
 
 	/* Go through and eclipse folks */
 	GList * launcher;
 	for (launcher = launcherList; launcher != NULL; launcher = launcher->next) {
 		launcherList_t * item = (launcherList_t *)launcher->data;
-		if (!g_strcmp0(trimdesktop, launcher_menu_item_get_desktop(item->menuitem))) {
+		if (!g_strcmp0(desktop, launcher_menu_item_get_desktop(item->menuitem))) {
 			launcher_menu_item_set_eclipsed(item->menuitem, TRUE);
-			dbusmenu_menuitem_property_set(item->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, "false");
+			dbusmenu_menuitem_property_set_bool(item->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
 		}
 	}
 
 	check_hidden();
+	/* Shouldn't need a resort here as hiding shouldn't cause things to
+	   move other than this item disappearing. */
 
-	return FALSE;
+	return;
 }
 
 /* Remove a black list item based on the definition file
@@ -340,7 +411,7 @@
 			}
 			if (serveritem == NULL) {
 				launcher_menu_item_set_eclipsed(li->menuitem, FALSE);
-				dbusmenu_menuitem_property_set(li->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, "true");
+				dbusmenu_menuitem_property_set_bool(li->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
 			}
 		}
 	}
@@ -626,14 +697,14 @@
 
 	/* If there is a menu item, let's get rid of it. */
 	if (sltp->menuitem != NULL) {
-		dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(sltp->menuitem), DBUSMENU_MENUITEM_PROP_VISIBLE, "false");
+		dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(sltp->menuitem), DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
 		dbusmenu_menuitem_child_delete(DBUSMENU_MENUITEM(data), DBUSMENU_MENUITEM(sltp->menuitem));
 		g_object_unref(G_OBJECT(sltp->menuitem));
 	}
 
 	/* If there is a separator, let's get rid of it. */
 	if (sltp->separator != NULL) {
-		dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(sltp->separator), DBUSMENU_MENUITEM_PROP_VISIBLE, "false");
+		dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(sltp->separator), DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
 		dbusmenu_menuitem_child_delete(DBUSMENU_MENUITEM(data), DBUSMENU_MENUITEM(sltp->separator));
 		g_object_unref(G_OBJECT(sltp->separator));
 	}
@@ -724,12 +795,21 @@
 				dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(li->menuitem), position);
 				position++;
 
+				/* Inserting the shortcuts from the launcher */
+				GList * shortcuts = launcher_menu_item_get_items(li->menuitem);
+				while (shortcuts != NULL) {
+					g_debug("\t\tMoving shortcut to position %d", position);
+					dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(shortcuts->data), position);
+					position++;
+					shortcuts = g_list_next(shortcuts);
+				}
+
 				/* Putting the launcher separator in */
 				g_debug("\tMoving launcher separator to position %d", position);
 				dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(li->separator), position);
 				if (!launcher_menu_item_get_eclipsed(li->menuitem)) {
 					/* Only clear the visiblity if we're not eclipsed */
-					dbusmenu_menuitem_property_set(li->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, "true");
+					dbusmenu_menuitem_property_set_bool(li->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
 					last_separator = li->separator;
 				}
 				position++;
@@ -765,7 +845,7 @@
 		if (si->separator != NULL) {
 			g_debug("\tMoving app %s separator to position %d", INDICATE_LISTENER_SERVER_DBUS_NAME(si->server), position);
 			dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(si->separator), position);
-			dbusmenu_menuitem_property_set(si->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, "true");
+			dbusmenu_menuitem_property_set_bool(si->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
 			position++;
 			last_separator = si->separator;
 		}
@@ -780,12 +860,21 @@
 		dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(li->menuitem), position);
 		position++;
 
+		/* Inserting the shortcuts from the launcher */
+		GList * shortcuts = launcher_menu_item_get_items(li->menuitem);
+		while (shortcuts != NULL) {
+			g_debug("\t\tMoving shortcut to position %d", position);
+			dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(shortcuts->data), position);
+			position++;
+			shortcuts = g_list_next(shortcuts);
+		}
+
 		/* Putting the launcher separator in */
 		g_debug("\tMoving launcher separator to position %d", position);
 		dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(li->separator), position);
 		if (!launcher_menu_item_get_eclipsed(li->menuitem)) {
 			/* Only clear the visiblity if we're not eclipsed */
-			dbusmenu_menuitem_property_set(li->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, "true");
+			dbusmenu_menuitem_property_set_bool(li->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
 			last_separator = li->separator;
 		}
 		position++;
@@ -794,7 +883,7 @@
 	}
 
 	if (last_separator != NULL) {
-		dbusmenu_menuitem_property_set(last_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, "false");
+		dbusmenu_menuitem_property_set_bool(last_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
 	} else {
 		g_warning("No last separator on resort");
 	}
@@ -953,7 +1042,7 @@
 
 		/* Hide the item immediately, and then remove it
 		   which might take a little longer. */
-		dbusmenu_menuitem_property_set(menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE, "false");
+		dbusmenu_menuitem_property_set_bool(menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
 		dbusmenu_menuitem_child_delete(DBUSMENU_MENUITEM(data), menuitem);
 		removed = TRUE;
 	}
@@ -981,7 +1070,11 @@
 	case G_FILE_MONITOR_EVENT_CREATED: {
 		gchar * path = g_file_get_path(file);
 		g_debug("\tCreate: %s", path);
-		g_idle_add(build_launcher, path);
+		if (g_str_has_suffix(path, "keyfile")) {
+			g_idle_add(build_launcher_keyfile, path);
+		} else {
+			g_idle_add(build_launcher, path);
+		}
 		break;
 	}
 	default:
@@ -1010,7 +1103,7 @@
 
 		if (!g_strcmp0(aidesktop, lidesktop)) {
 			launcher_menu_item_set_eclipsed(ll->menuitem, TRUE);
-			dbusmenu_menuitem_property_set(ll->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, "false");
+			dbusmenu_menuitem_property_set_bool(ll->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
 			break;
 		}
 	}
@@ -1035,7 +1128,7 @@
 
 		if (!g_strcmp0(aidesktop, lidesktop)) {
 			launcher_menu_item_set_eclipsed(ll->menuitem, FALSE);
-			dbusmenu_menuitem_property_set(ll->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, "true");
+			dbusmenu_menuitem_property_set_bool(ll->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
 			break;
 		}
 	}
@@ -1087,7 +1180,7 @@
 	g_list_free(li->appdiritems);
 
 	if (li->menuitem != NULL) {
-		dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(li->menuitem), DBUSMENU_MENUITEM_PROP_VISIBLE, "false");
+		dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(li->menuitem), DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
 		dbusmenu_menuitem_child_delete(root_menuitem, DBUSMENU_MENUITEM(li->menuitem));
 		g_object_unref(G_OBJECT(li->menuitem));
 		li->menuitem = NULL;
@@ -1119,11 +1212,34 @@
 	g_free(desktop);
 	g_debug("\tcontents: %s", trimdesktop);
 
+	build_launcher_core(trimdesktop);
+	g_free(trimdesktop);
+	return FALSE;
+}
+
+/* Use a key file to find the desktop file. */
+static gboolean
+build_launcher_keyfile (gpointer data)
+{
+	gchar * path = (gchar *)data;
+	gchar * desktop = desktop_file_from_keyfile (path);
+	if (desktop != NULL) {
+		build_launcher_core(desktop);
+		g_free(desktop);
+	}
+	return FALSE;
+}
+
+/* The core action of dealing with a desktop file that should
+   be a launcher */
+static void
+build_launcher_core (const gchar * desktop)
+{
 	/* Check to see if we already have a launcher */
 	GList * listitem;
 	for (listitem = launcherList; listitem != NULL; listitem = listitem->next) {
 		launcherList_t * li = (launcherList_t *)listitem->data;
-		if (!g_strcmp0(launcher_menu_item_get_desktop(li->menuitem), trimdesktop)) {
+		if (!g_strcmp0(launcher_menu_item_get_desktop(li->menuitem), desktop)) {
 			break;
 		}
 	}
@@ -1132,9 +1248,8 @@
 		/* If not */
 		/* Build the item */
 		launcherList_t * ll = g_new0(launcherList_t, 1);
-		ll->menuitem = launcher_menu_item_new(trimdesktop);
-		g_free(trimdesktop);
-		ll->appdiritems = g_list_append(NULL, path);
+		ll->menuitem = launcher_menu_item_new(desktop);
+		ll->appdiritems = g_list_append(NULL, g_strdup(desktop));
 
 		/* Build a separator */
 		ll->separator = dbusmenu_menuitem_new();
@@ -1145,6 +1260,11 @@
 
 		/* Add it to the menu */
 		dbusmenu_menuitem_child_append(root_menuitem, DBUSMENU_MENUITEM(ll->menuitem));
+		GList * shortcuts = launcher_menu_item_get_items(ll->menuitem);
+		while (shortcuts != NULL) {
+			dbusmenu_menuitem_child_append(root_menuitem, DBUSMENU_MENUITEM(shortcuts->data));
+			shortcuts = g_list_next(shortcuts);
+		}
 		dbusmenu_menuitem_child_append(root_menuitem, DBUSMENU_MENUITEM(ll->separator));
 
 		/* If we're in the black list or we've gotten eclipsed
@@ -1152,7 +1272,7 @@
 		if (blacklist_check(launcher_menu_item_get_desktop(ll->menuitem)) ||
 				launcher_menu_item_get_eclipsed(ll->menuitem)) {
 			launcher_menu_item_set_eclipsed(ll->menuitem, TRUE);
-			dbusmenu_menuitem_property_set(ll->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, "false");
+			dbusmenu_menuitem_property_set_bool(ll->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
 		}
 
 		resort_menu(root_menuitem);
@@ -1160,10 +1280,10 @@
 	} else {
 		/* If so add ourselves */
 		launcherList_t * ll = (launcherList_t *)listitem->data;
-		ll->appdiritems = g_list_append(ll->appdiritems, path);
+		ll->appdiritems = g_list_append(ll->appdiritems, g_strdup(desktop));
 	}
 
-	return FALSE;
+	return;
 }
 
 /* This function goes through all the launchers that we're
@@ -1197,7 +1317,11 @@
 	while ((filename = g_dir_read_name(dir)) != NULL) {
 		g_debug("Found file: %s", filename);
 		gchar * path = g_build_filename(directory, filename, NULL);
-		g_idle_add(build_launcher, path);
+		if (g_str_has_suffix(path, "keyfile")) {
+			g_idle_add(build_launcher_keyfile, path);
+		} else {
+			g_idle_add(build_launcher, path);
+		}
 	}
 
 	g_dir_close(dir);