Correct background for 'indicator' plugin - it should use panel settings.
[lxde/lxpanel.git] / plugins / indicator / indicator.c
1 /*
2 Copyright 2010 Julien Lavergne <gilir@ubuntu.com>
3
4 Based on indicator-applet :
5 Copyright 2009 Canonical Ltd.
6
7 Authors:
8 Ted Gould <ted@canonical.com>
9
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License
12 version 3.0 as published by the Free Software Foundation.
13
14 This library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License version 3.0 for more details.
18
19 You should have received a copy of the GNU General Public
20 License along with this library. If not, see
21 <http://www.gnu.org/licenses/>.
22
23 TODO Check also http://bazaar.launchpad.net/~unity-team/unity/trunk/view/head:/services/panel-service.c
24
25 TODO ? : add hotkey support (r348 + r352)
26
27 TODO : vertical support (r354)
28
29 */
30
31 #include "plugin.h"
32
33 #include <stdlib.h>
34 #include <glib/gi18n.h>
35
36 #include <gtk/gtk.h>
37 #include <libindicator/indicator-object.h>
38
39 static 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}
53 };
54
55 #define MENU_DATA_BOX "box"
56 #define MENU_DATA_INDICATOR_OBJECT "indicator-object"
57 #define MENU_DATA_INDICATOR_ENTRY "indicator-entry"
58 #define MENU_DATA_IN_MENUITEM "in-menuitem"
59 #define MENU_DATA_MENUITEM_PRESSED "menuitem-pressed"
60
61 #define IO_DATA_NAME "indicator-name"
62 #define IO_DATA_ORDER_NUMBER "indicator-order-number"
63
64 #define LOG_FILE_NAME "lxpanel-indicator-plugin.log"
65
66 GOutputStream * log_file = NULL;
67
68 typedef struct {
69 LXPanel *panel;
70 config_setting_t *settings;
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 */
78
79 gboolean applications; /* Support for differents indicators */
80 gboolean datetime;
81 gboolean me;
82 gboolean messages;
83 gboolean network;
84 gboolean session;
85 gboolean sound;
86 /* gboolean appmenu; */
87
88
89 } IndicatorPlugin;
90
91 static const gchar * indicator_env[] = {
92 "indicator-applet",
93 NULL
94 };
95
96 static gint
97 name2order (const gchar * name, const gchar * hint) {
98 int i;
99
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 }
106
107 return -1;
108 }
109
110 typedef struct _incoming_position_t incoming_position_t;
111 struct _incoming_position_t {
112 gint objposition;
113 gint entryposition;
114 gint menupos;
115 gboolean found;
116 };
117
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. */
122 static void
123 place_in_menu_cb (GtkWidget * widget, gpointer user_data)
124 {
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 */
169 static void
170 place_in_menu (GtkWidget *menubar,
171 GtkWidget *menuitem,
172 IndicatorObject *io,
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);
198 }
199
200 static void
201 something_shown (GtkWidget * widget, gpointer user_data)
202 {
203 GtkWidget * menuitem = GTK_WIDGET(user_data);
204 gtk_widget_show(menuitem);
205 }
206
207 static void
208 something_hidden (GtkWidget * widget, gpointer user_data)
209 {
210 GtkWidget * menuitem = GTK_WIDGET(user_data);
211 gtk_widget_hide(menuitem);
212 }
213
214 static void
215 sensitive_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
224 static void
225 entry_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
237 static gboolean
238 entry_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
271 g_signal_emit_by_name(io, INDICATOR_OBJECT_SIGNAL_SECONDARY_ACTIVATE,
272 entry, event->button.time);
273 }
274 }
275 break;
276 default: ;
277 }
278
279 return FALSE;
280 }
281
282 static gboolean
283 entry_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
297 static void
298 entry_added (IndicatorObject * io, IndicatorObjectEntry * entry, GtkWidget * menubar)
299 {
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);
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);
307
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);
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 }
325
326 if (gtk_widget_get_sensitive(GTK_WIDGET(entry->image))) {
327 something_sensitive = TRUE;
328 }
329
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);
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
360 place_in_menu(menubar, menuitem, io, entry);
361
362 if (something_visible) {
363 gtk_widget_show(menuitem);
364 }
365 gtk_widget_set_sensitive(menuitem, something_sensitive);
366
367 return;
368 }
369
370 static void
371 entry_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
396 static void
397 entry_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 }
409
410 array[1] = widget;
411 return;
412 }
413
414 /* Gets called when an entry for an object was moved. */
415 static void
416 entry_moved (IndicatorObject * io, IndicatorObjectEntry * entry,
417 gint old G_GNUC_UNUSED, gint new G_GNUC_UNUSED, gpointer user_data)
418 {
419 GtkWidget * menubar = GTK_WIDGET(user_data);
420
421 gpointer array[2];
422 array[0] = entry;
423 array[1] = NULL;
424
425 gtk_container_foreach(GTK_CONTAINER(menubar), entry_moved_find_cb, array);
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));
433 gtk_container_remove(GTK_CONTAINER(menubar), mi);
434 place_in_menu(menubar, mi, io, entry);
435 g_object_unref(G_OBJECT(mi));
436
437 return;
438 }
439
440 static void
441 entry_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
451 static void
452 menu_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
475 static gboolean
476 load_module (const gchar * name, GtkWidget * menubar)
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 */
489 gchar *fullpath = g_build_filename(INDICATOR_DIR, name, NULL);
490 g_debug("Full path: %s", fullpath);
491 IndicatorObject * io = indicator_object_new_from_file(fullpath);
492 g_free(fullpath);
493
494 /* Set the environment it's in */
495 indicator_object_set_environment(io, (const GStrv)indicator_env);
496
497 /* Attach the 'name' to the object */
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)));
500
501 /* Connect to it's signals */
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);
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;
514 entry_added(io, entrydata, menubar);
515 }
516
517 g_list_free(entries);
518
519 return TRUE;
520 }
521
522 #if 0
523 static void
524 log_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 }
530
531 static void
532 log_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);
546
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 }
552
553 g_file_delete(file, NULL, NULL);
554
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 }
566
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 */
575
576 return;
577 }
578 #endif
579
580 static gboolean
581 menubar_press (GtkWidget * widget,
582 GdkEventButton *event,
583 gpointer data G_GNUC_UNUSED)
584
585 {
586 if (event->button != 1) {
587 g_signal_stop_emission_by_name(widget, "button-press-event");
588 }
589
590 return FALSE;
591
592 }
593
594 static gboolean
595 menubar_scroll (GtkWidget *widget G_GNUC_UNUSED,
596 GdkEventScroll *event,
597 gpointer data G_GNUC_UNUSED)
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);
606
607 return FALSE;
608
609 }
610
611 static gboolean
612 menubar_on_expose (GtkWidget * widget,
613 GdkEventExpose *event G_GNUC_UNUSED,
614 GtkWidget * menubar)
615 {
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);
619
620 return FALSE;
621 }
622
623 static void indicator_load_modules(LXPanel *panel, GtkWidget *p)
624 {
625
626 gint indicators_loaded = 0;
627 IndicatorPlugin * indicator = lxpanel_plugin_get_data(p);
628
629 gtk_widget_hide_all(p);
630
631 gtk_container_forall(GTK_CONTAINER(indicator->menubar),
632 (GtkCallback)gtk_widget_destroy, NULL);
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
642 if (g_strcmp0(name, "libsession.so")== 0) {
643 if (indicator->session == 1){
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 }
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 }*/
684 }
685 g_dir_close (dir);
686 }
687
688 if (indicators_loaded == 0)
689 {
690 /* A label to allow for click through */
691 gtk_container_add(GTK_CONTAINER(p), gtk_label_new(_("No Indicators")));
692 }
693 else
694 {
695 gtk_container_add(GTK_CONTAINER(p), indicator->menubar);
696 }
697
698 /* Update the display, show the widget, and return. */
699 gtk_widget_show_all(p);
700
701 }
702
703 /* Plugin constructor. */
704 static GtkWidget *indicator_constructor(LXPanel *panel, config_setting_t *settings)
705 {
706 /* Allocate and initialize plugin context and set into Plugin private data pointer. */
707 IndicatorPlugin * indicator = g_new0(IndicatorPlugin, 1);
708 GtkWidget *p;
709 int tmp_int;
710
711 indicator->panel = panel;
712 indicator->settings = settings;
713
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;
721 /* indicator->appmenu = FALSE; */
722
723 /* Load parameters from the configuration file. */
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;*/
738
739 /* Allocate top level widget and set into Plugin widget pointer. */
740 p = gtk_event_box_new();
741 lxpanel_plugin_set_data(p, indicator, g_free);
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
769 gtk_widget_set_name(p, "fast-user-switch-applet");
770
771 /* Connect signals for container */
772 //g_log_set_default_handler(log_to_file, NULL);
773
774 /* Allocate icon as a child of top level. */
775 indicator->menubar = gtk_menu_bar_new();
776 gtk_widget_set_can_focus(indicator->menubar, TRUE);
777
778 /* Init some theme/icon stuff */
779 gtk_icon_theme_append_search_path(panel_get_icon_theme(panel),
780 INDICATOR_ICONS_DIR);
781 g_debug("Icons directory: %s", INDICATOR_ICONS_DIR);
782
783 gtk_widget_set_name(indicator->menubar, "fast-user-switch-menubar");
784
785 /* Connect signals. */
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
792 /* load 'em */
793 indicator_load_modules(panel, p);
794
795 return p;
796 }
797
798 #if 0
799 /* Plugin destructor. */
800 static void indicator_destructor(gpointer user_data)
801 {
802 IndicatorPlugin * indicator = (IndicatorPlugin *) user_data;
803
804 /* Deallocate all memory. */
805 g_free(indicator);
806 }
807 #endif
808
809 /* Callback when panel configuration changes. */
810 static void indicator_panel_configuration_changed(LXPanel *panel, GtkWidget *p)
811 {
812 /*
813 Update when configuration changed
814 */
815
816 /* load 'em */
817 indicator_load_modules(panel, p);
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. */
836 static gboolean indicator_apply_configuration(gpointer user_data)
837 {
838 IndicatorPlugin * indicator = lxpanel_plugin_get_data(user_data);
839
840 /* load 'em */
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);
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 */
856 return FALSE;
857 }
858
859 /* Callback when the configuration dialog is to be shown. */
860 static GtkWidget *indicator_configure(LXPanel *panel, GtkWidget *p)
861 {
862 IndicatorPlugin * indicator = lxpanel_plugin_get_data(p);
863 GtkWidget * dlg = lxpanel_generic_config_dlg(_("Indicator applets"),
864 panel, indicator_apply_configuration, p,
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,
871 /* _("Applications menus"), &indicator->appmenu, CONF_TYPE_BOOL,*/
872 NULL);
873 gtk_widget_set_size_request(GTK_WIDGET(dlg), 300, -1);
874 return dlg;
875 }
876
877 FM_DEFINE_MODULE(lxpanel_gtk, indicator)
878
879 /* Plugin descriptor. */
880 LXPanelPluginInit fm_module_init_lxpanel_gtk = {
881 .name = N_("Indicator applets"),
882 .description = N_("Add indicator applets to the panel"),
883
884 .new_instance = indicator_constructor,
885 .config = indicator_configure,
886 .reconfigure = indicator_panel_configuration_changed
887 };