Correct background for 'indicator' plugin - it should use panel settings.
[lxde/lxpanel.git] / plugins / indicator / indicator.c
CommitLineData
9dda8252
JL
1/*
2Copyright 2010 Julien Lavergne <gilir@ubuntu.com>
3
4Based on indicator-applet :
5Copyright 2009 Canonical Ltd.
6
7Authors:
8 Ted Gould <ted@canonical.com>
9
10This library is free software; you can redistribute it and/or
11modify it under the terms of the GNU General Public License
12version 3.0 as published by the Free Software Foundation.
13
14This library is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17GNU General Public License version 3.0 for more details.
18
19You should have received a copy of the GNU General Public
20License along with this library. If not, see
21<http://www.gnu.org/licenses/>.
22
9dda8252
JL
23TODO Check also http://bazaar.launchpad.net/~unity-team/unity/trunk/view/head:/services/panel-service.c
24
25TODO ? : add hotkey support (r348 + r352)
26
27TODO : vertical support (r354)
28
29*/
30
969a40cf 31#include "plugin.h"
9dda8252
JL
32
33#include <stdlib.h>
34#include <glib/gi18n.h>
35
36#include <gtk/gtk.h>
37#include <libindicator/indicator-object.h>
38
e41dd2dd
JL
39static gchar * indicator_order[][2] = {
40 {"libappmenu.so", NULL},
41 {"libapplication.so", NULL},
42 {"libapplication.so", "gst-keyboard-xkb"},
43 {"libmessaging.so", NULL},
44 {"libpower.so", NULL},
45 {"libapplication.so", "bluetooth-manager"},
46 {"libnetwork.so", NULL},
47 {"libnetworkmenu.so", NULL},
48 {"libapplication.so", "nm-applet"},
49 {"libsoundmenu.so", NULL},
50 {"libdatetime.so", NULL},
51 {"libsession.so", NULL},
52 {NULL, NULL}
9dda8252 53};
e41dd2dd
JL
54
55#define MENU_DATA_BOX "box"
9dda8252
JL
56#define MENU_DATA_INDICATOR_OBJECT "indicator-object"
57#define MENU_DATA_INDICATOR_ENTRY "indicator-entry"
e41dd2dd
JL
58#define MENU_DATA_IN_MENUITEM "in-menuitem"
59#define MENU_DATA_MENUITEM_PRESSED "menuitem-pressed"
60
61#define IO_DATA_NAME "indicator-name"
9dda8252
JL
62#define IO_DATA_ORDER_NUMBER "indicator-order-number"
63
64#define LOG_FILE_NAME "lxpanel-indicator-plugin.log"
65
66GOutputStream * log_file = NULL;
67
68typedef struct {
a7bd16a4 69 LXPanel *panel;
8cfb4645 70 config_setting_t *settings;
9dda8252
JL
71
72 IndicatorObject *io; /* Indicators applets */
73
74 GList *images; /* List of images of applets */
75 GList *menus; /* List of menus of applets */
76
77 GtkWidget * menubar; /* Displayed menubar */
8cfb4645 78
9dda8252 79 gboolean applications; /* Support for differents indicators */
9dda8252
JL
80 gboolean datetime;
81 gboolean me;
82 gboolean messages;
83 gboolean network;
84 gboolean session;
85 gboolean sound;
e41dd2dd 86 /* gboolean appmenu; */
9dda8252
JL
87
88
89} IndicatorPlugin;
90
e41dd2dd
JL
91static const gchar * indicator_env[] = {
92 "indicator-applet",
93 NULL
94};
95
9dda8252 96static gint
e41dd2dd
JL
97name2order (const gchar * name, const gchar * hint) {
98 int i;
9dda8252 99
e41dd2dd
JL
100 for (i = 0; indicator_order[i][0] != NULL; i++) {
101 if (g_strcmp0(name, indicator_order[i][0]) == 0 &&
102 g_strcmp0(hint, indicator_order[i][1]) == 0) {
103 return i;
104 }
105 }
9dda8252 106
e41dd2dd 107 return -1;
9dda8252 108}
8cfb4645 109
9dda8252
JL
110typedef struct _incoming_position_t incoming_position_t;
111struct _incoming_position_t {
112 gint objposition;
113 gint entryposition;
114 gint menupos;
115 gboolean found;
116};
e41dd2dd 117
9dda8252
JL
118/* This function helps by determining where in the menu list
119 this new entry should be placed. It compares the objects
120 that they're on, and then the individual entries. Each
121 is progressively more expensive. */
122static void
e41dd2dd 123place_in_menu_cb (GtkWidget * widget, gpointer user_data)
9dda8252 124{
e41dd2dd
JL
125 incoming_position_t * position = (incoming_position_t *)user_data;
126 if (position->found) {
127 /* We've already been placed, just finish the foreach */
128 return;
129 }
130
131 IndicatorObject * io = INDICATOR_OBJECT(g_object_get_data(G_OBJECT(widget), MENU_DATA_INDICATOR_OBJECT));
132 g_return_if_fail(INDICATOR_IS_OBJECT(io));
133
134 gint objposition = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(io), IO_DATA_ORDER_NUMBER));
135 /* We've already passed it, well, then this is where
136 we should be be. Stop! */
137 if (objposition > position->objposition) {
138 position->found = TRUE;
139 return;
140 }
141
142 /* The objects don't match yet, keep looking */
143 if (objposition < position->objposition) {
144 position->menupos++;
145 return;
146 }
147
148 /* The objects are the same, let's start looking at entries. */
149 IndicatorObjectEntry * entry = (IndicatorObjectEntry *)g_object_get_data(G_OBJECT(widget), MENU_DATA_INDICATOR_ENTRY);
150 gint entryposition = indicator_object_get_location(io, entry);
151
152 if (entryposition > position->entryposition) {
153 position->found = TRUE;
154 return;
155 }
156
157 if (entryposition < position->entryposition) {
158 position->menupos++;
159 return;
160 }
161
162 /* We've got the same object and the same entry. Well,
163 let's just put it right here then. */
164 position->found = TRUE;
165 return;
166}
167
168/* Position the entry */
169static void
0bcf9045
AG
170place_in_menu (GtkWidget *menubar,
171 GtkWidget *menuitem,
172 IndicatorObject *io,
e41dd2dd
JL
173 IndicatorObjectEntry *entry)
174{
175 incoming_position_t position;
176
177 /* Start with the default position for this indicator object */
178 gint io_position = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(io), IO_DATA_ORDER_NUMBER));
179
180 /* If name-hint is set, try to find the entry's position */
181 if (entry->name_hint != NULL) {
182 const gchar *name = (const gchar *)g_object_get_data(G_OBJECT(io), IO_DATA_NAME);
183 gint entry_position = name2order(name, entry->name_hint);
184
185 /* If we don't find the entry, fall back to the indicator object's position */
186 if (entry_position > -1)
187 io_position = entry_position;
188 }
189
190 position.objposition = io_position;
191 position.entryposition = indicator_object_get_location(io, entry);
192 position.menupos = 0;
193 position.found = FALSE;
194
195 gtk_container_foreach(GTK_CONTAINER(menubar), place_in_menu_cb, &position);
196
197 gtk_menu_shell_insert(GTK_MENU_SHELL(menubar), menuitem, position.menupos);
9dda8252
JL
198}
199
200static void
201something_shown (GtkWidget * widget, gpointer user_data)
202{
203 GtkWidget * menuitem = GTK_WIDGET(user_data);
204 gtk_widget_show(menuitem);
205}
206
207static void
208something_hidden (GtkWidget * widget, gpointer user_data)
209{
210 GtkWidget * menuitem = GTK_WIDGET(user_data);
211 gtk_widget_hide(menuitem);
212}
213
214static void
215sensitive_cb (GObject * obj, GParamSpec * pspec, gpointer user_data)
216{
217 g_return_if_fail(GTK_IS_WIDGET(obj));
218 g_return_if_fail(GTK_IS_WIDGET(user_data));
219
220 gtk_widget_set_sensitive(GTK_WIDGET(user_data), gtk_widget_get_sensitive(GTK_WIDGET(obj)));
221 return;
222}
223
224static void
e41dd2dd
JL
225entry_activated (GtkWidget * widget, gpointer user_data)
226{
227 g_return_if_fail(GTK_IS_WIDGET(widget));
228
229 IndicatorObject *io = g_object_get_data (G_OBJECT (widget), MENU_DATA_INDICATOR_OBJECT);
230 IndicatorObjectEntry *entry = g_object_get_data (G_OBJECT (widget), MENU_DATA_INDICATOR_ENTRY);
231
232 g_return_if_fail(INDICATOR_IS_OBJECT(io));
233
234 return indicator_object_entry_activate(io, entry, gtk_get_current_event_time());
235}
236
237static gboolean
238entry_secondary_activated (GtkWidget * widget, GdkEvent * event, gpointer user_data)
239{
240 g_return_val_if_fail(GTK_IS_WIDGET(widget), FALSE);
241
242 switch (event->type) {
243 case GDK_ENTER_NOTIFY:
244 g_object_set_data(G_OBJECT(widget), MENU_DATA_IN_MENUITEM, GINT_TO_POINTER(TRUE));
245 break;
246
247 case GDK_LEAVE_NOTIFY:
248 g_object_set_data(G_OBJECT(widget), MENU_DATA_IN_MENUITEM, GINT_TO_POINTER(FALSE));
249 g_object_set_data(G_OBJECT(widget), MENU_DATA_MENUITEM_PRESSED, GINT_TO_POINTER(FALSE));
250 break;
251
252 case GDK_BUTTON_PRESS:
253 if (event->button.button == 2) {
254 g_object_set_data(G_OBJECT(widget), MENU_DATA_MENUITEM_PRESSED, GINT_TO_POINTER(TRUE));
255 }
256 break;
257
258 case GDK_BUTTON_RELEASE:
259 if (event->button.button == 2) {
260 gboolean in_menuitem = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), MENU_DATA_IN_MENUITEM));
261 gboolean menuitem_pressed = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), MENU_DATA_MENUITEM_PRESSED));
262
263 if (in_menuitem && menuitem_pressed) {
264 g_object_set_data(G_OBJECT(widget), MENU_DATA_MENUITEM_PRESSED, GINT_TO_POINTER(FALSE));
265
266 IndicatorObject *io = g_object_get_data(G_OBJECT(widget), MENU_DATA_INDICATOR_OBJECT);
267 IndicatorObjectEntry *entry = g_object_get_data(G_OBJECT(widget), MENU_DATA_INDICATOR_ENTRY);
268
269 g_return_val_if_fail(INDICATOR_IS_OBJECT(io), FALSE);
270
0bcf9045 271 g_signal_emit_by_name(io, INDICATOR_OBJECT_SIGNAL_SECONDARY_ACTIVATE,
e41dd2dd
JL
272 entry, event->button.time);
273 }
274 }
275 break;
8cfb4645 276 default: ;
e41dd2dd
JL
277 }
278
279 return FALSE;
280}
281
282static gboolean
283entry_scrolled (GtkWidget *menuitem, GdkEventScroll *event, gpointer data)
284{
285 g_return_val_if_fail(GTK_IS_WIDGET(menuitem), FALSE);
286
287 IndicatorObject *io = g_object_get_data (G_OBJECT (menuitem), MENU_DATA_INDICATOR_OBJECT);
288 IndicatorObjectEntry *entry = g_object_get_data (G_OBJECT (menuitem), MENU_DATA_INDICATOR_ENTRY);
289
290 g_return_val_if_fail(INDICATOR_IS_OBJECT(io), FALSE);
291
292 g_signal_emit_by_name (io, INDICATOR_OBJECT_SIGNAL_ENTRY_SCROLLED, entry, 1, event->direction);
293
294 return FALSE;
295}
296
297static void
298entry_added (IndicatorObject * io, IndicatorObjectEntry * entry, GtkWidget * menubar)
9dda8252 299{
e41dd2dd
JL
300 const char *indicator_name = (const gchar *)g_object_get_data(G_OBJECT(io), IO_DATA_NAME);
301 g_debug("Signal: Entry Added from %s", indicator_name);
9dda8252
JL
302 gboolean something_visible = FALSE;
303 gboolean something_sensitive = FALSE;
304
305 GtkWidget * menuitem = gtk_menu_item_new();
306 GtkWidget * hbox = gtk_hbox_new(FALSE, 3);
8cfb4645 307
e41dd2dd
JL
308 g_object_set_data (G_OBJECT (menuitem), MENU_DATA_BOX, hbox);
309 g_object_set_data(G_OBJECT(menuitem), MENU_DATA_INDICATOR_OBJECT, io);
310 g_object_set_data(G_OBJECT(menuitem), MENU_DATA_INDICATOR_ENTRY, entry);
311
312 g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(entry_activated), NULL);
313 g_signal_connect(G_OBJECT(menuitem), "button-press-event", G_CALLBACK(entry_secondary_activated), NULL);
314 g_signal_connect(G_OBJECT(menuitem), "button-release-event", G_CALLBACK(entry_secondary_activated), NULL);
315 g_signal_connect(G_OBJECT(menuitem), "enter-notify-event", G_CALLBACK(entry_secondary_activated), NULL);
316 g_signal_connect(G_OBJECT(menuitem), "leave-notify-event", G_CALLBACK(entry_secondary_activated), NULL);
317 g_signal_connect(G_OBJECT(menuitem), "scroll-event", G_CALLBACK(entry_scrolled), NULL);
9dda8252
JL
318
319 if (entry->image != NULL)
320 {
321 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(entry->image), FALSE, FALSE, 1);
322 if (gtk_widget_get_visible(GTK_WIDGET(entry->image))) {
323 something_visible = TRUE;
324 }
8cfb4645 325
9dda8252
JL
326 if (gtk_widget_get_sensitive(GTK_WIDGET(entry->image))) {
327 something_sensitive = TRUE;
328 }
8cfb4645 329
9dda8252
JL
330 g_signal_connect(G_OBJECT(entry->image), "show", G_CALLBACK(something_shown), menuitem);
331 g_signal_connect(G_OBJECT(entry->image), "hide", G_CALLBACK(something_hidden), menuitem);
332 g_signal_connect(G_OBJECT(entry->image), "notify::sensitive", G_CALLBACK(sensitive_cb), menuitem);
9dda8252
JL
333 }
334 if (entry->label != NULL)
335 {
336 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(entry->label), FALSE, FALSE, 1);
337
338 if (gtk_widget_get_visible(GTK_WIDGET(entry->label))) {
339 something_visible = TRUE;
340 }
341
342 if (gtk_widget_get_sensitive(GTK_WIDGET(entry->label))) {
343
344 something_sensitive = TRUE;
345 }
346
347 g_signal_connect(G_OBJECT(entry->label), "show", G_CALLBACK(something_shown), menuitem);
348 g_signal_connect(G_OBJECT(entry->label), "hide", G_CALLBACK(something_hidden), menuitem);
349 g_signal_connect(G_OBJECT(entry->label), "notify::sensitive", G_CALLBACK(sensitive_cb), menuitem);
350
351 }
352 gtk_container_add(GTK_CONTAINER(menuitem), hbox);
353 gtk_widget_show(hbox);
354
355 if (entry->menu != NULL)
356 {
357 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), GTK_WIDGET(entry->menu));
358 }
359
e41dd2dd 360 place_in_menu(menubar, menuitem, io, entry);
9dda8252 361
9dda8252
JL
362 if (something_visible) {
363 gtk_widget_show(menuitem);
364 }
365 gtk_widget_set_sensitive(menuitem, something_sensitive);
366
9dda8252
JL
367 return;
368}
369
370static void
371entry_removed_cb (GtkWidget * widget, gpointer userdata)
372{
373 gpointer data = g_object_get_data(G_OBJECT(widget), MENU_DATA_INDICATOR_ENTRY);
374
375 if (data != userdata)
376 {
377 return;
378 }
379
380 IndicatorObjectEntry * entry = (IndicatorObjectEntry *)data;
381 if (entry->label != NULL) {
382 g_signal_handlers_disconnect_by_func(G_OBJECT(entry->label), G_CALLBACK(something_shown), widget);
383 g_signal_handlers_disconnect_by_func(G_OBJECT(entry->label), G_CALLBACK(something_hidden), widget);
384 g_signal_handlers_disconnect_by_func(G_OBJECT(entry->label), G_CALLBACK(sensitive_cb), widget);
385 }
386 if (entry->image != NULL) {
387 g_signal_handlers_disconnect_by_func(G_OBJECT(entry->image), G_CALLBACK(something_shown), widget);
388 g_signal_handlers_disconnect_by_func(G_OBJECT(entry->image), G_CALLBACK(something_hidden), widget);
389 g_signal_handlers_disconnect_by_func(G_OBJECT(entry->image), G_CALLBACK(sensitive_cb), widget);
390 }
391
392 gtk_widget_destroy(widget);
393 return;
394}
395
396static void
397entry_moved_find_cb (GtkWidget * widget, gpointer userdata)
398{
399 gpointer * array = (gpointer *)userdata;
400 if (array[1] != NULL) {
401 return;
402 }
403
404 gpointer data = g_object_get_data(G_OBJECT(widget), MENU_DATA_INDICATOR_ENTRY);
405
406 if (data != array[0]) {
407 return;
408 }
8cfb4645 409
9dda8252
JL
410 array[1] = widget;
411 return;
412}
8cfb4645 413
9dda8252 414/* Gets called when an entry for an object was moved. */
0bcf9045 415static void
9dda8252
JL
416entry_moved (IndicatorObject * io, IndicatorObjectEntry * entry,
417 gint old G_GNUC_UNUSED, gint new G_GNUC_UNUSED, gpointer user_data)
418{
e41dd2dd 419 GtkWidget * menubar = GTK_WIDGET(user_data);
9dda8252
JL
420
421 gpointer array[2];
422 array[0] = entry;
423 array[1] = NULL;
424
e41dd2dd 425 gtk_container_foreach(GTK_CONTAINER(menubar), entry_moved_find_cb, array);
9dda8252
JL
426 if (array[1] == NULL) {
427 g_warning("Moving an entry that isn't in our menus.");
428 return;
429 }
430
431 GtkWidget * mi = GTK_WIDGET(array[1]);
432 g_object_ref(G_OBJECT(mi));
e41dd2dd
JL
433 gtk_container_remove(GTK_CONTAINER(menubar), mi);
434 place_in_menu(menubar, mi, io, entry);
9dda8252 435 g_object_unref(G_OBJECT(mi));
8cfb4645 436
9dda8252
JL
437 return;
438}
439
440static void
441entry_removed (IndicatorObject * io G_GNUC_UNUSED, IndicatorObjectEntry * entry,
442 gpointer user_data)
443{
444 g_debug("Signal: Entry Removed");
445
446 gtk_container_foreach(GTK_CONTAINER(user_data), entry_removed_cb, entry);
447
448 return;
449}
450
e41dd2dd
JL
451static void
452menu_show (IndicatorObject * io, IndicatorObjectEntry * entry,
453 guint32 timestamp, gpointer user_data)
454{
455 GtkWidget * menubar = GTK_WIDGET(user_data);
456
457 if (entry == NULL) {
458 /* Close any open menus instead of opening one */
459 GList * entries = indicator_object_get_entries(io);
460 GList * entry = NULL;
461 for (entry = entries; entry != NULL; entry = g_list_next(entry)) {
462 IndicatorObjectEntry * entrydata = (IndicatorObjectEntry *)entry->data;
463 gtk_menu_popdown(entrydata->menu);
464 }
465 g_list_free(entries);
466
467 /* And tell the menubar to exit activation mode too */
468 gtk_menu_shell_cancel(GTK_MENU_SHELL(menubar));
469 return;
470 }
471
472 // TODO: do something sensible here
473}
474
9dda8252 475static gboolean
e41dd2dd 476load_module (const gchar * name, GtkWidget * menubar)
9dda8252
JL
477{
478 g_debug("Looking at Module: %s", name);
479 g_return_val_if_fail(name != NULL, FALSE);
480
481 if (!g_str_has_suffix(name, G_MODULE_SUFFIX))
482 {
483 return FALSE;
484 }
485
486 g_debug("Loading Module: %s", name);
487
488 /* Build the object for the module */
9dda8252 489 gchar *fullpath = g_build_filename(INDICATOR_DIR, name, NULL);
9dda8252 490 g_debug("Full path: %s", fullpath);
9dda8252
JL
491 IndicatorObject * io = indicator_object_new_from_file(fullpath);
492 g_free(fullpath);
e41dd2dd
JL
493
494 /* Set the environment it's in */
495 indicator_object_set_environment(io, (const GStrv)indicator_env);
8cfb4645 496
9dda8252 497 /* Attach the 'name' to the object */
e41dd2dd
JL
498 g_object_set_data_full(G_OBJECT(io), IO_DATA_NAME, g_strdup(name), g_free);
499 g_object_set_data(G_OBJECT(io), IO_DATA_ORDER_NUMBER, GINT_TO_POINTER(name2order(name, NULL)));
9dda8252
JL
500
501 /* Connect to it's signals */
e41dd2dd
JL
502 g_signal_connect(G_OBJECT(io), INDICATOR_OBJECT_SIGNAL_ENTRY_ADDED, G_CALLBACK(entry_added), menubar);
503 g_signal_connect(G_OBJECT(io), INDICATOR_OBJECT_SIGNAL_ENTRY_REMOVED, G_CALLBACK(entry_removed), menubar);
504 g_signal_connect(G_OBJECT(io), INDICATOR_OBJECT_SIGNAL_ENTRY_MOVED, G_CALLBACK(entry_moved), menubar);
505 g_signal_connect(G_OBJECT(io), INDICATOR_OBJECT_SIGNAL_MENU_SHOW, G_CALLBACK(menu_show), menubar);
9dda8252
JL
506
507 /* Work on the entries */
508 GList * entries = indicator_object_get_entries(io);
509 GList * entry = NULL;
510
511 for (entry = entries; entry != NULL; entry = g_list_next(entry))
512 {
513 IndicatorObjectEntry * entrydata = (IndicatorObjectEntry *)entry->data;
e41dd2dd 514 entry_added(io, entrydata, menubar);
9dda8252
JL
515 }
516
517 g_list_free(entries);
518
519 return TRUE;
520}
521
26ddbcdf 522#if 0
9dda8252
JL
523static void
524log_to_file_cb (GObject * source_obj G_GNUC_UNUSED,
525 GAsyncResult * result G_GNUC_UNUSED, gpointer user_data)
526{
527 g_free(user_data);
528 return;
529}
8cfb4645 530
9dda8252
JL
531static void
532log_to_file (const gchar * domain G_GNUC_UNUSED,
533 GLogLevelFlags level G_GNUC_UNUSED,
534 const gchar * message,
535 gpointer data G_GNUC_UNUSED)
536{
537 if (log_file == NULL) {
538 GError * error = NULL;
539 gchar * filename = g_build_filename(g_get_user_cache_dir(), LOG_FILE_NAME, NULL);
540 GFile * file = g_file_new_for_path(filename);
541 g_free(filename);
542
543 if (!g_file_test(g_get_user_cache_dir(), G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
544 GFile * cachedir = g_file_new_for_path(g_get_user_cache_dir());
545 g_file_make_directory_with_parents(cachedir, NULL, &error);
8cfb4645 546
9dda8252
JL
547 if (error != NULL) {
548 g_error("Unable to make directory '%s' for log file: %s", g_get_user_cache_dir(), error->message);
549 return;
550 }
551 }
8cfb4645 552
9dda8252 553 g_file_delete(file, NULL, NULL);
8cfb4645 554
9dda8252
JL
555 GFileIOStream * io = g_file_create_readwrite(file,
556 G_FILE_CREATE_REPLACE_DESTINATION, /* flags */
557 NULL, /* cancelable */
558 &error); /* error */
559 if (error != NULL) {
560 g_error("Unable to replace file: %s", error->message);
561 return;
562 }
563
564 log_file = g_io_stream_get_output_stream(G_IO_STREAM(io));
565 }
8cfb4645 566
9dda8252
JL
567 gchar * outputstring = g_strdup_printf("%s\n", message);
568 g_output_stream_write_async(log_file,
569 outputstring, /* data */
570 strlen(outputstring), /* length */
571 G_PRIORITY_LOW, /* priority */
572 NULL, /* cancelable */
573 log_to_file_cb, /* callback */
574 outputstring); /* data */
8cfb4645 575
9dda8252
JL
576 return;
577}
26ddbcdf 578#endif
9dda8252
JL
579
580static gboolean
581menubar_press (GtkWidget * widget,
582 GdkEventButton *event,
583 gpointer data G_GNUC_UNUSED)
584
8cfb4645
AG
585{
586 if (event->button != 1) {
587 g_signal_stop_emission_by_name(widget, "button-press-event");
9dda8252
JL
588 }
589
590 return FALSE;
591
592}
8cfb4645 593
9dda8252
JL
594static gboolean
595menubar_scroll (GtkWidget *widget G_GNUC_UNUSED,
596 GdkEventScroll *event,
0bcf9045 597 gpointer data G_GNUC_UNUSED)
9dda8252
JL
598{
599
600 GtkWidget *menuitem;
601
602 menuitem = gtk_get_event_widget ((GdkEvent *)event);
603
604 IndicatorObject *io = g_object_get_data (G_OBJECT (menuitem), "indicator");
605 g_signal_emit_by_name (io, "scroll", 1, event->direction);
8cfb4645 606
9dda8252
JL
607 return FALSE;
608
609}
610
9dda8252
JL
611static gboolean
612menubar_on_expose (GtkWidget * widget,
613 GdkEventExpose *event G_GNUC_UNUSED,
614 GtkWidget * menubar)
615{
8cfb4645
AG
616 if (GTK_WIDGET_HAS_FOCUS(menubar))
617 gtk_paint_focus(widget->style, widget->window, GTK_WIDGET_STATE(menubar),
618 NULL, widget, "menubar-applet", 0, 0, -1, -1);
9dda8252 619
8cfb4645 620 return FALSE;
9dda8252
JL
621}
622
a7bd16a4 623static void indicator_load_modules(LXPanel *panel, GtkWidget *p)
9dda8252
JL
624{
625
626 gint indicators_loaded = 0;
8cfb4645
AG
627 IndicatorPlugin * indicator = lxpanel_plugin_get_data(p);
628
629 gtk_widget_hide_all(p);
630
5b397638
AG
631 gtk_container_forall(GTK_CONTAINER(indicator->menubar),
632 (GtkCallback)gtk_widget_destroy, NULL);
9dda8252
JL
633
634 if (g_file_test(INDICATOR_DIR, (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
635 {
636 GDir *dir = g_dir_open(INDICATOR_DIR, 0, NULL);
637
638 const gchar *name;
639 while ((name = g_dir_read_name(dir)) != NULL)
640 {
641
e41dd2dd
JL
642 if (g_strcmp0(name, "libsession.so")== 0) {
643 if (indicator->session == 1){
9dda8252
JL
644 load_module(name, indicator->menubar);
645 indicators_loaded++;
646 }
647 }
648 else if (g_strcmp0(name, "libapplication.so")== 0) {
649 if (indicator->applications == 1){
650 load_module(name, indicator->menubar);
651 indicators_loaded++;
652 }
653 }
654 else if (g_strcmp0(name, "libdatetime.so")== 0) {
655 if (indicator->datetime == 1) {
656 load_module(name, indicator->menubar);
657 indicators_loaded++;
658 }
659 }
660 else if (g_strcmp0(name, "libmessaging.so")== 0) {
661 if (indicator->messages == 1) {
662 load_module(name, indicator->menubar);
663 indicators_loaded++;
664 }
665 }
666 else if (g_strcmp0(name, "libnetworkmenu.so")== 0) {
667 if (indicator->network == 1) {
668 load_module(name, indicator->menubar);
669 indicators_loaded++;
670 }
671 }
672 else if (g_strcmp0(name, "libsoundmenu.so")== 0) {
673 if (indicator->sound == 1) {
674 load_module(name, indicator->menubar);
675 indicators_loaded++;
676 }
677 }
e41dd2dd
JL
678 /* else if (g_strcmp0(name, "libappmenu.so") == 0) {
679 if (indicator->appmenu == 1) {
680 load_module(name, indicator->menubar);
681 indicators_loaded++;
682 }
683 }*/
9dda8252
JL
684 }
685 g_dir_close (dir);
686 }
8cfb4645 687
9dda8252
JL
688 if (indicators_loaded == 0)
689 {
690 /* A label to allow for click through */
5b397638 691 gtk_container_add(GTK_CONTAINER(p), gtk_label_new(_("No Indicators")));
9dda8252
JL
692 }
693 else
694 {
8cfb4645 695 gtk_container_add(GTK_CONTAINER(p), indicator->menubar);
9dda8252
JL
696 }
697
698 /* Update the display, show the widget, and return. */
8cfb4645 699 gtk_widget_show_all(p);
9dda8252
JL
700
701}
702
703/* Plugin constructor. */
a7bd16a4 704static GtkWidget *indicator_constructor(LXPanel *panel, config_setting_t *settings)
9dda8252
JL
705{
706 /* Allocate and initialize plugin context and set into Plugin private data pointer. */
707 IndicatorPlugin * indicator = g_new0(IndicatorPlugin, 1);
8cfb4645
AG
708 GtkWidget *p;
709 int tmp_int;
710
711 indicator->panel = panel;
712 indicator->settings = settings;
713
9dda8252
JL
714 /* Default support for indicators */
715 indicator->applications = TRUE;
716 indicator->datetime = FALSE;
717 indicator->messages = FALSE;
718 indicator->network = FALSE;
719 indicator->session = FALSE;
720 indicator->sound = FALSE;
e41dd2dd 721 /* indicator->appmenu = FALSE; */
9dda8252
JL
722
723 /* Load parameters from the configuration file. */
8cfb4645
AG
724 if (config_setting_lookup_int(settings, "applications", &tmp_int))
725 indicator->applications = tmp_int != 0;
726 if (config_setting_lookup_int(settings, "datetime", &tmp_int))
727 indicator->datetime = tmp_int != 0;
728 if (config_setting_lookup_int(settings, "messages", &tmp_int))
729 indicator->messages = tmp_int != 0;
730 if (config_setting_lookup_int(settings, "network", &tmp_int))
731 indicator->network = tmp_int != 0;
732 if (config_setting_lookup_int(settings, "session", &tmp_int))
733 indicator->session = tmp_int != 0;
734 if (config_setting_lookup_int(settings, "sound", &tmp_int))
735 indicator->sound = tmp_int != 0;
736 /* if (config_setting_lookup_int(settings, "appmenu", &tmp_int))
737 indicator->appmenu = tmp_int != 0;*/
9dda8252
JL
738
739 /* Allocate top level widget and set into Plugin widget pointer. */
8cfb4645
AG
740 p = gtk_event_box_new();
741 lxpanel_plugin_set_data(p, indicator, g_free);
9dda8252
JL
742
743 gtk_rc_parse_string (
744 "style \"indicator-applet-style\"\n"
745 "{\n"
746 " GtkMenuBar::shadow-type = none\n"
747 " GtkMenuBar::internal-padding = 0\n"
748 " GtkWidget::focus-line-width = 0\n"
749 " GtkWidget::focus-padding = 0\n"
750 "}\n"
751 "style \"indicator-applet-menubar-style\"\n"
752 "{\n"
753 " GtkMenuBar::shadow-type = none\n"
754 " GtkMenuBar::internal-padding = 0\n"
755 " GtkWidget::focus-line-width = 0\n"
756 " GtkWidget::focus-padding = 0\n"
757 " GtkMenuItem::horizontal-padding = 0\n"
758 "}\n"
759 "style \"indicator-applet-menuitem-style\"\n"
760 "{\n"
761 " GtkWidget::focus-line-width = 0\n"
762 " GtkWidget::focus-padding = 0\n"
763 " GtkMenuItem::horizontal-padding = 0\n"
764 "}\n"
765 "widget \"*.fast-user-switch-applet\" style \"indicator-applet-style\""
766 "widget \"*.fast-user-switch-menuitem\" style \"indicator-applet-menuitem-style\""
767 "widget \"*.fast-user-switch-menubar\" style \"indicator-applet-menubar-style\"");
768
8cfb4645 769 gtk_widget_set_name(p, "fast-user-switch-applet");
9dda8252 770
8cfb4645 771 /* Connect signals for container */
26ddbcdf 772 //g_log_set_default_handler(log_to_file, NULL);
9dda8252
JL
773
774 /* Allocate icon as a child of top level. */
775 indicator->menubar = gtk_menu_bar_new();
09fa171b 776 gtk_widget_set_can_focus(indicator->menubar, TRUE);
e41dd2dd
JL
777
778 /* Init some theme/icon stuff */
969a40cf 779 gtk_icon_theme_append_search_path(panel_get_icon_theme(panel),
e41dd2dd
JL
780 INDICATOR_ICONS_DIR);
781 g_debug("Icons directory: %s", INDICATOR_ICONS_DIR);
782
8cfb4645 783 gtk_widget_set_name(indicator->menubar, "fast-user-switch-menubar");
9dda8252
JL
784
785 /* Connect signals. */
9dda8252
JL
786 g_signal_connect(indicator->menubar, "button-press-event", G_CALLBACK(menubar_press), NULL);
787 g_signal_connect(indicator->menubar, "scroll-event", G_CALLBACK (menubar_scroll), NULL);
788 g_signal_connect_after(indicator->menubar, "expose-event", G_CALLBACK(menubar_on_expose), indicator->menubar);
789
790 gtk_container_set_border_width(GTK_CONTAINER(indicator->menubar), 0);
791
8cfb4645
AG
792 /* load 'em */
793 indicator_load_modules(panel, p);
9dda8252 794
8cfb4645 795 return p;
9dda8252
JL
796}
797
8cfb4645 798#if 0
9dda8252 799/* Plugin destructor. */
8cfb4645 800static void indicator_destructor(gpointer user_data)
9dda8252 801{
8cfb4645 802 IndicatorPlugin * indicator = (IndicatorPlugin *) user_data;
9dda8252
JL
803
804 /* Deallocate all memory. */
805 g_free(indicator);
806}
8cfb4645 807#endif
9dda8252
JL
808
809/* Callback when panel configuration changes. */
a7bd16a4 810static void indicator_panel_configuration_changed(LXPanel *panel, GtkWidget *p)
9dda8252
JL
811{
812 /*
813 Update when configuration changed
814 */
815
816 /* load 'em */
8cfb4645 817 indicator_load_modules(panel, p);
9dda8252
JL
818
819 /* Determine if the orientation changed in a way that requires action. */
820 /*
821 GtkWidget * sep = gtk_bin_get_child(GTK_BIN(p->pwid));
822 if (GTK_IS_VSEPARATOR(sep))
823 {
824 if (p->panel->orientation == GTK_ORIENTATION_HORIZONTAL)
825 return;
826 }
827 else
828 {
829 if (p->panel->orientation == GTK_ORIENTATION_VERTICAL)
830 return;
831 }
832*/
833}
834
835/* Callback when the configuration dialog has recorded a configuration change. */
8cfb4645 836static gboolean indicator_apply_configuration(gpointer user_data)
9dda8252 837{
8cfb4645 838 IndicatorPlugin * indicator = lxpanel_plugin_get_data(user_data);
9dda8252 839
9dda8252 840 /* load 'em */
8cfb4645
AG
841 indicator_load_modules(indicator->panel, user_data);
842
843 config_group_set_int(indicator->settings, "applications", indicator->applications);
844 config_group_set_int(indicator->settings, "datetime", indicator->datetime);
845 config_group_set_int(indicator->settings, "messages", indicator->messages);
846 config_group_set_int(indicator->settings, "network", indicator->network);
847 config_group_set_int(indicator->settings, "session", indicator->session);
848 config_group_set_int(indicator->settings, "sound", indicator->sound);
9dda8252
JL
849 /* Apply settings. */
850/*
851 if (p->panel->orientation == ORIENT_HORIZ)
852 gtk_widget_set_size_request(p->pwid, sp->size, 2);
853 else
854 gtk_widget_set_size_request(p->pwid, 2, sp->size);
855*/
8cfb4645 856 return FALSE;
9dda8252
JL
857}
858
859/* Callback when the configuration dialog is to be shown. */
752ee4e2 860static GtkWidget *indicator_configure(LXPanel *panel, GtkWidget *p)
9dda8252 861{
8cfb4645
AG
862 IndicatorPlugin * indicator = lxpanel_plugin_get_data(p);
863 GtkWidget * dlg = lxpanel_generic_config_dlg(_("Indicator applets"),
864 panel, indicator_apply_configuration, p,
9dda8252
JL
865 _("Indicator Applications"), &indicator->applications, CONF_TYPE_BOOL,
866 _("Clock Indicator"), &indicator->datetime, CONF_TYPE_BOOL,
867 _("Messaging Menu"), &indicator->messages, CONF_TYPE_BOOL,
868 _("Network Menu"), &indicator->network, CONF_TYPE_BOOL,
869 _("Session Menu"), &indicator->session, CONF_TYPE_BOOL,
870 _("Sound Menu"), &indicator->sound, CONF_TYPE_BOOL,
e41dd2dd 871 /* _("Applications menus"), &indicator->appmenu, CONF_TYPE_BOOL,*/
9dda8252
JL
872 NULL);
873 gtk_widget_set_size_request(GTK_WIDGET(dlg), 300, -1);
8cfb4645 874 return dlg;
9dda8252
JL
875}
876
8cfb4645 877FM_DEFINE_MODULE(lxpanel_gtk, indicator)
9dda8252
JL
878
879/* Plugin descriptor. */
8cfb4645 880LXPanelPluginInit fm_module_init_lxpanel_gtk = {
3c3e9c9e 881 .name = N_("Indicator applets"),
3c3e9c9e
HG
882 .description = N_("Add indicator applets to the panel"),
883
8cfb4645 884 .new_instance = indicator_constructor,
3c3e9c9e 885 .config = indicator_configure,
8cfb4645 886 .reconfigure = indicator_panel_configuration_changed
9dda8252 887};