Merge lp:~ted/indicator-applet/messages-launchers into lp:indicator-applet/messages0.2
- messages-launchers
- Merge into messages
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 |
Related bugs: |
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.
Description of the change
Ted Gould (ted) wrote : | # |
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_
- is reconsile_
- 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?
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_
> 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_
> 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.
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_
> > 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.
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.
00_empathy.desktop
for apps in main for example
while universe ones would have:
99_my_funky_
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
David Barth (dbarth) wrote : | # |
Go ahead with the change.
Preview Diff
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 |
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: /messages/ applications applications/ evolution- mail.desktop" > /etc/indicators /messages/ applications/ test
$ sudo bash
% mkdir -p /etc/indicators
% echo "/usr/share/