1.1.5
by Ted Gould
Import upstream version 0.2.0 |
1 |
/*
|
2 |
An indicator to show information that is in messaging applications
|
|
3 |
that the user is using.
|
|
4 |
||
5 |
Copyright 2009 Canonical Ltd.
|
|
6 |
||
7 |
Authors:
|
|
8 |
Ted Gould <ted@canonical.com>
|
|
9 |
||
10 |
This program is free software: you can redistribute it and/or modify it
|
|
11 |
under the terms of the GNU General Public License version 3, as published
|
|
12 |
by the Free Software Foundation.
|
|
13 |
||
14 |
This program is distributed in the hope that it will be useful, but
|
|
15 |
WITHOUT ANY WARRANTY; without even the implied warranties of
|
|
16 |
MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
|
|
17 |
PURPOSE. See the GNU General Public License for more details.
|
|
18 |
||
19 |
You should have received a copy of the GNU General Public License along
|
|
20 |
with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
21 |
*/
|
|
22 |
||
23 |
#include <string.h> |
|
14
by Sebastien Bacher
src/messages-service.c: initialise the translations |
24 |
#include <locale.h> |
1.1.7
by Ted Gould
Import upstream version 0.2.4 |
25 |
#include <libintl.h> |
26 |
#include <config.h> |
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
27 |
#include <pango/pango-utils.h> |
28 |
#include <dbus/dbus-glib-bindings.h> |
|
29 |
#include <libindicate/listener.h> |
|
30 |
#include <gio/gio.h> |
|
31 |
||
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
32 |
#include <libdbusmenu-glib/client.h> |
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
33 |
#include <libdbusmenu-glib/server.h> |
34 |
||
35 |
#include "im-menu-item.h" |
|
36 |
#include "app-menu-item.h" |
|
37 |
#include "launcher-menu-item.h" |
|
38 |
#include "dbus-data.h" |
|
39 |
#include "dirs.h" |
|
40 |
#include "messages-service-dbus.h" |
|
41 |
||
42 |
static IndicateListener * listener; |
|
43 |
static GList * serverList = NULL; |
|
44 |
static GList * launcherList = NULL; |
|
45 |
||
46 |
static DbusmenuMenuitem * root_menuitem = NULL; |
|
47 |
static GMainLoop * mainloop = NULL; |
|
48 |
||
49 |
static MessageServiceDbus * dbus_interface = NULL; |
|
50 |
||
51 |
||
52 |
static void server_count_changed (AppMenuItem * appitem, guint count, gpointer data); |
|
53 |
static void server_name_changed (AppMenuItem * appitem, gchar * name, gpointer data); |
|
54 |
static void im_time_changed (ImMenuItem * imitem, glong seconds, gpointer data); |
|
55 |
static void resort_menu (DbusmenuMenuitem * menushell); |
|
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
56 |
static void indicator_removed (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gpointer data); |
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
57 |
static void check_eclipses (AppMenuItem * ai); |
58 |
static void remove_eclipses (AppMenuItem * ai); |
|
59 |
static gboolean build_launcher (gpointer data); |
|
60 |
static gboolean build_launchers (gpointer data); |
|
61 |
static gboolean blacklist_init (gpointer data); |
|
62 |
static gboolean blacklist_add (gpointer data); |
|
63 |
static gboolean blacklist_remove (gpointer data); |
|
64 |
static void blacklist_dir_changed (GFileMonitor * monitor, GFile * file, GFile * other_file, GFileMonitorEvent event_type, gpointer user_data); |
|
65 |
static void app_dir_changed (GFileMonitor * monitor, GFile * file, GFile * other_file, GFileMonitorEvent event_type, gpointer user_data); |
|
66 |
static gboolean destroy_launcher (gpointer data); |
|
67 |
static void check_hidden (void); |
|
68 |
||
69 |
||
70 |
/*
|
|
71 |
* Server List
|
|
72 |
*/
|
|
73 |
||
74 |
typedef struct _serverList_t serverList_t; |
|
75 |
struct _serverList_t { |
|
76 |
IndicateListenerServer * server; |
|
77 |
AppMenuItem * menuitem; |
|
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
78 |
DbusmenuMenuitem * separator; |
79 |
gboolean attention; |
|
80 |
guint count; |
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
81 |
GList * imList; |
82 |
};
|
|
83 |
||
84 |
static gint |
|
85 |
serverList_equal (gconstpointer a, gconstpointer b) |
|
86 |
{
|
|
87 |
serverList_t * pa, * pb; |
|
88 |
||
89 |
pa = (serverList_t *)a; |
|
90 |
pb = (serverList_t *)b; |
|
91 |
||
92 |
const gchar * pas = INDICATE_LISTENER_SERVER_DBUS_NAME(pa->server); |
|
93 |
const gchar * pbs = INDICATE_LISTENER_SERVER_DBUS_NAME(pb->server); |
|
94 |
||
95 |
return g_strcmp0(pas, pbs); |
|
96 |
}
|
|
97 |
||
98 |
static gint |
|
99 |
serverList_sort (gconstpointer a, gconstpointer b) |
|
100 |
{
|
|
101 |
serverList_t * pa, * pb; |
|
102 |
||
103 |
pa = (serverList_t *)a; |
|
104 |
pb = (serverList_t *)b; |
|
105 |
||
106 |
const gchar * pan = app_menu_item_get_name(pa->menuitem); |
|
107 |
const gchar * pbn = app_menu_item_get_name(pb->menuitem); |
|
108 |
||
109 |
return g_strcmp0(pan, pbn); |
|
110 |
}
|
|
111 |
||
112 |
/*
|
|
113 |
* Item List
|
|
114 |
*/
|
|
115 |
||
116 |
typedef struct _imList_t imList_t; |
|
117 |
struct _imList_t { |
|
118 |
IndicateListenerServer * server; |
|
119 |
IndicateListenerIndicator * indicator; |
|
120 |
DbusmenuMenuitem * menuitem; |
|
121 |
gulong timechange_cb; |
|
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
122 |
gulong attentionchange_cb; |
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
123 |
};
|
124 |
||
125 |
static gboolean |
|
126 |
imList_equal (gconstpointer a, gconstpointer b) |
|
127 |
{
|
|
128 |
imList_t * pa, * pb; |
|
129 |
||
130 |
pa = (imList_t *)a; |
|
131 |
pb = (imList_t *)b; |
|
132 |
||
133 |
const gchar * pas = INDICATE_LISTENER_SERVER_DBUS_NAME(pa->server); |
|
134 |
const gchar * pbs = INDICATE_LISTENER_SERVER_DBUS_NAME(pb->server); |
|
135 |
||
136 |
guint pai = INDICATE_LISTENER_INDICATOR_ID(pa->indicator); |
|
137 |
guint pbi = INDICATE_LISTENER_INDICATOR_ID(pb->indicator); |
|
138 |
||
139 |
g_debug("\tComparing (%s %d) to (%s %d)", pas, pai, pbs, pbi); |
|
140 |
||
141 |
return !((!g_strcmp0(pas, pbs)) && (pai == pbi)); |
|
142 |
}
|
|
143 |
||
144 |
static gint |
|
145 |
imList_sort (gconstpointer a, gconstpointer b) |
|
146 |
{
|
|
147 |
imList_t * pa, * pb; |
|
148 |
||
149 |
pa = (imList_t *)a; |
|
150 |
pb = (imList_t *)b; |
|
151 |
||
152 |
return (gint)(im_menu_item_get_seconds(IM_MENU_ITEM(pb->menuitem)) - im_menu_item_get_seconds(IM_MENU_ITEM(pa->menuitem))); |
|
153 |
}
|
|
154 |
||
155 |
/*
|
|
156 |
* Launcher List
|
|
157 |
*/
|
|
158 |
||
159 |
typedef struct _launcherList_t launcherList_t; |
|
160 |
struct _launcherList_t { |
|
161 |
LauncherMenuItem * menuitem; |
|
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
162 |
DbusmenuMenuitem * separator; |
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
163 |
GList * appdiritems; |
164 |
};
|
|
165 |
||
166 |
static gint |
|
167 |
launcherList_sort (gconstpointer a, gconstpointer b) |
|
168 |
{
|
|
169 |
launcherList_t * pa, * pb; |
|
170 |
||
171 |
pa = (launcherList_t *)a; |
|
172 |
pb = (launcherList_t *)b; |
|
173 |
||
174 |
const gchar * pan = launcher_menu_item_get_name(pa->menuitem); |
|
175 |
const gchar * pbn = launcher_menu_item_get_name(pb->menuitem); |
|
176 |
||
177 |
return g_strcmp0(pan, pbn); |
|
178 |
}
|
|
179 |
||
180 |
static void |
|
181 |
launcherList_count_helper (gpointer data, gpointer user_data) |
|
182 |
{
|
|
183 |
guint * count = (guint *)user_data; |
|
184 |
launcherList_t * li = (launcherList_t *)data; |
|
185 |
||
186 |
if (!launcher_menu_item_get_eclipsed(li->menuitem)) { |
|
187 |
*count = *count + 1; |
|
188 |
}
|
|
189 |
||
190 |
return; |
|
191 |
}
|
|
192 |
||
193 |
static guint |
|
194 |
launcherList_count (void) |
|
195 |
{
|
|
196 |
guint count = 0; |
|
197 |
||
198 |
g_list_foreach(launcherList, launcherList_count_helper, &count); |
|
199 |
||
200 |
return count; |
|
201 |
}
|
|
202 |
||
203 |
/*
|
|
204 |
* Black List
|
|
205 |
*/
|
|
206 |
||
207 |
static GHashTable * blacklist = NULL; |
|
208 |
static GFileMonitor * blacklistdirmon = NULL; |
|
209 |
||
210 |
/* Initialize the black list and start to setup
|
|
211 |
handlers for it. */
|
|
212 |
static gboolean |
|
213 |
blacklist_init (gpointer data) |
|
214 |
{
|
|
215 |
blacklist = g_hash_table_new_full(g_str_hash, g_str_equal, |
|
216 |
g_free, g_free); |
|
217 |
||
218 |
gchar * blacklistdir = g_build_filename(g_get_user_config_dir(), USER_BLACKLIST_DIR, NULL); |
|
219 |
g_debug("Looking at blacklist: %s", blacklistdir); |
|
220 |
if (!g_file_test(blacklistdir, G_FILE_TEST_IS_DIR)) { |
|
221 |
g_free(blacklistdir); |
|
222 |
return FALSE; |
|
223 |
}
|
|
224 |
||
225 |
GFile * filedir = g_file_new_for_path(blacklistdir); |
|
226 |
blacklistdirmon = g_file_monitor_directory(filedir, G_FILE_MONITOR_NONE, NULL, NULL); |
|
227 |
if (blacklistdirmon != NULL) { |
|
228 |
g_signal_connect(G_OBJECT(blacklistdirmon), "changed", G_CALLBACK(blacklist_dir_changed), NULL); |
|
229 |
}
|
|
230 |
||
231 |
GError * error = NULL; |
|
232 |
GDir * dir = g_dir_open(blacklistdir, 0, &error); |
|
233 |
if (dir == NULL) { |
|
234 |
g_warning("Unable to open blacklist directory (%s): %s", blacklistdir, error == NULL ? "No Message" : error->message); |
|
235 |
g_error_free(error); |
|
236 |
g_free(blacklistdir); |
|
237 |
return FALSE; |
|
238 |
}
|
|
239 |
||
240 |
const gchar * filename = NULL; |
|
241 |
while ((filename = g_dir_read_name(dir)) != NULL) { |
|
242 |
g_debug("Found file: %s", filename); |
|
243 |
gchar * path = g_build_filename(blacklistdir, filename, NULL); |
|
244 |
g_idle_add(blacklist_add, path); |
|
245 |
}
|
|
246 |
||
247 |
g_dir_close(dir); |
|
248 |
g_free(blacklistdir); |
|
249 |
||
250 |
return FALSE; |
|
251 |
}
|
|
252 |
||
253 |
/* Add a definition file into the black list and eclipse
|
|
254 |
and launchers that have the same file. */
|
|
255 |
static gboolean |
|
256 |
blacklist_add (gpointer udata) |
|
257 |
{
|
|
258 |
gchar * definition_file = (gchar *)udata; |
|
259 |
/* Dump the file */
|
|
260 |
gchar * desktop; |
|
261 |
g_file_get_contents(definition_file, &desktop, NULL, NULL); |
|
262 |
if (desktop == NULL) { |
|
263 |
g_warning("Couldn't get data out of: %s", definition_file); |
|
264 |
return FALSE; |
|
265 |
}
|
|
266 |
||
267 |
/* Clean up the data */
|
|
268 |
gchar * trimdesktop = pango_trim_string(desktop); |
|
269 |
g_free(desktop); |
|
270 |
||
271 |
/* Check for conflicts */
|
|
272 |
gpointer data = g_hash_table_lookup(blacklist, trimdesktop); |
|
273 |
if (data != NULL) { |
|
274 |
gchar * oldfile = (gchar *)data; |
|
275 |
if (!g_strcmp0(oldfile, definition_file)) { |
|
276 |
g_warning("Already added file '%s'", oldfile); |
|
277 |
} else { |
|
278 |
g_warning("Already have desktop file '%s' in blacklist file '%s' not adding from '%s'", trimdesktop, oldfile, definition_file); |
|
279 |
}
|
|
280 |
||
281 |
g_free(trimdesktop); |
|
282 |
g_free(definition_file); |
|
283 |
return FALSE; |
|
284 |
}
|
|
285 |
||
286 |
/* Actually blacklist this thing */
|
|
287 |
g_hash_table_insert(blacklist, trimdesktop, definition_file); |
|
288 |
g_debug("Adding Blacklist item '%s' for desktop '%s'", definition_file, trimdesktop); |
|
289 |
||
290 |
/* Go through and eclipse folks */
|
|
291 |
GList * launcher; |
|
292 |
for (launcher = launcherList; launcher != NULL; launcher = launcher->next) { |
|
293 |
launcherList_t * item = (launcherList_t *)launcher->data; |
|
294 |
if (!g_strcmp0(trimdesktop, launcher_menu_item_get_desktop(item->menuitem))) { |
|
295 |
launcher_menu_item_set_eclipsed(item->menuitem, TRUE); |
|
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
296 |
dbusmenu_menuitem_property_set(item->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, "false"); |
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
297 |
}
|
298 |
}
|
|
299 |
||
300 |
check_hidden(); |
|
301 |
||
302 |
return FALSE; |
|
303 |
}
|
|
304 |
||
305 |
/* Remove a black list item based on the definition file
|
|
306 |
and uneclipse those launchers blocked by it. */
|
|
307 |
static gboolean |
|
308 |
blacklist_remove (gpointer data) |
|
309 |
{
|
|
310 |
gchar * definition_file = (gchar *)data; |
|
311 |
g_debug("Removing: %s", definition_file); |
|
312 |
||
313 |
GHashTableIter iter; |
|
314 |
gpointer key, value; |
|
315 |
gboolean found = FALSE; |
|
316 |
||
317 |
g_hash_table_iter_init(&iter, blacklist); |
|
318 |
while (g_hash_table_iter_next(&iter, &key, &value)) { |
|
319 |
if (!g_strcmp0((gchar *)value, definition_file)) { |
|
320 |
found = TRUE; |
|
321 |
break; |
|
322 |
}
|
|
323 |
}
|
|
324 |
||
325 |
if (!found) { |
|
326 |
g_debug("\tNot found!"); |
|
327 |
return FALSE; |
|
328 |
}
|
|
329 |
||
330 |
GList * launcheritem; |
|
331 |
for (launcheritem = launcherList; launcheritem != NULL; launcheritem = launcheritem->next) { |
|
332 |
launcherList_t * li = (launcherList_t *)launcheritem->data; |
|
333 |
if (!g_strcmp0(launcher_menu_item_get_desktop(li->menuitem), (gchar *)key)) { |
|
334 |
GList * serveritem; |
|
335 |
for (serveritem = serverList; serveritem != NULL; serveritem = serveritem->next) { |
|
336 |
serverList_t * si = (serverList_t *)serveritem->data; |
|
337 |
if (!g_strcmp0(app_menu_item_get_desktop(si->menuitem), (gchar *)key)) { |
|
338 |
break; |
|
339 |
}
|
|
340 |
}
|
|
341 |
if (serveritem == NULL) { |
|
342 |
launcher_menu_item_set_eclipsed(li->menuitem, FALSE); |
|
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
343 |
dbusmenu_menuitem_property_set(li->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, "true"); |
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
344 |
}
|
345 |
}
|
|
346 |
}
|
|
347 |
||
348 |
if (!g_hash_table_remove(blacklist, key)) { |
|
349 |
g_warning("Unable to remove '%s' with value '%s'", definition_file, (gchar *)key); |
|
350 |
}
|
|
351 |
||
352 |
check_hidden(); |
|
1.1.7
by Ted Gould
Import upstream version 0.2.4 |
353 |
resort_menu(root_menuitem); |
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
354 |
|
355 |
return FALSE; |
|
356 |
}
|
|
357 |
||
358 |
/* Check to see if a particular desktop file is
|
|
359 |
in the blacklist. */
|
|
360 |
static gboolean |
|
361 |
blacklist_check (const gchar * desktop_file) |
|
362 |
{
|
|
363 |
g_debug("Checking blacklist for: %s", desktop_file); |
|
364 |
if (blacklist == NULL) return FALSE; |
|
365 |
||
366 |
if (g_hash_table_lookup(blacklist, desktop_file)) { |
|
367 |
g_debug("\tFound!"); |
|
368 |
return TRUE; |
|
369 |
}
|
|
370 |
||
371 |
return FALSE; |
|
372 |
}
|
|
373 |
||
374 |
/* A callback everytime the blacklist directory changes
|
|
375 |
in some way. It needs to handle that. */
|
|
376 |
static void |
|
377 |
blacklist_dir_changed (GFileMonitor * monitor, GFile * file, GFile * other_file, GFileMonitorEvent event_type, gpointer user_data) |
|
378 |
{
|
|
379 |
g_debug("Blacklist directory changed!"); |
|
380 |
||
381 |
switch (event_type) { |
|
382 |
case G_FILE_MONITOR_EVENT_DELETED: { |
|
383 |
gchar * path = g_file_get_path(file); |
|
384 |
g_debug("\tDelete: %s", path); |
|
385 |
g_idle_add(blacklist_remove, path); |
|
386 |
break; |
|
387 |
}
|
|
388 |
case G_FILE_MONITOR_EVENT_CREATED: { |
|
389 |
gchar * path = g_file_get_path(file); |
|
390 |
g_debug("\tCreate: %s", path); |
|
391 |
g_idle_add(blacklist_add, path); |
|
392 |
break; |
|
393 |
}
|
|
394 |
default: |
|
395 |
break; |
|
396 |
}
|
|
397 |
||
398 |
return; |
|
399 |
}
|
|
400 |
||
401 |
/*
|
|
402 |
* More code
|
|
403 |
*/
|
|
404 |
||
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
405 |
/* Goes through all the servers and sees if any of them
|
406 |
want attention. If they do, then well we'll give it
|
|
407 |
to them. If they don't, let's not bother the user
|
|
408 |
any, shall we? */
|
|
409 |
static void |
|
410 |
check_attention (void) |
|
411 |
{
|
|
412 |
GList * pointer; |
|
413 |
for (pointer = serverList; pointer != NULL; pointer = g_list_next(pointer)) { |
|
414 |
serverList_t * slt = (serverList_t *)pointer->data; |
|
415 |
if (slt->attention) { |
|
416 |
message_service_dbus_set_attention(dbus_interface, TRUE); |
|
417 |
return; |
|
418 |
}
|
|
419 |
}
|
|
420 |
message_service_dbus_set_attention(dbus_interface, FALSE); |
|
421 |
return; |
|
422 |
}
|
|
423 |
||
424 |
/* This checks a server listing to see if it should
|
|
425 |
have attention. It can get attention through it's
|
|
426 |
count or by having an indicator that is requestion
|
|
427 |
attention. */
|
|
428 |
static void |
|
429 |
server_attention (serverList_t * slt) |
|
430 |
{
|
|
431 |
/* Count, easy yes and out. */
|
|
432 |
if (slt->count > 0) { |
|
433 |
slt->attention = TRUE; |
|
434 |
return; |
|
435 |
}
|
|
436 |
||
437 |
/* Check to see if any of the indicators want attention */
|
|
438 |
GList * pointer; |
|
439 |
for (pointer = slt->imList; pointer != NULL; pointer = g_list_next(pointer)) { |
|
440 |
imList_t * ilt = (imList_t *)pointer->data; |
|
441 |
if (im_menu_item_get_attention(IM_MENU_ITEM(ilt->menuitem))) { |
|
442 |
slt->attention = TRUE; |
|
443 |
return; |
|
444 |
}
|
|
445 |
}
|
|
446 |
||
447 |
/* Nope, no one */
|
|
448 |
slt->attention = FALSE; |
|
449 |
return; |
|
450 |
}
|
|
451 |
||
452 |
/* A new server has been created on the indicate bus.
|
|
453 |
We need to check to see if we like it. And build
|
|
454 |
structures for it if so. */
|
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
455 |
static void |
456 |
server_added (IndicateListener * listener, IndicateListenerServer * server, gchar * type, gpointer data) |
|
457 |
{
|
|
458 |
g_debug("Server Added '%s' of type '%s'.", INDICATE_LISTENER_SERVER_DBUS_NAME(server), type); |
|
459 |
if (type == NULL) { |
|
460 |
return; |
|
461 |
}
|
|
462 |
||
463 |
if (type[0] == '\0') { |
|
464 |
return; |
|
465 |
}
|
|
466 |
||
467 |
if (strncmp(type, "message", strlen("message"))) { |
|
468 |
g_debug("\tServer type '%s' is not a message based type.", type); |
|
469 |
return; |
|
470 |
}
|
|
471 |
||
472 |
DbusmenuMenuitem * menushell = DBUSMENU_MENUITEM(data); |
|
473 |
if (menushell == NULL) { |
|
474 |
g_error("\tData in callback is not a menushell"); |
|
475 |
return; |
|
476 |
}
|
|
477 |
||
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
478 |
/* Build the Menu item */
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
479 |
AppMenuItem * menuitem = app_menu_item_new(listener, server); |
480 |
||
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
481 |
/* Build a possible server structure */
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
482 |
serverList_t * sl_item = g_new0(serverList_t, 1); |
483 |
sl_item->server = server; |
|
484 |
sl_item->menuitem = menuitem; |
|
485 |
sl_item->imList = NULL; |
|
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
486 |
sl_item->attention = FALSE; |
487 |
sl_item->count = 0; |
|
488 |
||
489 |
/* Build a separator */
|
|
490 |
sl_item->separator = dbusmenu_menuitem_new(); |
|
491 |
dbusmenu_menuitem_property_set(sl_item->separator, "type", DBUSMENU_CLIENT_TYPES_SEPARATOR); |
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
492 |
|
493 |
/* Incase we got an indicator first */
|
|
494 |
GList * alreadythere = g_list_find_custom(serverList, sl_item, serverList_equal); |
|
495 |
if (alreadythere != NULL) { |
|
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
496 |
/* Use the one we already had */
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
497 |
g_free(sl_item); |
498 |
sl_item = (serverList_t *)alreadythere->data; |
|
499 |
sl_item->menuitem = menuitem; |
|
500 |
serverList = g_list_sort(serverList, serverList_sort); |
|
501 |
} else { |
|
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
502 |
/* Insert the new one in the list */
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
503 |
serverList = g_list_insert_sorted(serverList, sl_item, serverList_sort); |
504 |
}
|
|
505 |
||
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
506 |
/* Connect the signals up to the menu item */
|
507 |
g_signal_connect(G_OBJECT(menuitem), APP_MENU_ITEM_SIGNAL_COUNT_CHANGED, G_CALLBACK(server_count_changed), sl_item); |
|
508 |
g_signal_connect(G_OBJECT(menuitem), APP_MENU_ITEM_SIGNAL_NAME_CHANGED, G_CALLBACK(server_name_changed), menushell); |
|
509 |
||
510 |
/* Put our new menu item in, with the separator behind it.
|
|
511 |
resort_menu will take care of whether it should be hidden
|
|
512 |
or not. */
|
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
513 |
dbusmenu_menuitem_child_append(menushell, DBUSMENU_MENUITEM(menuitem)); |
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
514 |
dbusmenu_menuitem_child_append(menushell, DBUSMENU_MENUITEM(sl_item->separator)); |
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
515 |
|
516 |
resort_menu(menushell); |
|
517 |
check_hidden(); |
|
518 |
||
519 |
return; |
|
520 |
}
|
|
521 |
||
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
522 |
/* The name of a server has changed, we probably
|
523 |
need to reorder the menu to keep it in alphabetical
|
|
524 |
order. This happens often after we read the destkop
|
|
525 |
file from disk. */
|
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
526 |
static void |
527 |
server_name_changed (AppMenuItem * appitem, gchar * name, gpointer data) |
|
528 |
{
|
|
529 |
serverList = g_list_sort(serverList, serverList_sort); |
|
530 |
check_eclipses(appitem); |
|
531 |
resort_menu(DBUSMENU_MENUITEM(data)); |
|
532 |
return; |
|
533 |
}
|
|
534 |
||
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
535 |
/* If the count on the server changes, we need to know
|
536 |
whether that should be grabbing attention or not. If
|
|
537 |
it is, we need to reevaluate whether the whole thing
|
|
538 |
should be grabbing attention or not. */
|
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
539 |
static void |
540 |
server_count_changed (AppMenuItem * appitem, guint count, gpointer data) |
|
541 |
{
|
|
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
542 |
serverList_t * slt = (serverList_t *)data; |
543 |
slt->count = count; |
|
544 |
||
545 |
if (count == 0 && slt->attention) { |
|
546 |
/* Regen based on indicators if the count isn't going to cause it. */
|
|
547 |
server_attention(slt); |
|
548 |
/* If we're dropping let's see if we're the last. */
|
|
549 |
if (!slt->attention) { |
|
550 |
check_attention(); |
|
551 |
}
|
|
552 |
}
|
|
553 |
||
554 |
if (count != 0 && !slt->attention) { |
|
555 |
slt->attention = TRUE; |
|
556 |
/* Let's tell everyone about us! */
|
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
557 |
message_service_dbus_set_attention(dbus_interface, TRUE); |
558 |
}
|
|
559 |
||
560 |
return; |
|
561 |
}
|
|
562 |
||
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
563 |
/* Respond to the IM entrie's time changing
|
564 |
which results in it needing to resort the list
|
|
565 |
and rebuild the menu to match. */
|
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
566 |
static void |
567 |
im_time_changed (ImMenuItem * imitem, glong seconds, gpointer data) |
|
568 |
{
|
|
569 |
serverList_t * sl = (serverList_t *)data; |
|
570 |
sl->imList = g_list_sort(sl->imList, imList_sort); |
|
571 |
resort_menu(root_menuitem); |
|
572 |
return; |
|
573 |
}
|
|
574 |
||
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
575 |
/* The IM entrie's request for attention has changed
|
576 |
so we need to pass that up the stack. */
|
|
577 |
static void |
|
578 |
im_attention_changed (ImMenuItem * imitem, gboolean requestit, gpointer data) |
|
579 |
{
|
|
580 |
serverList_t * sl = (serverList_t *)data; |
|
581 |
||
582 |
if (requestit) { |
|
583 |
sl->attention = TRUE; |
|
584 |
message_service_dbus_set_attention(dbus_interface, TRUE); |
|
585 |
} else { |
|
586 |
server_attention(sl); |
|
587 |
if (!sl->attention) { |
|
588 |
check_attention(); |
|
589 |
}
|
|
590 |
}
|
|
591 |
||
592 |
return; |
|
593 |
}
|
|
594 |
||
595 |
/* Run when a server is removed from the indicator bus. It figures
|
|
596 |
out if we have it somewhere, and if so then we dump it out and
|
|
597 |
clean up all of it's entries. */
|
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
598 |
static void |
599 |
server_removed (IndicateListener * listener, IndicateListenerServer * server, gchar * type, gpointer data) |
|
600 |
{
|
|
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
601 |
/* Look for the server */
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
602 |
g_debug("Removing server: %s", INDICATE_LISTENER_SERVER_DBUS_NAME(server)); |
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
603 |
serverList_t slt = {0}; |
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
604 |
slt.server = server; |
605 |
GList * lookup = g_list_find_custom(serverList, &slt, serverList_equal); |
|
606 |
||
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
607 |
/* If we don't have it, exit */
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
608 |
if (lookup == NULL) { |
609 |
g_debug("\tUnable to find server: %s", INDICATE_LISTENER_SERVER_DBUS_NAME(server)); |
|
610 |
return; |
|
611 |
}
|
|
612 |
||
613 |
serverList_t * sltp = (serverList_t *)lookup->data; |
|
614 |
||
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
615 |
/* Removing indicators from this server */
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
616 |
while (sltp->imList) { |
617 |
imList_t * imitem = (imList_t *)sltp->imList->data; |
|
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
618 |
indicator_removed(listener, server, imitem->indicator, data); |
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
619 |
}
|
620 |
||
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
621 |
/* Remove from the server list */
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
622 |
serverList = g_list_remove(serverList, sltp); |
623 |
||
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
624 |
/* Remove launchers this could be eclipsing */
|
625 |
remove_eclipses(sltp->menuitem); |
|
626 |
||
627 |
/* If there is a menu item, let's get rid of it. */
|
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
628 |
if (sltp->menuitem != NULL) { |
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
629 |
dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(sltp->menuitem), DBUSMENU_MENUITEM_PROP_VISIBLE, "false"); |
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
630 |
dbusmenu_menuitem_child_delete(DBUSMENU_MENUITEM(data), DBUSMENU_MENUITEM(sltp->menuitem)); |
631 |
g_object_unref(G_OBJECT(sltp->menuitem)); |
|
632 |
}
|
|
633 |
||
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
634 |
/* If there is a separator, let's get rid of it. */
|
635 |
if (sltp->separator != NULL) { |
|
636 |
dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(sltp->separator), DBUSMENU_MENUITEM_PROP_VISIBLE, "false"); |
|
637 |
dbusmenu_menuitem_child_delete(DBUSMENU_MENUITEM(data), DBUSMENU_MENUITEM(sltp->separator)); |
|
638 |
g_object_unref(G_OBJECT(sltp->separator)); |
|
639 |
}
|
|
640 |
||
641 |
if (sltp->attention) { |
|
642 |
/* Check to see if this was the server causing the menu item to
|
|
643 |
be lit up. */
|
|
644 |
check_attention(); |
|
645 |
}
|
|
646 |
||
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
647 |
g_free(sltp); |
648 |
||
649 |
check_hidden(); |
|
650 |
||
651 |
return; |
|
652 |
}
|
|
653 |
||
654 |
typedef struct _menushell_location menushell_location_t; |
|
655 |
struct _menushell_location { |
|
656 |
const IndicateListenerServer * server; |
|
657 |
gint position; |
|
658 |
gboolean found; |
|
659 |
};
|
|
660 |
||
661 |
static void |
|
662 |
menushell_foreach_cb (DbusmenuMenuitem * data_mi, gpointer data_ms) { |
|
663 |
menushell_location_t * msl = (menushell_location_t *)data_ms; |
|
664 |
||
665 |
if (msl->found) return; |
|
666 |
||
667 |
msl->position++; |
|
668 |
||
669 |
if (!IS_APP_MENU_ITEM(data_mi)) { |
|
670 |
return; |
|
671 |
}
|
|
672 |
||
673 |
AppMenuItem * appmenu = APP_MENU_ITEM(data_mi); |
|
674 |
if (!g_strcmp0(INDICATE_LISTENER_SERVER_DBUS_NAME((IndicateListenerServer*)msl->server), INDICATE_LISTENER_SERVER_DBUS_NAME(app_menu_item_get_server(appmenu)))) { |
|
675 |
msl->found = TRUE; |
|
676 |
}
|
|
677 |
||
678 |
return; |
|
679 |
}
|
|
680 |
||
681 |
static void |
|
682 |
check_hidden (void) |
|
683 |
{
|
|
684 |
g_debug("Checking Hidden..."); |
|
685 |
gboolean hide = FALSE; |
|
686 |
if (launcherList_count() == 0) { |
|
687 |
g_debug("\tZero Launchers"); |
|
688 |
/* If we don't have visible launchers we need to look more */
|
|
689 |
if (g_list_length(serverList) == 0) { |
|
690 |
g_debug("\tZero Applications"); |
|
691 |
hide = TRUE; |
|
692 |
}
|
|
693 |
}
|
|
694 |
||
695 |
message_service_dbus_set_icon(dbus_interface, hide); |
|
696 |
return; |
|
697 |
}
|
|
698 |
||
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
699 |
/* This function takes care of putting the menu in the right order.
|
700 |
It basically it rebuilds the order by looking through all the
|
|
701 |
applications and launchers and puts them in the right place. The
|
|
702 |
menu functions will handle the cases where they don't move so this
|
|
703 |
is a good way to ensure everything is right. */
|
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
704 |
static void |
705 |
resort_menu (DbusmenuMenuitem * menushell) |
|
706 |
{
|
|
707 |
guint position = 0; |
|
708 |
GList * serverentry; |
|
709 |
GList * launcherentry = launcherList; |
|
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
710 |
DbusmenuMenuitem * last_separator = NULL; |
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
711 |
|
712 |
g_debug("Reordering Menu:"); |
|
713 |
||
714 |
for (serverentry = serverList; serverentry != NULL; serverentry = serverentry->next) { |
|
715 |
serverList_t * si = (serverList_t *)serverentry->data; |
|
716 |
||
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
717 |
/* Looking to see if there are any launchers we need to insert
|
718 |
into the menu structure. We put as many as we need to. */
|
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
719 |
if (launcherentry != NULL) { |
720 |
launcherList_t * li = (launcherList_t *)launcherentry->data; |
|
721 |
while (launcherentry != NULL && g_strcmp0(launcher_menu_item_get_name(li->menuitem), app_menu_item_get_name(si->menuitem)) < 0) { |
|
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
722 |
/* Putting the launcher item in */
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
723 |
g_debug("\tMoving launcher '%s' to position %d", launcher_menu_item_get_name(li->menuitem), position); |
724 |
dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(li->menuitem), position); |
|
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
725 |
position++; |
726 |
||
727 |
/* Putting the launcher separator in */
|
|
728 |
g_debug("\tMoving launcher separator to position %d", position); |
|
729 |
dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(li->separator), position); |
|
730 |
if (!launcher_menu_item_get_eclipsed(li->menuitem)) { |
|
731 |
/* Only clear the visiblity if we're not eclipsed */
|
|
732 |
dbusmenu_menuitem_property_set(li->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, "true"); |
|
733 |
last_separator = li->separator; |
|
734 |
}
|
|
735 |
position++; |
|
736 |
||
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
737 |
launcherentry = launcherentry->next; |
738 |
if (launcherentry != NULL) { |
|
739 |
li = (launcherList_t *)launcherentry->data; |
|
740 |
}
|
|
741 |
}
|
|
742 |
}
|
|
743 |
||
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
744 |
/* Putting the app menu item in */
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
745 |
if (si->menuitem != NULL) { |
746 |
g_debug("\tMoving app %s to position %d", INDICATE_LISTENER_SERVER_DBUS_NAME(si->server), position); |
|
747 |
dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(si->menuitem), position); |
|
748 |
position++; |
|
749 |
}
|
|
750 |
||
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
751 |
/* Putting all the indicators that are related to this application
|
752 |
after it. */
|
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
753 |
GList * imentry; |
754 |
for (imentry = si->imList; imentry != NULL; imentry = imentry->next) { |
|
755 |
imList_t * imi = (imList_t *)imentry->data; |
|
756 |
||
757 |
if (imi->menuitem != NULL) { |
|
758 |
g_debug("\tMoving indicator on %s id %d to position %d", INDICATE_LISTENER_SERVER_DBUS_NAME(imi->server), INDICATE_LISTENER_INDICATOR_ID(imi->indicator), position); |
|
759 |
dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(imi->menuitem), position); |
|
760 |
position++; |
|
761 |
}
|
|
762 |
}
|
|
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
763 |
|
764 |
/* Lastly putting the separator in */
|
|
765 |
if (si->separator != NULL) { |
|
766 |
g_debug("\tMoving app %s separator to position %d", INDICATE_LISTENER_SERVER_DBUS_NAME(si->server), position); |
|
767 |
dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(si->separator), position); |
|
768 |
dbusmenu_menuitem_property_set(si->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, "true"); |
|
769 |
position++; |
|
770 |
last_separator = si->separator; |
|
771 |
}
|
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
772 |
}
|
773 |
||
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
774 |
/* Put any leftover launchers in at the end of the list. */
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
775 |
while (launcherentry != NULL) { |
776 |
launcherList_t * li = (launcherList_t *)launcherentry->data; |
|
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
777 |
|
778 |
/* Putting the launcher in */
|
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
779 |
g_debug("\tMoving launcher '%s' to position %d", launcher_menu_item_get_name(li->menuitem), position); |
780 |
dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(li->menuitem), position); |
|
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
781 |
position++; |
782 |
||
783 |
/* Putting the launcher separator in */
|
|
784 |
g_debug("\tMoving launcher separator to position %d", position); |
|
785 |
dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(li->separator), position); |
|
786 |
if (!launcher_menu_item_get_eclipsed(li->menuitem)) { |
|
787 |
/* Only clear the visiblity if we're not eclipsed */
|
|
788 |
dbusmenu_menuitem_property_set(li->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, "true"); |
|
789 |
last_separator = li->separator; |
|
790 |
}
|
|
791 |
position++; |
|
792 |
||
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
793 |
launcherentry = launcherentry->next; |
794 |
}
|
|
795 |
||
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
796 |
if (last_separator != NULL) { |
797 |
dbusmenu_menuitem_property_set(last_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, "false"); |
|
798 |
} else { |
|
799 |
g_warning("No last separator on resort"); |
|
800 |
}
|
|
801 |
||
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
802 |
return; |
803 |
}
|
|
804 |
||
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
805 |
/* Responding to a new indicator showing up on the bus. We
|
806 |
need to create a menuitem for it and start populating the
|
|
807 |
internal structures to track it. */
|
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
808 |
static void |
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
809 |
indicator_added (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gpointer data) |
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
810 |
{
|
811 |
DbusmenuMenuitem * menushell = DBUSMENU_MENUITEM(data); |
|
812 |
if (menushell == NULL) { |
|
813 |
g_error("Data in callback is not a menushell"); |
|
814 |
return; |
|
815 |
}
|
|
816 |
||
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
817 |
imList_t * listItem = g_new0(imList_t, 1); |
818 |
listItem->server = server; |
|
819 |
listItem->indicator = indicator; |
|
820 |
||
821 |
/* Building the IM Menu Item which is a subclass
|
|
822 |
of DBus Menuitem */
|
|
823 |
ImMenuItem * menuitem = im_menu_item_new(listener, server, indicator); |
|
824 |
g_object_ref(G_OBJECT(menuitem)); |
|
825 |
listItem->menuitem = DBUSMENU_MENUITEM(menuitem); |
|
826 |
||
827 |
/* Looking for a server entry to attach this indicator
|
|
828 |
to. If we can't find one then we have to build one
|
|
829 |
and attach the indicator to it. */
|
|
830 |
serverList_t sl_item_local = {0}; |
|
831 |
serverList_t * sl_item = NULL; |
|
832 |
sl_item_local.server = server; |
|
833 |
GList * serverentry = g_list_find_custom(serverList, &sl_item_local, serverList_equal); |
|
834 |
||
835 |
if (serverentry == NULL) { |
|
836 |
/* This sucks, we got an indicator before the server. I guess
|
|
837 |
that's the joy of being asynchronous */
|
|
838 |
serverList_t * sl_item = g_new0(serverList_t, 1); |
|
839 |
sl_item->server = server; |
|
840 |
sl_item->menuitem = NULL; |
|
841 |
sl_item->imList = NULL; |
|
842 |
sl_item->attention = FALSE; |
|
843 |
sl_item->count = 0; |
|
844 |
sl_item->separator = NULL; |
|
845 |
||
846 |
serverList = g_list_insert_sorted(serverList, sl_item, serverList_sort); |
|
847 |
} else { |
|
848 |
sl_item = (serverList_t *)serverentry->data; |
|
849 |
}
|
|
850 |
||
851 |
/* Added a this entry into the IM list */
|
|
852 |
sl_item->imList = g_list_insert_sorted(sl_item->imList, listItem, imList_sort); |
|
853 |
listItem->timechange_cb = g_signal_connect(G_OBJECT(menuitem), IM_MENU_ITEM_SIGNAL_TIME_CHANGED, G_CALLBACK(im_time_changed), sl_item); |
|
854 |
listItem->attentionchange_cb = g_signal_connect(G_OBJECT(menuitem), IM_MENU_ITEM_SIGNAL_ATTENTION_CHANGED, G_CALLBACK(im_attention_changed), sl_item); |
|
855 |
||
856 |
/* Check the length of the list. If we've got more inidactors
|
|
857 |
than we allow. Well. Someone's gotta pay. Sorry. I didn't
|
|
858 |
want to do this, but you did it to yourself. */
|
|
859 |
if (g_list_length(sl_item->imList) > MAX_NUMBER_OF_INDICATORS) { |
|
860 |
GList * indicatoritem; |
|
861 |
gint count; |
|
862 |
for (indicatoritem = sl_item->imList, count = 0; indicatoritem != NULL; indicatoritem = g_list_next(indicatoritem), count++) { |
|
863 |
imList_t * im = (imList_t *)indicatoritem->data; |
|
864 |
im_menu_item_show(IM_MENU_ITEM(im->menuitem), count < MAX_NUMBER_OF_INDICATORS); |
|
865 |
}
|
|
866 |
}
|
|
867 |
||
868 |
/* Placing the item into the shell. Look to see if
|
|
869 |
we can find our server and slip in there. Otherwise
|
|
870 |
we'll just append. */
|
|
871 |
menushell_location_t msl; |
|
872 |
msl.found = FALSE; |
|
873 |
msl.position = 0; |
|
874 |
msl.server = server; |
|
875 |
||
876 |
dbusmenu_menuitem_foreach(DBUSMENU_MENUITEM(menushell), menushell_foreach_cb, &msl); |
|
877 |
if (msl.found) { |
|
878 |
dbusmenu_menuitem_child_add_position(menushell, DBUSMENU_MENUITEM(menuitem), msl.position); |
|
879 |
} else { |
|
880 |
g_warning("Unable to find server menu item"); |
|
881 |
dbusmenu_menuitem_child_append(menushell, DBUSMENU_MENUITEM(menuitem)); |
|
882 |
}
|
|
883 |
||
884 |
return; |
|
885 |
}
|
|
886 |
||
887 |
/* Process and indicator getting removed from the system. We
|
|
888 |
first need to ensure that it's one of ours and figure out
|
|
889 |
where we put it. When we find all that out we can go through
|
|
890 |
the process of removing the effect it had on the system. */
|
|
891 |
static void |
|
892 |
indicator_removed (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gpointer data) |
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
893 |
{
|
894 |
g_debug("Removing %s %d", INDICATE_LISTENER_SERVER_DBUS_NAME(server), INDICATE_LISTENER_INDICATOR_ID(indicator)); |
|
895 |
||
896 |
gboolean removed = FALSE; |
|
897 |
||
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
898 |
/* Find the server that was related to this item */
|
899 |
serverList_t sl_item_local = {0}; |
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
900 |
serverList_t * sl_item = NULL; |
901 |
sl_item_local.server = server; |
|
902 |
GList * serverentry = g_list_find_custom(serverList, &sl_item_local, serverList_equal); |
|
903 |
if (serverentry == NULL) { |
|
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
904 |
/* We didn't care about that server */
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
905 |
return; |
906 |
}
|
|
907 |
sl_item = (serverList_t *)serverentry->data; |
|
908 |
||
909 |
/* Look in the IM Hash Table */
|
|
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
910 |
imList_t listData = {0}; |
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
911 |
listData.server = server; |
912 |
listData.indicator = indicator; |
|
913 |
||
914 |
GList * listItem = g_list_find_custom(sl_item->imList, &listData, imList_equal); |
|
915 |
DbusmenuMenuitem * menuitem = NULL; |
|
916 |
imList_t * ilt = NULL; |
|
917 |
if (listItem != NULL) { |
|
918 |
ilt = (imList_t *)listItem->data; |
|
919 |
menuitem = ilt->menuitem; |
|
920 |
}
|
|
921 |
||
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
922 |
/* If we found a menu item and an imList_t item then
|
923 |
we can go ahead and remove it. Otherwise we can
|
|
924 |
skip this and exit. */
|
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
925 |
if (!removed && menuitem != NULL) { |
926 |
sl_item->imList = g_list_remove(sl_item->imList, ilt); |
|
927 |
g_signal_handler_disconnect(menuitem, ilt->timechange_cb); |
|
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
928 |
g_signal_handler_disconnect(menuitem, ilt->attentionchange_cb); |
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
929 |
g_free(ilt); |
930 |
||
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
931 |
if (im_menu_item_get_attention(IM_MENU_ITEM(menuitem)) && im_menu_item_shown(IM_MENU_ITEM(menuitem))) { |
932 |
/* If the removed indicator menu item was asking for
|
|
933 |
attention we need to see if this server should still
|
|
934 |
be asking for attention. */
|
|
935 |
server_attention(sl_item); |
|
936 |
/* If the server is no longer asking for attention then
|
|
937 |
we need to check if the whole system should be. */
|
|
938 |
if (!sl_item->attention) { |
|
939 |
check_attention(); |
|
940 |
}
|
|
941 |
}
|
|
942 |
||
943 |
if (im_menu_item_shown(IM_MENU_ITEM(menuitem)) && g_list_length(sl_item->imList) >= MAX_NUMBER_OF_INDICATORS) { |
|
944 |
/* In this case we need to show a different indicator
|
|
945 |
becasue a shown one has left. But we're going to be
|
|
946 |
easy and set all the values. */
|
|
947 |
GList * indicatoritem; |
|
948 |
gint count; |
|
949 |
for (indicatoritem = sl_item->imList, count = 0; indicatoritem != NULL; indicatoritem = g_list_next(indicatoritem), count++) { |
|
950 |
imList_t * im = (imList_t *)indicatoritem->data; |
|
951 |
im_menu_item_show(IM_MENU_ITEM(im->menuitem), count < MAX_NUMBER_OF_INDICATORS); |
|
952 |
}
|
|
953 |
}
|
|
954 |
||
955 |
/* Hide the item immediately, and then remove it
|
|
956 |
which might take a little longer. */
|
|
957 |
dbusmenu_menuitem_property_set(menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE, "false"); |
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
958 |
dbusmenu_menuitem_child_delete(DBUSMENU_MENUITEM(data), menuitem); |
959 |
removed = TRUE; |
|
960 |
}
|
|
961 |
||
962 |
if (!removed) { |
|
963 |
g_warning("We were asked to remove %s %d but we didn't.", INDICATE_LISTENER_SERVER_DBUS_NAME(server), INDICATE_LISTENER_INDICATOR_ID(indicator)); |
|
964 |
}
|
|
965 |
||
966 |
return; |
|
967 |
}
|
|
968 |
||
969 |
static void |
|
970 |
app_dir_changed (GFileMonitor * monitor, GFile * file, GFile * other_file, GFileMonitorEvent event_type, gpointer user_data) |
|
971 |
{
|
|
972 |
gchar * directory = (gchar *)user_data; |
|
973 |
g_debug("Application directory changed: %s", directory); |
|
974 |
||
975 |
switch (event_type) { |
|
976 |
case G_FILE_MONITOR_EVENT_DELETED: { |
|
977 |
gchar * path = g_file_get_path(file); |
|
978 |
g_debug("\tDelete: %s", path); |
|
979 |
g_idle_add(destroy_launcher, path); |
|
980 |
break; |
|
981 |
}
|
|
982 |
case G_FILE_MONITOR_EVENT_CREATED: { |
|
983 |
gchar * path = g_file_get_path(file); |
|
984 |
g_debug("\tCreate: %s", path); |
|
985 |
g_idle_add(build_launcher, path); |
|
986 |
break; |
|
987 |
}
|
|
988 |
default: |
|
989 |
break; |
|
990 |
}
|
|
991 |
||
992 |
return; |
|
993 |
}
|
|
994 |
||
995 |
/* Check to see if a new desktop file causes
|
|
996 |
any of the launchers to be eclipsed by a running
|
|
997 |
process */
|
|
998 |
static void |
|
999 |
check_eclipses (AppMenuItem * ai) |
|
1000 |
{
|
|
1001 |
g_debug("Checking eclipsing"); |
|
1002 |
const gchar * aidesktop = app_menu_item_get_desktop(ai); |
|
1003 |
if (aidesktop == NULL) return; |
|
1004 |
g_debug("\tApp desktop: %s", aidesktop); |
|
1005 |
||
1006 |
GList * llitem; |
|
1007 |
for (llitem = launcherList; llitem != NULL; llitem = llitem->next) { |
|
1008 |
launcherList_t * ll = (launcherList_t *)llitem->data; |
|
1009 |
const gchar * lidesktop = launcher_menu_item_get_desktop(ll->menuitem); |
|
1010 |
g_debug("\tLauncher desktop: %s", lidesktop); |
|
1011 |
||
1012 |
if (!g_strcmp0(aidesktop, lidesktop)) { |
|
1013 |
launcher_menu_item_set_eclipsed(ll->menuitem, TRUE); |
|
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
1014 |
dbusmenu_menuitem_property_set(ll->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, "false"); |
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
1015 |
break; |
1016 |
}
|
|
1017 |
}
|
|
1018 |
||
1019 |
return; |
|
1020 |
}
|
|
1021 |
||
1022 |
/* Remove any eclipses that might have been caused
|
|
1023 |
by this app item that is now retiring */
|
|
1024 |
static void |
|
1025 |
remove_eclipses (AppMenuItem * ai) |
|
1026 |
{
|
|
1027 |
const gchar * aidesktop = app_menu_item_get_desktop(ai); |
|
1028 |
if (aidesktop == NULL) return; |
|
1029 |
||
1030 |
if (blacklist_check(aidesktop)) return; |
|
1031 |
||
1032 |
GList * llitem; |
|
1033 |
for (llitem = launcherList; llitem != NULL; llitem = llitem->next) { |
|
1034 |
launcherList_t * ll = (launcherList_t *)llitem->data; |
|
1035 |
const gchar * lidesktop = launcher_menu_item_get_desktop(ll->menuitem); |
|
1036 |
||
1037 |
if (!g_strcmp0(aidesktop, lidesktop)) { |
|
1038 |
launcher_menu_item_set_eclipsed(ll->menuitem, FALSE); |
|
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
1039 |
dbusmenu_menuitem_property_set(ll->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, "true"); |
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
1040 |
break; |
1041 |
}
|
|
1042 |
}
|
|
1043 |
||
1044 |
return; |
|
1045 |
}
|
|
1046 |
||
1047 |
/* Remove a launcher from the system. We need to figure
|
|
1048 |
out what it's up to! */
|
|
1049 |
static gboolean |
|
1050 |
destroy_launcher (gpointer data) |
|
1051 |
{
|
|
1052 |
gchar * appdirentry = (gchar *)data; |
|
1053 |
||
1054 |
GList * listitem; |
|
1055 |
GList * direntry; |
|
1056 |
launcherList_t * li; |
|
1057 |
gchar * appdir; |
|
1058 |
||
1059 |
for (listitem = launcherList; listitem != NULL; listitem = listitem->next) { |
|
1060 |
li = (launcherList_t *)listitem->data; |
|
1061 |
for (direntry = li->appdiritems; direntry != NULL; direntry = direntry->next) { |
|
1062 |
appdir = (gchar *)direntry->data; |
|
1063 |
if (!g_strcmp0(appdir, appdirentry)) { |
|
1064 |
break; |
|
1065 |
}
|
|
1066 |
}
|
|
1067 |
||
1068 |
if (direntry != NULL) { |
|
1069 |
break; |
|
1070 |
}
|
|
1071 |
}
|
|
1072 |
||
1073 |
if (listitem == NULL) { |
|
1074 |
g_warning("Removed '%s' by the way of it not seeming to exist anywhere.", appdirentry); |
|
1075 |
return FALSE; |
|
1076 |
}
|
|
1077 |
||
1078 |
if (g_list_length(li->appdiritems) > 1) { |
|
1079 |
/* Just remove this item, and we can move on */
|
|
1080 |
g_debug("Just removing file entry: %s", appdir); |
|
1081 |
li->appdiritems = g_list_remove(li->appdiritems, appdir); |
|
1082 |
g_free(appdir); |
|
1083 |
return FALSE; |
|
1084 |
}
|
|
1085 |
||
1086 |
/* Full Destroy */
|
|
1087 |
g_free(appdir); |
|
1088 |
g_list_free(li->appdiritems); |
|
1089 |
||
1090 |
if (li->menuitem != NULL) { |
|
1091 |
dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(li->menuitem), DBUSMENU_MENUITEM_PROP_VISIBLE, "false"); |
|
1092 |
dbusmenu_menuitem_child_delete(root_menuitem, DBUSMENU_MENUITEM(li->menuitem)); |
|
1093 |
g_object_unref(G_OBJECT(li->menuitem)); |
|
1094 |
li->menuitem = NULL; |
|
1095 |
}
|
|
1096 |
||
1097 |
launcherList = g_list_remove(launcherList, li); |
|
1098 |
g_free(li); |
|
1099 |
||
1100 |
return FALSE; |
|
1101 |
}
|
|
1102 |
||
1103 |
/* This function turns a specific file into a menu
|
|
1104 |
item and registers it appropriately with everyone */
|
|
1105 |
static gboolean |
|
1106 |
build_launcher (gpointer data) |
|
1107 |
{
|
|
1108 |
/* Read the file get the data */
|
|
1109 |
gchar * path = (gchar *)data; |
|
1110 |
g_debug("\tpath: %s", path); |
|
1111 |
gchar * desktop = NULL; |
|
1112 |
||
1113 |
g_file_get_contents(path, &desktop, NULL, NULL); |
|
1114 |
||
1115 |
if (desktop == NULL) { |
|
1116 |
return FALSE; |
|
1117 |
}
|
|
1118 |
||
1119 |
gchar * trimdesktop = pango_trim_string(desktop); |
|
1120 |
g_free(desktop); |
|
1121 |
g_debug("\tcontents: %s", trimdesktop); |
|
1122 |
||
1123 |
/* Check to see if we already have a launcher */
|
|
1124 |
GList * listitem; |
|
1125 |
for (listitem = launcherList; listitem != NULL; listitem = listitem->next) { |
|
1126 |
launcherList_t * li = (launcherList_t *)listitem->data; |
|
1127 |
if (!g_strcmp0(launcher_menu_item_get_desktop(li->menuitem), trimdesktop)) { |
|
1128 |
break; |
|
1129 |
}
|
|
1130 |
}
|
|
1131 |
||
1132 |
if (listitem == NULL) { |
|
1133 |
/* If not */
|
|
1134 |
/* Build the item */
|
|
1135 |
launcherList_t * ll = g_new0(launcherList_t, 1); |
|
1136 |
ll->menuitem = launcher_menu_item_new(trimdesktop); |
|
1137 |
g_free(trimdesktop); |
|
1138 |
ll->appdiritems = g_list_append(NULL, path); |
|
1139 |
||
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
1140 |
/* Build a separator */
|
1141 |
ll->separator = dbusmenu_menuitem_new(); |
|
1142 |
dbusmenu_menuitem_property_set(ll->separator, "type", DBUSMENU_CLIENT_TYPES_SEPARATOR); |
|
1143 |
||
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
1144 |
/* Add it to the list */
|
1145 |
launcherList = g_list_insert_sorted(launcherList, ll, launcherList_sort); |
|
1146 |
||
1147 |
/* Add it to the menu */
|
|
1148 |
dbusmenu_menuitem_child_append(root_menuitem, DBUSMENU_MENUITEM(ll->menuitem)); |
|
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
1149 |
dbusmenu_menuitem_child_append(root_menuitem, DBUSMENU_MENUITEM(ll->separator)); |
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
1150 |
|
1.1.7
by Ted Gould
Import upstream version 0.2.4 |
1151 |
/* If we're in the black list or we've gotten eclipsed
|
1152 |
by something else, hide the item and the separator. */
|
|
1153 |
if (blacklist_check(launcher_menu_item_get_desktop(ll->menuitem)) || |
|
1154 |
launcher_menu_item_get_eclipsed(ll->menuitem)) { |
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
1155 |
launcher_menu_item_set_eclipsed(ll->menuitem, TRUE); |
1.1.6
by Ted Gould
Import upstream version 0.2.2 |
1156 |
dbusmenu_menuitem_property_set(ll->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, "false"); |
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
1157 |
}
|
1.1.8
by Ted Gould
Import upstream version 0.2.5 |
1158 |
|
1.1.9
by Ted Gould
Import upstream version 0.2.6 |
1159 |
resort_menu(root_menuitem); |
1.1.8
by Ted Gould
Import upstream version 0.2.5 |
1160 |
check_hidden(); |
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
1161 |
} else { |
1162 |
/* If so add ourselves */
|
|
1163 |
launcherList_t * ll = (launcherList_t *)listitem->data; |
|
1164 |
ll->appdiritems = g_list_append(ll->appdiritems, path); |
|
1165 |
}
|
|
1166 |
||
1167 |
return FALSE; |
|
1168 |
}
|
|
1169 |
||
1170 |
/* This function goes through all the launchers that we're
|
|
1171 |
supposed to be grabbing and decides to show turn them
|
|
1172 |
into menu items or not. It doens't do the work, but it
|
|
1173 |
makes the decision. */
|
|
1174 |
static gboolean |
|
1175 |
build_launchers (gpointer data) |
|
1176 |
{
|
|
1177 |
gchar * directory = (gchar *)data; |
|
1178 |
||
1179 |
if (!g_file_test(directory, G_FILE_TEST_IS_DIR)) { |
|
1180 |
return FALSE; |
|
1181 |
}
|
|
1182 |
||
1183 |
GFile * filedir = g_file_new_for_path(directory); |
|
1184 |
GFileMonitor * dirmon = g_file_monitor_directory(filedir, G_FILE_MONITOR_NONE, NULL, NULL); |
|
1185 |
if (dirmon != NULL) { |
|
1186 |
g_signal_connect(G_OBJECT(dirmon), "changed", G_CALLBACK(app_dir_changed), directory); |
|
1187 |
}
|
|
1188 |
||
1189 |
GError * error = NULL; |
|
1190 |
GDir * dir = g_dir_open(directory, 0, &error); |
|
1191 |
if (dir == NULL) { |
|
1192 |
g_warning("Unable to open system apps directory: %s", error->message); |
|
1193 |
g_error_free(error); |
|
1194 |
return FALSE; |
|
1195 |
}
|
|
1196 |
||
1197 |
const gchar * filename = NULL; |
|
1198 |
while ((filename = g_dir_read_name(dir)) != NULL) { |
|
1199 |
g_debug("Found file: %s", filename); |
|
1200 |
gchar * path = g_build_filename(directory, filename, NULL); |
|
1201 |
g_idle_add(build_launcher, path); |
|
1202 |
}
|
|
1203 |
||
1204 |
g_dir_close(dir); |
|
1205 |
launcherList = g_list_sort(launcherList, launcherList_sort); |
|
1206 |
return FALSE; |
|
1207 |
}
|
|
1208 |
||
1209 |
/* Oh, if you don't know what main() is for
|
|
1210 |
we really shouldn't be talking. */
|
|
1211 |
int
|
|
1212 |
main (int argc, char ** argv) |
|
1213 |
{
|
|
1214 |
g_type_init(); |
|
1215 |
||
1216 |
DBusGConnection * connection = dbus_g_bus_get(DBUS_BUS_SESSION, NULL); |
|
1217 |
DBusGProxy * bus_proxy = dbus_g_proxy_new_for_name(connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS); |
|
1218 |
GError * error = NULL; |
|
1219 |
guint nameret = 0; |
|
1220 |
||
1221 |
if (!org_freedesktop_DBus_request_name(bus_proxy, INDICATOR_MESSAGES_DBUS_NAME, 0, &nameret, &error)) { |
|
1222 |
g_error("Unable to call to request name"); |
|
1223 |
return 1; |
|
1224 |
}
|
|
1225 |
||
1226 |
if (nameret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { |
|
1227 |
g_error("Unable to get name"); |
|
1228 |
return 1; |
|
1229 |
}
|
|
1230 |
||
1.1.7
by Ted Gould
Import upstream version 0.2.4 |
1231 |
/* Setting up i18n and gettext. Apparently, we need
|
1232 |
all of these. */
|
|
1233 |
setlocale (LC_ALL, ""); |
|
1234 |
bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR); |
|
1235 |
textdomain (GETTEXT_PACKAGE); |
|
14
by Sebastien Bacher
src/messages-service.c: initialise the translations |
1236 |
|
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
1237 |
dbus_interface = message_service_dbus_new(); |
1238 |
||
1239 |
listener = indicate_listener_ref_default(); |
|
1240 |
serverList = NULL; |
|
1241 |
||
1242 |
root_menuitem = dbusmenu_menuitem_new(); |
|
1243 |
DbusmenuServer * server = dbusmenu_server_new(INDICATOR_MESSAGES_DBUS_OBJECT); |
|
1244 |
dbusmenu_server_set_root(server, root_menuitem); |
|
1245 |
||
1246 |
g_signal_connect(listener, INDICATE_LISTENER_SIGNAL_INDICATOR_ADDED, G_CALLBACK(indicator_added), root_menuitem); |
|
1247 |
g_signal_connect(listener, INDICATE_LISTENER_SIGNAL_INDICATOR_REMOVED, G_CALLBACK(indicator_removed), root_menuitem); |
|
1248 |
g_signal_connect(listener, INDICATE_LISTENER_SIGNAL_SERVER_ADDED, G_CALLBACK(server_added), root_menuitem); |
|
1249 |
g_signal_connect(listener, INDICATE_LISTENER_SIGNAL_SERVER_REMOVED, G_CALLBACK(server_removed), root_menuitem); |
|
1250 |
||
1251 |
g_idle_add(blacklist_init, NULL); |
|
1252 |
g_idle_add(build_launchers, SYSTEM_APPS_DIR); |
|
1.1.7
by Ted Gould
Import upstream version 0.2.4 |
1253 |
g_idle_add(build_launchers, SYSTEM_APPS_DIR_OLD); |
1.1.5
by Ted Gould
Import upstream version 0.2.0 |
1254 |
gchar * userdir = g_build_filename(g_get_user_config_dir(), USER_APPS_DIR, NULL); |
1255 |
g_idle_add(build_launchers, userdir); |
|
1256 |
||
1257 |
mainloop = g_main_loop_new(NULL, FALSE); |
|
1258 |
g_main_loop_run(mainloop); |
|
1259 |
||
1260 |
g_free(userdir); |
|
1261 |
||
1262 |
return 0; |
|
1263 |
}
|