Add indicator applet, turn off by default
authorJulien Lavergne <julien.lavergne@gmail.com>
Sat, 31 Dec 2011 14:51:53 +0000 (15:51 +0100)
committerJulien Lavergne <julien.lavergne@gmail.com>
Sat, 31 Dec 2011 14:51:53 +0000 (15:51 +0100)
configure.ac
src/plugins/indicator/Makefile.am [new file with mode: 0644]
src/plugins/indicator/indicator.c [new file with mode: 0644]

index b9041c8..2a87762 100644 (file)
@@ -46,6 +46,34 @@ PKG_CHECK_MODULES(PACKAGE, [$pkg_modules])
 AC_SUBST(PACKAGE_CFLAGS)
 AC_SUBST(PACKAGE_LIBS)
 
+###########################
+# Indicator Info
+###########################
+AC_ARG_ENABLE([indicator_support],
+    AS_HELP_STRING([--enable-indicator-support],
+               [enable plugin loading (default: disable)]),
+               indicator_support=$enableval, indicator_support="no")
+AM_CONDITIONAL(ENABLE_INDICATOR_SUPPORT, test x"$indicator_support" = x"yes")
+
+if test "$indicator_support" != "no"; then
+       INDICATOR_REQUIRED_VERSION=0.3.0
+       INDICATOR_PKG_NAME=indicator-0.4
+
+       PKG_CHECK_MODULES(APPLET, $INDICATOR_PKG_NAME >= $INDICATOR_REQUIRED_VERSION)
+       AC_SUBST(APPLET_CFLAGS)
+
+       if test "x$with_localinstall" = "xyes"; then
+               INDICATORDIR="${libdir}/indicators/2/"
+               INDICATORICONSDIR="${datadir}/indicator-applet/icons/"
+       else
+               INDICATORDIR=`$PKG_CONFIG --variable=indicatordir $INDICATOR_PKG_NAME`
+               INDICATORICONSDIR=`$PKG_CONFIG --variable=iconsdir $INDICATOR_PKG_NAME`
+fi
+       AC_SUBST(INDICATORDIR)
+       AC_SUBST(INDICATORICONSDIR)
+fi
+
+
 pkg_modules="x11"
 PKG_CHECK_MODULES(X11, [$pkg_modules])
 AC_SUBST(X11_LIBS)
@@ -201,6 +229,7 @@ plugin_thermal=
 plugin_cpufreq=
 plugin_monitors=
 plugin_wnckpager=
+plugin_indicator=
 
 AC_MSG_CHECKING([which plugins should be built dynamically])
 AC_ARG_WITH(plugins,
@@ -238,6 +267,7 @@ dnl    done
     plugin_cpufreq=cpufreq
     plugin_monitors=monitors
     plugin_wnckpager=wnckpager
+    plugin_indicator=indicator
 
     AC_MSG_RESULT(all)
 else
@@ -282,6 +312,9 @@ else
             wnckpager)
                 plugin_wnckpager=wnckpager
                 ;;
+            indicator)
+                plugin_indicator=indicator
+                ;;
             *)
                 echo "Unknown plugin $plugin."
                 exit 1
@@ -302,6 +335,12 @@ else
     dnl force OSS plugin to <null>
     plugin_volume=
 fi
+
+dnl Exclude indicator support when there is no support.
+if test x"$indicator_support" = "xno"; then
+    plugin_indicator=
+fi
+
 PLUGINS_LIST="\
     $plugin_netstatus \
     $plugin_volume \
@@ -314,7 +353,8 @@ PLUGINS_LIST="\
     $plugin_thermal \
     $plugin_cpufreq \
     $plugin_monitors \
-    $plugin_wnckpager"
+    $plugin_wnckpager\
+    $plugin_indicator"
 
 AC_SUBST(PLUGINS_LIST)
 
@@ -389,6 +429,7 @@ AC_CONFIG_FILES([
     src/plugins/cpufreq/Makefile
     src/plugins/monitors/Makefile
     src/plugins/wnckpager/Makefile
+    src/plugins/indicator/Makefile
     po/Makefile.in
     data/Makefile
     data/default/panels/panel
@@ -438,6 +479,9 @@ echo Building dynamic plugins:
     if test x"$plugin_wnckpager" != x; then
         AC_MSG_RESULT([    wnckpager - Pager which support openbox and compiz])
     fi
+    if test x"$plugin_indicator" != x; then
+        AC_MSG_RESULT([    indicator - Indicator support])
+    fi
 else
 echo Dynamic loader for plugins....... : disabled.
 fi
diff --git a/src/plugins/indicator/Makefile.am b/src/plugins/indicator/Makefile.am
new file mode 100644 (file)
index 0000000..07ffb5c
--- /dev/null
@@ -0,0 +1,23 @@
+indicator_la_CFLAGS = \
+       -I. \
+       -I$(top_srcdir)/src \
+       -DINDICATOR_DIR=\""$(INDICATORDIR)"\" \
+       -DINDICATOR_ICONS_DIR=\""$(INDICATORICONSDIR)"\" \
+       $(PACKAGE_CFLAGS) \
+       $(APPLET_CFLAGS) \
+       $(G_CAST_CHECKS)
+
+module_LTLIBRARIES = indicator.la
+
+moduledir = $(libdir)/lxpanel/plugins
+
+indicator_la_SOURCES = \
+       indicator.c
+
+indicator_la_LIBADD = \
+       $(PACKAGE_LIBS) \
+       $(APPLET_LIBS)
+
+indicator_la_LDFLAGS = \
+       -module \
+       @LXPANEL_MODULE@
diff --git a/src/plugins/indicator/indicator.c b/src/plugins/indicator/indicator.c
new file mode 100644 (file)
index 0000000..4282534
--- /dev/null
@@ -0,0 +1,789 @@
+/*
+Copyright 2010 Julien Lavergne <gilir@ubuntu.com>
+
+Based on indicator-applet :
+Copyright 2009 Canonical Ltd.
+
+Authors:
+    Ted Gould <ted@canonical.com>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+version 3.0 as published by the Free Software Foundation.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License version 3.0 for more details.
+
+You should have received a copy of the GNU General Public
+License along with this library. If not, see
+<http://www.gnu.org/licenses/>.
+
+
+TODO
+last revision merged from http://bazaar.launchpad.net/~indicator-applet-developers/indicator-applet
+r363
+
+TODO Check also http://bazaar.launchpad.net/~unity-team/unity/trunk/view/head:/services/panel-service.c
+
+TODO ? : add hotkey support (r348 + r352)
+
+TODO : vertical support (r354)
+
+*/
+
+#include "plugin.h"
+
+#include "misc.h"
+#include "panel.h"
+#include "dbg.h"
+
+#include <stdlib.h>
+#include <glib/gi18n.h>
+
+#include <gtk/gtk.h>
+#include <libindicator/indicator-object.h>
+
+static gchar * indicator_order[] = {
+        "libapplication.so",
+        "libsoundmenu.so",
+        "libmessaging.so",
+        "libdatetime.so",
+        "libme.so",
+        "libsession.so",
+        NULL
+};
+#define  MENU_DATA_INDICATOR_OBJECT  "indicator-object"
+#define  MENU_DATA_INDICATOR_ENTRY   "indicator-entry"
+#define  IO_DATA_ORDER_NUMBER        "indicator-order-number"
+
+#define LOG_FILE_NAME  "lxpanel-indicator-plugin.log"
+
+GOutputStream * log_file = NULL;
+
+typedef struct {
+
+    Plugin * plugin;                   /* Back pointer to plugin */
+
+    IndicatorObject *io;               /* Indicators applets */
+
+    GList *images;                             /* List of images of applets */
+    GList *menus;                              /* List of menus of applets */
+
+    GtkWidget * menubar;               /* Displayed menubar */
+    
+    gboolean applications;      /* Support for differents indicators */
+    gboolean appmenu;
+    gboolean datetime;
+    gboolean me;
+    gboolean messages;
+    gboolean network;
+    gboolean session;
+    gboolean sound;
+
+
+} IndicatorPlugin;
+
+static gint
+name2order (const gchar * name) {
+       int i;
+
+       for (i = 0; indicator_order[i] != NULL; i++) {
+               if (g_strcmp0(name, indicator_order[i]) == 0) {
+                       return i;
+               }
+       }
+
+       return -1;
+}
+typedef struct _incoming_position_t incoming_position_t;
+struct _incoming_position_t {
+        gint objposition;
+        gint entryposition;
+        gint menupos;
+        gboolean found;
+};
+/* This function helps by determining where in the menu list
+   this new entry should be placed.  It compares the objects
+   that they're on, and then the individual entries.  Each
+   is progressively more expensive. */
+static void
+place_in_menu (GtkWidget * widget, gpointer user_data)
+{
+        incoming_position_t * position = (incoming_position_t *)user_data;
+        if (position->found) {
+                /* We've already been placed, just finish the foreach */
+                return;
+        }
+        IndicatorObject * io = INDICATOR_OBJECT(g_object_get_data(G_OBJECT(widget), MENU_DATA_INDICATOR_OBJECT));
+        g_assert(io != NULL);
+        gint objposition = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(io), IO_DATA_ORDER_NUMBER));
+        /* We've already passed it, well, then this is where
+           we should be be.  Stop! */
+        if (objposition > position->objposition) {
+                position->found = TRUE;
+                return;
+        }
+        /* The objects don't match yet, keep looking */
+        if (objposition < position->objposition) {
+                position->menupos++;
+                return;
+        }
+        /* The objects are the same, let's start looking at entries. */
+        IndicatorObjectEntry * entry = (IndicatorObjectEntry *)g_object_get_data(G_OBJECT(widget), MENU_DATA_INDICATOR_ENTRY);
+        gint entryposition = indicator_object_get_location(io, entry);
+        if (entryposition > position->entryposition) {
+                position->found = TRUE;
+                return;
+        }
+        if (entryposition < position->entryposition) {
+                position->menupos++;
+                return;
+        }
+        /* We've got the same object and the same entry.  Well,
+           let's just put it right here then. */
+        position->found = TRUE;
+        return;
+}
+
+static void
+something_shown (GtkWidget * widget, gpointer user_data)
+{
+        GtkWidget * menuitem = GTK_WIDGET(user_data);
+        gtk_widget_show(menuitem);
+}
+
+static void
+something_hidden (GtkWidget * widget, gpointer user_data)
+{
+        GtkWidget * menuitem = GTK_WIDGET(user_data);
+        gtk_widget_hide(menuitem);
+}
+
+static void
+sensitive_cb (GObject * obj, GParamSpec * pspec, gpointer user_data)
+{
+    g_return_if_fail(GTK_IS_WIDGET(obj));
+    g_return_if_fail(GTK_IS_WIDGET(user_data));
+
+    gtk_widget_set_sensitive(GTK_WIDGET(user_data), gtk_widget_get_sensitive(GTK_WIDGET(obj)));
+    return;
+}
+
+static void
+entry_added (IndicatorObject * io, IndicatorObjectEntry * entry, GtkWidget * menu)
+{
+    g_debug("Signal: Entry Added");
+    gboolean something_visible = FALSE;
+    gboolean something_sensitive = FALSE;
+
+    GtkWidget * menuitem = gtk_menu_item_new();
+    GtkWidget * hbox = gtk_hbox_new(FALSE, 3);
+    
+    g_object_set_data (G_OBJECT (menuitem), "indicator", io);
+
+    if (entry->image != NULL)
+    {
+        gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(entry->image), FALSE, FALSE, 1);
+        if (gtk_widget_get_visible(GTK_WIDGET(entry->image))) {
+                something_visible = TRUE;
+        }
+        
+        if (gtk_widget_get_sensitive(GTK_WIDGET(entry->image))) {
+            something_sensitive = TRUE;
+        }
+        
+        g_signal_connect(G_OBJECT(entry->image), "show", G_CALLBACK(something_shown), menuitem);
+        g_signal_connect(G_OBJECT(entry->image), "hide", G_CALLBACK(something_hidden), menuitem);
+        g_signal_connect(G_OBJECT(entry->image), "notify::sensitive", G_CALLBACK(sensitive_cb), menuitem);
+        
+    }
+    if (entry->label != NULL)
+    {
+        gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(entry->label), FALSE, FALSE, 1);
+
+        if (gtk_widget_get_visible(GTK_WIDGET(entry->label))) {
+                something_visible = TRUE;
+        }
+
+        if (gtk_widget_get_sensitive(GTK_WIDGET(entry->label))) {
+
+            something_sensitive = TRUE;
+        }
+
+        g_signal_connect(G_OBJECT(entry->label), "show", G_CALLBACK(something_shown), menuitem);
+        g_signal_connect(G_OBJECT(entry->label), "hide", G_CALLBACK(something_hidden), menuitem);
+        g_signal_connect(G_OBJECT(entry->label), "notify::sensitive", G_CALLBACK(sensitive_cb), menuitem);
+
+    }
+    gtk_container_add(GTK_CONTAINER(menuitem), hbox);
+    gtk_widget_show(hbox);
+
+    if (entry->menu != NULL)
+    {
+        gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), GTK_WIDGET(entry->menu));
+    }
+
+    incoming_position_t position;
+    position.objposition = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(io), IO_DATA_ORDER_NUMBER));
+    position.entryposition = indicator_object_get_location(io, entry);
+    position.menupos = 0;
+    position.found = FALSE;
+    gtk_container_foreach(GTK_CONTAINER(menu), place_in_menu, &position);
+
+    gtk_menu_shell_insert(GTK_MENU_SHELL(menu), menuitem, position.menupos);
+    
+    if (something_visible) {
+        gtk_widget_show(menuitem);
+    }
+    gtk_widget_set_sensitive(menuitem, something_sensitive);
+
+    g_object_set_data(G_OBJECT(menuitem), MENU_DATA_INDICATOR_ENTRY,  entry);
+    g_object_set_data(G_OBJECT(menuitem), MENU_DATA_INDICATOR_OBJECT, io);
+
+    return;
+}
+
+static void
+entry_removed_cb (GtkWidget * widget, gpointer userdata)
+{
+    gpointer data = g_object_get_data(G_OBJECT(widget), MENU_DATA_INDICATOR_ENTRY);
+
+    if (data != userdata)
+    {
+        return;
+    }
+
+    IndicatorObjectEntry * entry = (IndicatorObjectEntry *)data;
+    if (entry->label != NULL) {
+        g_signal_handlers_disconnect_by_func(G_OBJECT(entry->label), G_CALLBACK(something_shown), widget);
+        g_signal_handlers_disconnect_by_func(G_OBJECT(entry->label), G_CALLBACK(something_hidden), widget);
+        g_signal_handlers_disconnect_by_func(G_OBJECT(entry->label), G_CALLBACK(sensitive_cb), widget);
+    }
+    if (entry->image != NULL) {
+        g_signal_handlers_disconnect_by_func(G_OBJECT(entry->image), G_CALLBACK(something_shown), widget);
+        g_signal_handlers_disconnect_by_func(G_OBJECT(entry->image), G_CALLBACK(something_hidden), widget);
+        g_signal_handlers_disconnect_by_func(G_OBJECT(entry->image), G_CALLBACK(sensitive_cb), widget);
+    }
+
+    gtk_widget_destroy(widget);
+    return;
+}
+
+static void
+entry_moved_find_cb (GtkWidget * widget, gpointer userdata)
+{
+    gpointer * array = (gpointer *)userdata;
+    if (array[1] != NULL) {
+        return;
+    }
+
+    gpointer data = g_object_get_data(G_OBJECT(widget), MENU_DATA_INDICATOR_ENTRY);
+
+    if (data != array[0]) {
+        return;
+    }
+    array[1] = widget;
+    return;
+}
+/* Gets called when an entry for an object was moved. */
+static void 
+entry_moved (IndicatorObject * io, IndicatorObjectEntry * entry,
+             gint old G_GNUC_UNUSED, gint new G_GNUC_UNUSED, gpointer user_data)
+{
+    GtkWidget * menu = GTK_WIDGET(user_data);
+
+    gpointer array[2];
+    array[0] = entry;
+    array[1] = NULL;
+
+    gtk_container_foreach(GTK_CONTAINER(user_data), entry_moved_find_cb, array);
+    if (array[1] == NULL) {
+        g_warning("Moving an entry that isn't in our menus.");
+        return;
+    }
+
+    GtkWidget * mi = GTK_WIDGET(array[1]);
+    g_object_ref(G_OBJECT(mi));
+    gtk_container_remove(GTK_CONTAINER(user_data), mi);
+
+    incoming_position_t position;
+    position.objposition = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(io), IO_DATA_ORDER_NUMBER));
+    position.entryposition = indicator_object_get_location(io, entry);
+    position.menupos = 0;
+    position.found = FALSE;
+
+    gtk_container_foreach(GTK_CONTAINER(menu), place_in_menu, &position);
+    gtk_menu_shell_insert(GTK_MENU_SHELL(menu), mi, position.menupos);
+    g_object_unref(G_OBJECT(mi));
+    return;
+}
+
+static void
+entry_removed (IndicatorObject * io G_GNUC_UNUSED, IndicatorObjectEntry * entry,
+               gpointer user_data)
+{
+    g_debug("Signal: Entry Removed");
+
+    gtk_container_foreach(GTK_CONTAINER(user_data), entry_removed_cb, entry);
+
+    return;
+}
+
+static gboolean
+load_module (const gchar * name, GtkWidget * menu)
+{
+    g_debug("Looking at Module: %s", name);
+    g_return_val_if_fail(name != NULL, FALSE);
+
+    if (!g_str_has_suffix(name, G_MODULE_SUFFIX))
+    {
+        return FALSE;
+    }
+
+    g_debug("Loading Module: %s", name);
+
+    /* Build the object for the module */
+
+    gchar *fullpath = g_build_filename(INDICATOR_DIR, name, NULL);
+
+    g_debug("Full path: %s", fullpath);
+
+    IndicatorObject * io = indicator_object_new_from_file(fullpath);
+    g_free(fullpath);
+    
+    /* Attach the 'name' to the object */
+    g_object_set_data(G_OBJECT(io), IO_DATA_ORDER_NUMBER, GINT_TO_POINTER(name2order(name)));
+
+    /* Connect to it's signals */
+    g_signal_connect(G_OBJECT(io), INDICATOR_OBJECT_SIGNAL_ENTRY_ADDED,   G_CALLBACK(entry_added),    menu);
+    g_signal_connect(G_OBJECT(io), INDICATOR_OBJECT_SIGNAL_ENTRY_REMOVED, G_CALLBACK(entry_removed),  menu);
+    g_signal_connect(G_OBJECT(io), INDICATOR_OBJECT_SIGNAL_ENTRY_MOVED,   G_CALLBACK(entry_moved),    menu);
+
+    /* Work on the entries */
+    GList * entries = indicator_object_get_entries(io);
+    GList * entry = NULL;
+
+    for (entry = entries; entry != NULL; entry = g_list_next(entry))
+    {
+        IndicatorObjectEntry * entrydata = (IndicatorObjectEntry *)entry->data;
+        entry_added(io, entrydata, menu);
+    }
+
+    g_list_free(entries);
+
+    return TRUE;
+}
+
+static void
+log_to_file_cb (GObject * source_obj G_GNUC_UNUSED,
+                GAsyncResult * result G_GNUC_UNUSED, gpointer user_data)
+{
+    g_free(user_data);
+    return;
+}
+static void
+log_to_file (const gchar * domain G_GNUC_UNUSED,
+             GLogLevelFlags level G_GNUC_UNUSED,
+             const gchar * message,
+             gpointer data G_GNUC_UNUSED)
+{
+    if (log_file == NULL) {
+        GError * error = NULL;
+        gchar * filename = g_build_filename(g_get_user_cache_dir(), LOG_FILE_NAME, NULL);
+        GFile * file = g_file_new_for_path(filename);
+        g_free(filename);
+
+        if (!g_file_test(g_get_user_cache_dir(), G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
+            GFile * cachedir = g_file_new_for_path(g_get_user_cache_dir());
+            g_file_make_directory_with_parents(cachedir, NULL, &error);
+            if (error != NULL) {
+                g_error("Unable to make directory '%s' for log file: %s", g_get_user_cache_dir(), error->message);
+                return;
+            }
+        }
+        g_file_delete(file, NULL, NULL);
+        GFileIOStream * io = g_file_create_readwrite(file,
+                                G_FILE_CREATE_REPLACE_DESTINATION, /* flags */
+                                NULL, /* cancelable */
+                                &error); /* error */
+        if (error != NULL) {
+            g_error("Unable to replace file: %s", error->message);
+            return;
+        }
+
+        log_file = g_io_stream_get_output_stream(G_IO_STREAM(io));
+    }
+        
+    gchar * outputstring = g_strdup_printf("%s\n", message);
+    g_output_stream_write_async(log_file,
+                                outputstring, /* data */
+                                strlen(outputstring), /* length */
+                                G_PRIORITY_LOW, /* priority */
+                                NULL, /* cancelable */
+                                log_to_file_cb, /* callback */
+                                outputstring); /* data */
+    return;
+}
+
+static gboolean
+menubar_press (GtkWidget * widget,
+                    GdkEventButton *event,
+                    gpointer data G_GNUC_UNUSED)
+
+{      
+    if (event->button != 1) {  
+        g_signal_stop_emission_by_name(widget, "button-press-event");  
+    }
+
+    return FALSE;
+
+}
+       
+static gboolean
+menubar_scroll (GtkWidget      *widget G_GNUC_UNUSED,
+                GdkEventScroll *event,
+                gpointer        data G_GNUC_UNUSED)    
+{
+
+    GtkWidget *menuitem;
+
+    menuitem = gtk_get_event_widget ((GdkEvent *)event);
+
+    IndicatorObject *io = g_object_get_data (G_OBJECT (menuitem), "indicator");
+    g_signal_emit_by_name (io, "scroll", 1, event->direction);
+       
+    return FALSE;
+
+}
+
+       
+static gboolean
+menubar_on_expose (GtkWidget * widget,
+                    GdkEventExpose *event G_GNUC_UNUSED,
+                    GtkWidget * menubar)
+{
+
+       if (GTK_WIDGET_HAS_FOCUS(menubar))
+               gtk_paint_focus(widget->style, widget->window, GTK_WIDGET_STATE(menubar),
+                               NULL, widget, "menubar-applet", 0, 0, -1, -1);
+
+       return FALSE;
+}
+
+static gint indicator_load_modules(Plugin * p)
+{
+
+    gint indicators_loaded = 0;
+    IndicatorPlugin * indicator = (IndicatorPlugin *) p->priv;
+    
+    gtk_widget_hide_all(p->pwid);
+    
+    GList *l = NULL;
+    for (l = gtk_container_get_children(GTK_CONTAINER(indicator->menubar)); l; l = l->next)
+    {
+        gtk_widget_destroy(GTK_WIDGET(l->data));
+    }
+
+    if (g_file_test(INDICATOR_DIR, (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
+    {
+        GDir *dir = g_dir_open(INDICATOR_DIR, 0, NULL);
+
+        const gchar *name;
+        while ((name = g_dir_read_name(dir)) != NULL)
+        {
+
+            if (g_strcmp0(name, "libsession.so") == 0) {
+                if (indicator->session == 1) {
+                    load_module(name, indicator->menubar);
+                    indicators_loaded++;
+                }
+            }
+            else if (g_strcmp0(name, "libapplication.so")== 0) {
+                if (indicator->applications == 1){
+                    load_module(name, indicator->menubar);
+                    indicators_loaded++;
+                }
+            }
+            else if (g_strcmp0(name, "libdatetime.so")== 0) {
+                if (indicator->datetime == 1) {
+                    load_module(name, indicator->menubar);
+                    indicators_loaded++;
+                }
+            }
+            else if (g_strcmp0(name, "libmessaging.so")== 0) {
+                if (indicator->messages == 1) {
+                    load_module(name, indicator->menubar);
+                    indicators_loaded++;
+                }
+            }
+            else if (g_strcmp0(name, "libnetworkmenu.so")== 0) {
+                if (indicator->network == 1) {
+                    load_module(name, indicator->menubar);
+                    indicators_loaded++;
+                }
+            }
+            else if (g_strcmp0(name, "libsoundmenu.so")== 0) {
+                if (indicator->sound == 1) {
+                    load_module(name, indicator->menubar);
+                    indicators_loaded++;
+                }
+            }
+        }
+        g_dir_close (dir);
+    }
+    
+    if (indicators_loaded == 0)
+    {
+        /* A label to allow for click through */
+        GtkWidget * item = gtk_label_new(_("No Indicators"));
+        gtk_container_add(GTK_CONTAINER(p->pwid), item);
+        gtk_widget_show(item);
+    }
+    else
+    {
+        gtk_container_add(GTK_CONTAINER(p->pwid), indicator->menubar);
+        
+        /* Set background to default. */
+        gtk_widget_set_style(indicator->menubar, p->panel->defstyle);
+        gtk_widget_show(indicator->menubar);
+    }
+
+    /* Update the display, show the widget, and return. */
+    gtk_widget_show_all(p->pwid);
+
+}
+
+/* Plugin constructor. */
+static int indicator_constructor(Plugin * p, char ** fp)
+{
+    /* Allocate and initialize plugin context and set into Plugin private data pointer. */
+    IndicatorPlugin * indicator = g_new0(IndicatorPlugin, 1);
+    indicator->plugin = p;
+    p->priv = indicator;
+    
+    /* Default support for indicators */
+    indicator->applications = TRUE;
+    indicator->datetime     = FALSE;
+    indicator->messages     = FALSE;
+    indicator->network      = FALSE;
+    indicator->session      = FALSE;
+    indicator->sound        = FALSE;
+
+    /* Load parameters from the configuration file. */
+
+    line s;
+    s.len = 256;
+    if (fp != NULL)
+    {
+        while (lxpanel_get_line(fp, &s) != LINE_BLOCK_END)
+        {
+            if (s.type == LINE_NONE)
+            {
+                ERR( "space: illegal token %s\n", s.str);
+                return 0;
+            }
+            if (s.type == LINE_VAR)
+            {
+                if (g_ascii_strcasecmp(s.t[0], "applications") == 0)
+                    indicator->applications = str2num(bool_pair, s.t[1], 0);
+                else if (g_ascii_strcasecmp(s.t[0], "datetime") == 0)
+                    indicator->datetime = str2num(bool_pair, s.t[1], 0);
+                else if (g_ascii_strcasecmp(s.t[0], "messages") == 0)
+                    indicator->messages = str2num(bool_pair, s.t[1], 0);
+                else if (g_ascii_strcasecmp(s.t[0], "network") == 1)
+                    indicator->network = str2num(bool_pair, s.t[1], 0);
+                else if (g_ascii_strcasecmp(s.t[0], "session") == 0)
+                    indicator->session = str2num(bool_pair, s.t[1], 0);
+                else if (g_ascii_strcasecmp(s.t[0], "sound") == 0)
+                    indicator->sound = str2num(bool_pair, s.t[1], 0);
+
+                else
+                    ERR( "indicator: unknown var %s\n", s.t[0]);
+            }
+            else
+            {
+                ERR( "indicator: illegal in this context %s\n", s.str);
+                return 0;
+            }
+        }
+    }
+
+    /* Allocate top level widget and set into Plugin widget pointer. */
+    p->pwid = gtk_event_box_new();
+
+    gtk_rc_parse_string (
+        "style \"indicator-applet-style\"\n"
+        "{\n"
+        "    GtkMenuBar::shadow-type = none\n"
+        "    GtkMenuBar::internal-padding = 0\n"
+        "    GtkWidget::focus-line-width = 0\n"
+        "    GtkWidget::focus-padding = 0\n"
+        "}\n"
+        "style \"indicator-applet-menubar-style\"\n"
+        "{\n"
+        "    GtkMenuBar::shadow-type = none\n"
+        "    GtkMenuBar::internal-padding = 0\n"
+        "    GtkWidget::focus-line-width = 0\n"
+        "    GtkWidget::focus-padding = 0\n"
+        "    GtkMenuItem::horizontal-padding = 0\n"
+        "}\n"
+        "style \"indicator-applet-menuitem-style\"\n"
+        "{\n"
+        "    GtkWidget::focus-line-width = 0\n"
+        "    GtkWidget::focus-padding = 0\n"
+        "    GtkMenuItem::horizontal-padding = 0\n"
+        "}\n"
+        "widget \"*.fast-user-switch-applet\" style \"indicator-applet-style\""
+        "widget \"*.fast-user-switch-menuitem\" style \"indicator-applet-menuitem-style\""
+        "widget \"*.fast-user-switch-menubar\" style \"indicator-applet-menubar-style\"");
+
+    gtk_widget_set_name(GTK_WIDGET (p->pwid), "fast-user-switch-applet");
+    
+    /* Connect signals for container */
+    g_signal_connect(p->pwid, "button-press-event", G_CALLBACK(plugin_button_press_event), p);
+
+    g_log_set_default_handler(log_to_file, NULL);
+
+    /* Allocate icon as a child of top level. */
+    indicator->menubar = gtk_menu_bar_new();
+    GTK_WIDGET_SET_FLAGS (indicator->menubar, GTK_WIDGET_FLAGS(indicator->menubar) | GTK_CAN_FOCUS);
+    gtk_widget_set_name(GTK_WIDGET (indicator->menubar), "fast-user-switch-menubar");
+
+    /* Connect signals. */
+    g_signal_connect(p->pwid, "button-press-event", G_CALLBACK(plugin_button_press_event), p);
+    g_signal_connect(indicator->menubar, "button-press-event", G_CALLBACK(menubar_press), NULL);
+    g_signal_connect(indicator->menubar, "scroll-event", G_CALLBACK (menubar_scroll), NULL);
+    g_signal_connect_after(indicator->menubar, "expose-event", G_CALLBACK(menubar_on_expose), indicator->menubar);
+
+    gtk_container_set_border_width(GTK_CONTAINER(indicator->menubar), 0);
+
+       /* load 'em */
+    indicator_load_modules(p);
+
+    return 1;
+
+}
+
+/* Plugin destructor. */
+static void indicator_destructor(Plugin * p)
+{
+    IndicatorPlugin * indicator = (IndicatorPlugin *) p->priv;
+
+    /* Deallocate all memory. */
+    g_free(indicator);
+}
+
+/* Callback when panel configuration changes. */
+static void indicator_panel_configuration_changed(Plugin * p)
+{
+    /*
+    Update when configuration changed
+    */
+
+    /* load 'em */
+       indicator_load_modules(p);
+
+    /* Determine if the orientation changed in a way that requires action. */
+    /*
+    GtkWidget * sep = gtk_bin_get_child(GTK_BIN(p->pwid));
+    if (GTK_IS_VSEPARATOR(sep))
+    {
+        if (p->panel->orientation == GTK_ORIENTATION_HORIZONTAL)
+        return;
+    }
+    else
+    {
+        if (p->panel->orientation == GTK_ORIENTATION_VERTICAL)
+            return;
+    }
+*/
+}
+
+/* Callback when the configuration dialog has recorded a configuration change. */
+static void indicator_apply_configuration(Plugin * p)
+{
+
+    /* IndicatorPlugin * indicator = (IndicatorPlugin *) p->priv;*/
+    
+    /* load 'em */
+       indicator_load_modules(p);
+
+    /* Apply settings. */
+/*
+    if (p->panel->orientation == ORIENT_HORIZ)
+        gtk_widget_set_size_request(p->pwid, sp->size, 2);
+    else
+        gtk_widget_set_size_request(p->pwid, 2, sp->size);
+*/
+}
+
+/* Callback when the configuration dialog is to be shown. */
+static void indicator_configure(Plugin * p, GtkWindow * parent)
+{
+    IndicatorPlugin * indicator = (IndicatorPlugin *) p->priv;
+    GtkWidget * dlg = create_generic_config_dlg(
+        _(p->class->name),
+        GTK_WIDGET(parent),
+        (GSourceFunc) indicator_apply_configuration, (gpointer) p,
+        _("Indicator Applications"), &indicator->applications, CONF_TYPE_BOOL,
+        _("Clock Indicator"), &indicator->datetime, CONF_TYPE_BOOL,
+        _("Messaging Menu"), &indicator->messages, CONF_TYPE_BOOL,
+        _("Network Menu"), &indicator->network, CONF_TYPE_BOOL,
+        _("Session Menu"), &indicator->session, CONF_TYPE_BOOL,
+        _("Sound Menu"), &indicator->sound, CONF_TYPE_BOOL,
+        NULL);
+    gtk_widget_set_size_request(GTK_WIDGET(dlg), 300, -1);
+    gtk_window_present(GTK_WINDOW(dlg));
+}
+
+/* Callback when the configuration is to be saved. */
+static void indicator_save_configuration(Plugin * p, FILE * fp)
+{
+    IndicatorPlugin * indicator= (IndicatorPlugin *) p->priv;
+    lxpanel_put_int(fp, "applications", indicator->applications);
+    lxpanel_put_int(fp, "datetime", indicator->datetime);
+    lxpanel_put_int(fp, "messages", indicator->messages);
+    lxpanel_put_int(fp, "network", indicator->network);
+    lxpanel_put_int(fp, "session", indicator->session);
+    lxpanel_put_int(fp, "sound", indicator->sound);
+}
+
+/* Plugin descriptor. */
+PluginClass indicator_plugin_class = {
+
+    PLUGINCLASS_VERSIONING,
+
+    type : "indicator",
+    name : N_("Indicator applets"),
+    version: "1.0",
+    description : N_("Add indicator applets to the panel"),
+
+    constructor : indicator_constructor,
+    destructor  : indicator_destructor,
+    config : indicator_configure,
+    save : indicator_save_configuration,
+    panel_configuration_changed : indicator_panel_configuration_changed
+};