Merge lp:~ted/indicator-applet/messages-launchers into lp:indicator-applet/messages0.2

Proposed by Ted Gould
Status: Merged
Merged at revision: not available
Proposed branch: lp:~ted/indicator-applet/messages-launchers
Merge into: lp:indicator-applet/messages0.2
Diff against target: None lines
To merge this branch: bzr merge lp:~ted/indicator-applet/messages-launchers
Reviewer Review Type Date Requested Status
David Barth Approve
Review via email: mp+10439@code.launchpad.net

Commit message

Initial work to implement launchers in the messaging menu.

To post a comment you must log in.
Revision history for this message
Ted Gould (ted) wrote :

Okay, so this branch adds all the initial code for launchers. Basically it puts launchers in the menu so that you can click on them and start the application. It then hides them when the real application starts up. But, unfortunatly hide doesn't work in dbusmenu yet, so it's a little unclimatic, you'll have to trust the debug message there :)

To make a simple launcher:
  $ sudo bash
  % mkdir -p /etc/indicators/messages/applications
  % echo "/usr/share/applications/evolution-mail.desktop" > /etc/indicators/messages/applications/test

Revision history for this message
David Barth (dbarth) wrote :

Looks like solid code apart from the gobject boilerplate. A few questions and remarks:
- does g_app_info_launch manage notification ids? or do you have to trigger that explicitly with g_app_launch_context_get_startup_notify_id ()? it would be good to add that for the release and cancel the s-n in case of errors
- is reconsile_list_and_menu (reconcile?) an API that was used by other modules? is there a need to deprecate it?
- on sorting launchers: it feels weird that they are sorted dynamically (in terms of having a stable UI), why not just use the order of files found in the config directory, minus the ones which are eclipsed? is there a particular UX requirement there? would that be impacted by the extra launchers feature afterwards?

review: Needs Information
Revision history for this message
Ted Gould (ted) wrote :

On Thu, 2009-08-20 at 13:59 +0000, David Barth wrote:
> - does g_app_info_launch manage notification ids? or do you
> have to trigger that explicitly with g_app_launch_context_get_startup_notify_id ()?
> it would be good to add that for the release and cancel
> the s-n in case of errors

I'm not sure. I'll look into the GNOME Panel code and steal it from
them to see how they do it :)

> - is reconsile_list_and_menu (reconcile?) an API that was
> used by other modules? is there a need to deprecate it?

No, nothing here is used by other modules. The only external symbols
are those defined in libindicator.

It's also declared static ;)

> - on sorting launchers: it feels weird that they are sorted
> dynamically (in terms of having a stable UI), why not just
> use the order of files found in the config directory, minus
> the ones which are eclipsed? is there a particular UX
> requirement there? would that be impacted by the extra
> launchers feature afterwards?

They're sorted by the name in the desktop file, so I don't know how we
could sort them without opening up the desktop files. For the most
part, since this is a menu, it's closed as any reordering would be done.
If there is a reorder operation, it'll only move the entries that
actually move. DBusmenu checks to make sure the reorder is a real
reorder and not just a request to put things in the same place.

146. By Ted Gould

Use a GDK app context. Not sure about the timestamp units though.

147. By Ted Gould

Should be in milliseconds not micro

Revision history for this message
Ted Gould (ted) wrote :

On Thu, 2009-08-20 at 14:27 +0000, Ted Gould wrote:
> On Thu, 2009-08-20 at 13:59 +0000, David Barth wrote:
> > - does g_app_info_launch manage notification ids? or do you
> > have to trigger that explicitly with g_app_launch_context_get_startup_notify_id ()?
> > it would be good to add that for the release and cancel
> > the s-n in case of errors
>
> I'm not sure. I'll look into the GNOME Panel code and steal it from
> them to see how they do it :)

Turns out they use libgnome :(

I'm not using the GDK App Context which should do this. Updated the
branch.

Revision history for this message
David Barth (dbarth) wrote :

Ted Gould wrote:
> [...]
> It's also declared static ;)
>
Ahum... Sure ;)
>> - on sorting launchers: it feels weird that they are sorted
>> dynamically (in terms of having a stable UI), why not just
>> use the order of files found in the config directory, minus
>> the ones which are eclipsed? is there a particular UX
>> requirement there? would that be impacted by the extra
>> launchers feature afterwards?
>>
>
> They're sorted by the name in the desktop file, so I don't know how we
> could sort them without opening up the desktop files. For the most
> part, since this is a menu, it's closed as any reordering would be done.
> If there is a reorder operation, it'll only move the entries that
> actually move. DBusmenu checks to make sure the reorder is a real
> reorder and not just a request to put things in the same place.
>
having:
00_evolution.desktop
00_empathy.desktop
for apps in main for example

while universe ones would have:
99_my_funky_msging_app.desktop

the alphabetical order still applies, which should be consistent with
what's *in* the desktop file, while providing some extra level of
ordering at the distribution level.

It's a suggestion. It shouldn't block the merge proposal however.

David

Revision history for this message
David Barth (dbarth) wrote :

Go ahead with the change.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'configure.ac'
2--- configure.ac 2009-08-04 16:44:11 +0000
3+++ configure.ac 2009-08-19 18:36:22 +0000
4@@ -17,6 +17,8 @@
5 AC_SUBST(VERSION)
6 AC_CONFIG_MACRO_DIR([m4])
7
8+m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
9+
10 ###########################
11 # Dependencies
12 ###########################
13
14=== modified file 'src/Makefile.am'
15--- src/Makefile.am 2009-05-28 15:19:48 +0000
16+++ src/Makefile.am 2009-08-20 01:57:37 +0000
17@@ -1,13 +1,32 @@
18
19 bin_PROGRAMS = indicator-messages-service
20
21+######################################
22+# Building the messages indicator
23+######################################
24+
25 messaginglibdir = $(INDICATORDIR)
26 messaginglib_LTLIBRARIES = libmessaging.la
27-libmessaging_la_SOURCES = indicator-messages.c im-menu-item.c im-menu-item.h app-menu-item.c app-menu-item.h
28+libmessaging_la_SOURCES = \
29+ indicator-messages.c\
30+ dbus-data.h
31 libmessaging_la_CFLAGS = $(APPLET_CFLAGS) -Wall -Wl,-Bsymbolic-functions -Wl,-z,defs -Wl,--as-needed -Werror
32 libmessaging_la_LIBADD = $(APPLET_LIBS)
33 libmessaging_la_LDFLAGS = -module -avoid-version
34
35-indicator_messages_service_SOURCES = indicator-service.c im-menu-item.c im-menu-item.h app-menu-item.c app-menu-item.h
36+######################################
37+# Building the messages service
38+######################################
39+
40+indicator_messages_service_SOURCES = \
41+ messages-service.c \
42+ im-menu-item.c \
43+ im-menu-item.h \
44+ app-menu-item.c \
45+ app-menu-item.h \
46+ launcher-menu-item.c \
47+ launcher-menu-item.h \
48+ dirs.h \
49+ dbus-data.h
50 indicator_messages_service_CFLAGS = $(APPLET_CFLAGS) -Wall -Wl,-Bsymbolic-functions -Wl,-z,defs -Wl,--as-needed -Werror
51 indicator_messages_service_LDADD = $(APPLET_LIBS)
52
53=== modified file 'src/app-menu-item.c'
54--- src/app-menu-item.c 2009-05-26 14:30:31 +0000
55+++ src/app-menu-item.c 2009-08-20 03:29:40 +0000
56@@ -45,6 +45,7 @@
57
58 gchar * type;
59 GAppInfo * appinfo;
60+ gchar * desktop;
61 guint unreadcount;
62 gboolean count_on_label;
63 };
64@@ -105,6 +106,7 @@
65 priv->server = NULL;
66 priv->type = NULL;
67 priv->appinfo = NULL;
68+ priv->desktop = NULL;
69 priv->unreadcount = 0;
70 priv->count_on_label = FALSE;
71
72@@ -136,6 +138,10 @@
73 g_free(priv->type);
74 }
75
76+ if (priv->desktop != NULL) {
77+ g_free(priv->desktop);
78+ }
79+
80 if (priv->appinfo != NULL) {
81 g_object_unref(priv->appinfo);
82 }
83@@ -229,15 +235,23 @@
84
85 if (priv->appinfo != NULL) {
86 g_object_unref(G_OBJECT(priv->appinfo));
87+ priv->appinfo = NULL;
88+ }
89+
90+ if (priv->desktop != NULL) {
91+ g_free(priv->desktop);
92+ priv->desktop = NULL;
93 }
94
95 if (value == NULL || value[0] == '\0') {
96 return;
97 }
98-
99+
100 priv->appinfo = G_APP_INFO(g_desktop_app_info_new_from_filename(value));
101 g_return_if_fail(priv->appinfo != NULL);
102
103+ priv->desktop = g_strdup(value);
104+
105 update_label(self);
106 g_signal_emit(G_OBJECT(self), signals[NAME_CHANGED], 0, app_menu_item_get_name(self), TRUE);
107
108@@ -257,6 +271,7 @@
109 static void
110 indicator_added_cb (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * type, gpointer data)
111 {
112+ g_return_if_fail(IS_APP_MENU_ITEM(data));
113 AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(data);
114
115 if (g_strcmp0(INDICATE_LISTENER_SERVER_DBUS_NAME(server), INDICATE_LISTENER_SERVER_DBUS_NAME(priv->server))) {
116@@ -296,6 +311,7 @@
117 guint
118 app_menu_item_get_count (AppMenuItem * appitem)
119 {
120+ g_return_val_if_fail(IS_APP_MENU_ITEM(appitem), 0);
121 AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(appitem);
122
123 return priv->unreadcount;
124@@ -303,6 +319,7 @@
125
126 IndicateListenerServer *
127 app_menu_item_get_server (AppMenuItem * appitem) {
128+ g_return_val_if_fail(IS_APP_MENU_ITEM(appitem), NULL);
129 AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(appitem);
130
131 return priv->server;
132@@ -311,6 +328,7 @@
133 const gchar *
134 app_menu_item_get_name (AppMenuItem * appitem)
135 {
136+ g_return_val_if_fail(IS_APP_MENU_ITEM(appitem), NULL);
137 AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(appitem);
138
139 if (priv->appinfo == NULL) {
140@@ -319,3 +337,11 @@
141 return g_app_info_get_name(priv->appinfo);
142 }
143 }
144+
145+const gchar *
146+app_menu_item_get_desktop (AppMenuItem * appitem)
147+{
148+ g_return_val_if_fail(IS_APP_MENU_ITEM(appitem), NULL);
149+ AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(appitem);
150+ return priv->desktop;
151+}
152
153=== modified file 'src/app-menu-item.h'
154--- src/app-menu-item.h 2009-05-26 14:30:31 +0000
155+++ src/app-menu-item.h 2009-08-20 03:29:40 +0000
156@@ -59,6 +59,7 @@
157 guint app_menu_item_get_count (AppMenuItem * appitem);
158 IndicateListenerServer * app_menu_item_get_server (AppMenuItem * appitem);
159 const gchar * app_menu_item_get_name (AppMenuItem * appitem);
160+const gchar * app_menu_item_get_desktop (AppMenuItem * appitem);
161
162 G_END_DECLS
163
164
165=== added file 'src/dirs.h'
166--- src/dirs.h 1970-01-01 00:00:00 +0000
167+++ src/dirs.h 2009-08-19 18:50:16 +0000
168@@ -0,0 +1,3 @@
169+#define SYSTEM_APPS_DIR "/etc/indicators/messages/applications"
170+#define USER_APPS_DIR "indicators/messages/applications"
171+#define USER_BLACKLIST_DIR "indicators/messages/applications-blacklist"
172
173=== added file 'src/launcher-menu-item.c'
174--- src/launcher-menu-item.c 1970-01-01 00:00:00 +0000
175+++ src/launcher-menu-item.c 2009-08-20 03:29:40 +0000
176@@ -0,0 +1,184 @@
177+/*
178+An indicator to show information that is in messaging applications
179+that the user is using.
180+
181+Copyright 2009 Canonical Ltd.
182+
183+Authors:
184+ Ted Gould <ted@canonical.com>
185+
186+This program is free software: you can redistribute it and/or modify it
187+under the terms of the GNU General Public License version 3, as published
188+by the Free Software Foundation.
189+
190+This program is distributed in the hope that it will be useful, but
191+WITHOUT ANY WARRANTY; without even the implied warranties of
192+MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
193+PURPOSE. See the GNU General Public License for more details.
194+
195+You should have received a copy of the GNU General Public License along
196+with this program. If not, see <http://www.gnu.org/licenses/>.
197+*/
198+
199+#ifdef HAVE_CONFIG_H
200+#include "config.h"
201+#endif
202+
203+#include <glib/gi18n.h>
204+#include <gio/gdesktopappinfo.h>
205+#include "launcher-menu-item.h"
206+
207+enum {
208+ NAME_CHANGED,
209+ LAST_SIGNAL
210+};
211+
212+static guint signals[LAST_SIGNAL] = { 0 };
213+
214+typedef struct _LauncherMenuItemPrivate LauncherMenuItemPrivate;
215+struct _LauncherMenuItemPrivate
216+{
217+ GAppInfo * appinfo;
218+ gchar * desktop;
219+};
220+
221+#define LAUNCHER_MENU_ITEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), LAUNCHER_MENU_ITEM_TYPE, LauncherMenuItemPrivate))
222+
223+/* Prototypes */
224+static void launcher_menu_item_class_init (LauncherMenuItemClass *klass);
225+static void launcher_menu_item_init (LauncherMenuItem *self);
226+static void launcher_menu_item_dispose (GObject *object);
227+static void launcher_menu_item_finalize (GObject *object);
228+static void activate_cb (LauncherMenuItem * self, gpointer data);
229+
230+
231+G_DEFINE_TYPE (LauncherMenuItem, launcher_menu_item, DBUSMENU_TYPE_MENUITEM);
232+
233+static void
234+launcher_menu_item_class_init (LauncherMenuItemClass *klass)
235+{
236+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
237+
238+ g_type_class_add_private (klass, sizeof (LauncherMenuItemPrivate));
239+
240+ object_class->dispose = launcher_menu_item_dispose;
241+ object_class->finalize = launcher_menu_item_finalize;
242+
243+ signals[NAME_CHANGED] = g_signal_new(LAUNCHER_MENU_ITEM_SIGNAL_NAME_CHANGED,
244+ G_TYPE_FROM_CLASS(klass),
245+ G_SIGNAL_RUN_LAST,
246+ G_STRUCT_OFFSET (LauncherMenuItemClass, name_changed),
247+ NULL, NULL,
248+ g_cclosure_marshal_VOID__STRING,
249+ G_TYPE_NONE, 1, G_TYPE_STRING);
250+
251+ return;
252+}
253+
254+static void
255+launcher_menu_item_init (LauncherMenuItem *self)
256+{
257+ g_debug("Building new Launcher Menu Item");
258+ LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(self);
259+
260+ priv->appinfo = NULL;
261+ priv->desktop = NULL;
262+
263+ return;
264+}
265+
266+static void
267+launcher_menu_item_dispose (GObject *object)
268+{
269+ // LauncherMenuItem * self = LAUNCHER_MENU_ITEM(object);
270+ // LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(self);
271+
272+ G_OBJECT_CLASS (launcher_menu_item_parent_class)->dispose (object);
273+}
274+
275+static void
276+launcher_menu_item_finalize (GObject *object)
277+{
278+ LauncherMenuItem * self = LAUNCHER_MENU_ITEM(object);
279+ LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(self);
280+
281+ if (priv->appinfo != NULL) {
282+ g_object_unref(priv->appinfo);
283+ priv->appinfo = NULL;
284+ }
285+
286+ if (priv->desktop != NULL) {
287+ g_free(priv->desktop);
288+ priv->desktop = NULL;
289+ }
290+
291+ G_OBJECT_CLASS (launcher_menu_item_parent_class)->finalize (object);
292+
293+ return;
294+}
295+
296+LauncherMenuItem *
297+launcher_menu_item_new (const gchar * desktop_file)
298+{
299+ LauncherMenuItem * self = g_object_new(LAUNCHER_MENU_ITEM_TYPE, NULL);
300+ g_debug("\tDesktop file: %s", desktop_file);
301+
302+ LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(self);
303+
304+ priv->appinfo = G_APP_INFO(g_desktop_app_info_new_from_filename(desktop_file));
305+ priv->desktop = g_strdup(desktop_file);
306+
307+ g_debug("\tName: %s", launcher_menu_item_get_name(self));
308+ dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), "label", launcher_menu_item_get_name(self));
309+
310+ g_signal_connect(G_OBJECT(self), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(activate_cb), NULL);
311+
312+ return self;
313+}
314+
315+const gchar *
316+launcher_menu_item_get_name (LauncherMenuItem * appitem)
317+{
318+ LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(appitem);
319+
320+ if (priv->appinfo == NULL) {
321+ return NULL;
322+ } else {
323+ return g_app_info_get_name(priv->appinfo);
324+ }
325+}
326+
327+/* When the menu item is clicked on it tries to launch
328+ the application that is represented by the desktop file */
329+static void
330+activate_cb (LauncherMenuItem * self, gpointer data)
331+{
332+ LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(self);
333+ g_return_if_fail(priv->appinfo != NULL);
334+
335+ GError * error = NULL;
336+ if (!g_app_info_launch(priv->appinfo, NULL, NULL, &error)) {
337+ g_warning("Application failed to launch '%s' because: %s", launcher_menu_item_get_name(self), error->message);
338+ g_error_free(error);
339+ }
340+
341+ return;
342+}
343+
344+const gchar *
345+launcher_menu_item_get_desktop (LauncherMenuItem * launchitem)
346+{
347+ g_return_val_if_fail(IS_LAUNCHER_MENU_ITEM(launchitem), NULL);
348+ LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(launchitem);
349+ return priv->desktop;
350+}
351+
352+/* Hides the menu item based on whether it is eclipsed
353+ or not. */
354+void
355+launcher_menu_item_set_eclipsed (LauncherMenuItem * li, gboolean eclipsed)
356+{
357+ g_debug("Laucher '%s' is %s", launcher_menu_item_get_name(li), eclipsed ? "now eclipsed" : "shown again");
358+ dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(li), "show", eclipsed ? "false" : "true");
359+ return;
360+}
361
362=== added file 'src/launcher-menu-item.h'
363--- src/launcher-menu-item.h 1970-01-01 00:00:00 +0000
364+++ src/launcher-menu-item.h 2009-08-20 03:29:40 +0000
365@@ -0,0 +1,64 @@
366+/*
367+An indicator to show information that is in messaging applications
368+that the user is using.
369+
370+Copyright 2009 Canonical Ltd.
371+
372+Authors:
373+ Ted Gould <ted@canonical.com>
374+
375+This program is free software: you can redistribute it and/or modify it
376+under the terms of the GNU General Public License version 3, as published
377+by the Free Software Foundation.
378+
379+This program is distributed in the hope that it will be useful, but
380+WITHOUT ANY WARRANTY; without even the implied warranties of
381+MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
382+PURPOSE. See the GNU General Public License for more details.
383+
384+You should have received a copy of the GNU General Public License along
385+with this program. If not, see <http://www.gnu.org/licenses/>.
386+*/
387+
388+#ifndef __LAUNCHER_MENU_ITEM_H__
389+#define __LAUNCHER_MENU_ITEM_H__
390+
391+#include <glib.h>
392+#include <glib-object.h>
393+
394+#include <libdbusmenu-glib/menuitem.h>
395+
396+G_BEGIN_DECLS
397+
398+#define LAUNCHER_MENU_ITEM_TYPE (launcher_menu_item_get_type ())
399+#define LAUNCHER_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), LAUNCHER_MENU_ITEM_TYPE, LauncherMenuItem))
400+#define LAUNCHER_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), LAUNCHER_MENU_ITEM_TYPE, LauncherMenuItemClass))
401+#define IS_LAUNCHER_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LAUNCHER_MENU_ITEM_TYPE))
402+#define IS_LAUNCHER_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), LAUNCHER_MENU_ITEM_TYPE))
403+#define LAUNCHER_MENU_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), LAUNCHER_MENU_ITEM_TYPE, LauncherMenuItemClass))
404+
405+#define LAUNCHER_MENU_ITEM_SIGNAL_NAME_CHANGED "name-changed"
406+
407+typedef struct _LauncherMenuItem LauncherMenuItem;
408+typedef struct _LauncherMenuItemClass LauncherMenuItemClass;
409+
410+struct _LauncherMenuItemClass {
411+ DbusmenuMenuitemClass parent_class;
412+
413+ void (* name_changed) (gchar * name);
414+};
415+
416+struct _LauncherMenuItem {
417+ DbusmenuMenuitem parent;
418+};
419+
420+GType launcher_menu_item_get_type (void);
421+LauncherMenuItem * launcher_menu_item_new (const gchar * desktop_file);
422+const gchar * launcher_menu_item_get_name (LauncherMenuItem * appitem);
423+const gchar * launcher_menu_item_get_desktop (LauncherMenuItem * launchitem);
424+void launcher_menu_item_set_eclipsed (LauncherMenuItem * li, gboolean eclipsed);
425+
426+G_END_DECLS
427+
428+#endif /* __LAUNCHER_MENU_ITEM_H__ */
429+
430
431=== renamed file 'src/indicator-service.c' => 'src/messages-service.c'
432--- src/indicator-service.c 2009-05-27 08:44:37 +0000
433+++ src/messages-service.c 2009-08-20 03:54:33 +0000
434@@ -21,6 +21,7 @@
435 */
436
437 #include <string.h>
438+#include <pango/pango-utils.h>
439 #include <dbus/dbus-glib-bindings.h>
440 #include <libindicate/listener.h>
441
442@@ -28,10 +29,13 @@
443
444 #include "im-menu-item.h"
445 #include "app-menu-item.h"
446+#include "launcher-menu-item.h"
447 #include "dbus-data.h"
448+#include "dirs.h"
449
450 static IndicateListener * listener;
451-static GList * serverList;
452+static GList * serverList = NULL;
453+static GList * launcherList = NULL;
454
455 static DbusmenuMenuitem * root_menuitem = NULL;
456 static GMainLoop * mainloop = NULL;
457@@ -40,8 +44,12 @@
458 static void server_count_changed (AppMenuItem * appitem, guint count, gpointer data);
459 static void server_name_changed (AppMenuItem * appitem, gchar * name, gpointer data);
460 static void im_time_changed (ImMenuItem * imitem, glong seconds, gpointer data);
461-static void reconsile_list_and_menu (GList * serverlist, DbusmenuMenuitem * menushell);
462+static void resort_menu (DbusmenuMenuitem * menushell);
463 static void indicator_removed (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * type, gpointer data);
464+static void check_eclipses (AppMenuItem * ai);
465+static void remove_eclipses (AppMenuItem * ai);
466+static gboolean build_launcher (gpointer data);
467+static gboolean build_launchers (gpointer data);
468
469 typedef struct _serverList_t serverList_t;
470 struct _serverList_t {
471@@ -116,6 +124,25 @@
472 return (gint)(im_menu_item_get_seconds(IM_MENU_ITEM(pb->menuitem)) - im_menu_item_get_seconds(IM_MENU_ITEM(pa->menuitem)));
473 }
474
475+typedef struct _launcherList_t launcherList_t;
476+struct _launcherList_t {
477+ LauncherMenuItem * menuitem;
478+};
479+
480+static gint
481+launcherList_sort (gconstpointer a, gconstpointer b)
482+{
483+ launcherList_t * pa, * pb;
484+
485+ pa = (launcherList_t *)a;
486+ pb = (launcherList_t *)b;
487+
488+ const gchar * pan = launcher_menu_item_get_name(pa->menuitem);
489+ const gchar * pbn = launcher_menu_item_get_name(pb->menuitem);
490+
491+ return g_strcmp0(pan, pbn);
492+}
493+
494 static void
495 server_added (IndicateListener * listener, IndicateListenerServer * server, gchar * type, gpointer data)
496 {
497@@ -162,7 +189,7 @@
498 dbusmenu_menuitem_child_append(menushell, DBUSMENU_MENUITEM(menuitem));
499 /* Should be prepend ^ */
500
501- reconsile_list_and_menu(serverList, menushell);
502+ resort_menu(menushell);
503
504 return;
505 }
506@@ -171,7 +198,8 @@
507 server_name_changed (AppMenuItem * appitem, gchar * name, gpointer data)
508 {
509 serverList = g_list_sort(serverList, serverList_sort);
510- reconsile_list_and_menu(serverList, DBUSMENU_MENUITEM(data));
511+ check_eclipses(appitem);
512+ resort_menu(DBUSMENU_MENUITEM(data));
513 return;
514 }
515
516@@ -226,7 +254,7 @@
517 {
518 serverList_t * sl = (serverList_t *)data;
519 sl->imList = g_list_sort(sl->imList, imList_sort);
520- reconsile_list_and_menu(serverList, root_menuitem);
521+ resort_menu(root_menuitem);
522 return;
523 }
524
525@@ -245,6 +273,8 @@
526
527 serverList_t * sltp = (serverList_t *)lookup->data;
528
529+ remove_eclipses(sltp->menuitem);
530+
531 while (sltp->imList) {
532 imList_t * imitem = (imList_t *)sltp->imList->data;
533 indicator_removed(listener, server, imitem->indicator, "message", data);
534@@ -255,6 +285,7 @@
535 if (sltp->menuitem != NULL) {
536 dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(sltp->menuitem), "visibile", "false");
537 dbusmenu_menuitem_child_delete(DBUSMENU_MENUITEM(data), DBUSMENU_MENUITEM(sltp->menuitem));
538+ g_object_unref(G_OBJECT(sltp->menuitem));
539 }
540
541 g_free(sltp);
542@@ -293,15 +324,31 @@
543 }
544
545 static void
546-reconsile_list_and_menu (GList * serverlist, DbusmenuMenuitem * menushell)
547+resort_menu (DbusmenuMenuitem * menushell)
548 {
549 guint position = 0;
550 GList * serverentry;
551+ GList * launcherentry = launcherList;
552
553 g_debug("Reordering Menu:");
554
555 for (serverentry = serverList; serverentry != NULL; serverentry = serverentry->next) {
556 serverList_t * si = (serverList_t *)serverentry->data;
557+
558+ if (launcherentry != NULL) {
559+ launcherList_t * li = (launcherList_t *)launcherentry->data;
560+ while (launcherentry != NULL && g_strcmp0(launcher_menu_item_get_name(li->menuitem), app_menu_item_get_name(si->menuitem)) < 0) {
561+ g_debug("\tMoving launcher '%s' to position %d", launcher_menu_item_get_name(li->menuitem), position);
562+ dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(li->menuitem), position);
563+
564+ position++;
565+ launcherentry = launcherentry->next;
566+ if (launcherentry != NULL) {
567+ li = (launcherList_t *)launcherentry->data;
568+ }
569+ }
570+ }
571+
572 if (si->menuitem != NULL) {
573 g_debug("\tMoving app %s to position %d", INDICATE_LISTENER_SERVER_DBUS_NAME(si->server), position);
574 dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(si->menuitem), position);
575@@ -320,6 +367,15 @@
576 }
577 }
578
579+ while (launcherentry != NULL) {
580+ launcherList_t * li = (launcherList_t *)launcherentry->data;
581+ g_debug("\tMoving launcher '%s' to position %d", launcher_menu_item_get_name(li->menuitem), position);
582+ dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(li->menuitem), position);
583+
584+ position++;
585+ launcherentry = launcherentry->next;
586+ }
587+
588 return;
589 }
590
591@@ -465,6 +521,123 @@
592 return;
593 }
594
595+/* Check to see if a new desktop file causes
596+ any of the launchers to be eclipsed by a running
597+ process */
598+static void
599+check_eclipses (AppMenuItem * ai)
600+{
601+ g_debug("Checking eclipsing");
602+ const gchar * aidesktop = app_menu_item_get_desktop(ai);
603+ if (aidesktop == NULL) return;
604+ g_debug("\tApp desktop: %s", aidesktop);
605+
606+ GList * llitem;
607+ for (llitem = launcherList; llitem != NULL; llitem = llitem->next) {
608+ launcherList_t * ll = (launcherList_t *)llitem->data;
609+ const gchar * lidesktop = launcher_menu_item_get_desktop(ll->menuitem);
610+ g_debug("\tLauncher desktop: %s", lidesktop);
611+
612+ if (!g_strcmp0(aidesktop, lidesktop)) {
613+ launcher_menu_item_set_eclipsed(ll->menuitem, TRUE);
614+ break;
615+ }
616+ }
617+
618+ return;
619+}
620+
621+/* Remove any eclipses that might have been caused
622+ by this app item that is now retiring */
623+static void
624+remove_eclipses (AppMenuItem * ai)
625+{
626+ const gchar * aidesktop = app_menu_item_get_desktop(ai);
627+ if (aidesktop == NULL) return;
628+
629+ GList * llitem;
630+ for (llitem = launcherList; llitem != NULL; llitem = llitem->next) {
631+ launcherList_t * ll = (launcherList_t *)llitem->data;
632+ const gchar * lidesktop = launcher_menu_item_get_desktop(ll->menuitem);
633+
634+ if (!g_strcmp0(aidesktop, lidesktop)) {
635+ launcher_menu_item_set_eclipsed(ll->menuitem, FALSE);
636+ break;
637+ }
638+ }
639+
640+ return;
641+}
642+
643+/* This function turns a specific file into a menu
644+ item and registers it appropriately with everyone */
645+static gboolean
646+build_launcher (gpointer data)
647+{
648+ /* Read the file get the data */
649+ gchar * path = (gchar *)data;
650+ g_debug("\tpath: %s", path);
651+ gchar * desktop = NULL;
652+
653+ g_file_get_contents(path, &desktop, NULL, NULL);
654+ g_free(path);
655+
656+ if (desktop == NULL) {
657+ return FALSE;
658+ }
659+
660+ gchar * trimdesktop = pango_trim_string(desktop);
661+ g_free(desktop);
662+ g_debug("\tcontents: %s", trimdesktop);
663+
664+ /* Build the item */
665+ launcherList_t * ll = g_new0(launcherList_t, 1);
666+ ll->menuitem = launcher_menu_item_new(trimdesktop);
667+ g_free(trimdesktop);
668+
669+ /* Add it to the list */
670+ launcherList = g_list_insert_sorted(launcherList, ll, launcherList_sort);
671+
672+ /* Add it to the menu */
673+ dbusmenu_menuitem_child_append(root_menuitem, DBUSMENU_MENUITEM(ll->menuitem));
674+ resort_menu(root_menuitem);
675+
676+ return FALSE;
677+}
678+
679+/* This function goes through all the launchers that we're
680+ supposed to be grabbing and decides to show turn them
681+ into menu items or not. It doens't do the work, but it
682+ makes the decision. */
683+static gboolean
684+build_launchers (gpointer data)
685+{
686+ if (!g_file_test(SYSTEM_APPS_DIR, G_FILE_TEST_IS_DIR)) {
687+ return FALSE;
688+ }
689+
690+ GError * error = NULL;
691+ GDir * dir = g_dir_open(SYSTEM_APPS_DIR, 0, &error);
692+ if (dir == NULL) {
693+ g_warning("Unable to open system apps directory: %s", error->message);
694+ g_error_free(error);
695+ return FALSE;
696+ }
697+
698+ const gchar * filename = NULL;
699+ while ((filename = g_dir_read_name(dir)) != NULL) {
700+ g_debug("Found file: %s", filename);
701+ gchar * path = g_build_filename(SYSTEM_APPS_DIR, filename, NULL);
702+ g_idle_add(build_launcher, path);
703+ }
704+
705+ g_dir_close(dir);
706+ launcherList = g_list_sort(launcherList, launcherList_sort);
707+ return FALSE;
708+}
709+
710+/* Oh, if you don't know what main() is for
711+ we really shouldn't be talking. */
712 int
713 main (int argc, char ** argv)
714 {
715@@ -497,6 +670,8 @@
716 g_signal_connect(listener, INDICATE_LISTENER_SIGNAL_SERVER_ADDED, G_CALLBACK(server_added), root_menuitem);
717 g_signal_connect(listener, INDICATE_LISTENER_SIGNAL_SERVER_REMOVED, G_CALLBACK(server_removed), root_menuitem);
718
719+ g_idle_add(build_launchers, NULL);
720+
721 mainloop = g_main_loop_new(NULL, FALSE);
722 g_main_loop_run(mainloop);
723

Subscribers

People subscribed via source and target branches