aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am215
-rw-r--r--src/indicator-messages-status-provider-0.5.pc.in.in15
-rw-r--r--src/messages-service.c40
-rw-r--r--src/status-items.c314
-rw-r--r--src/status-items.h38
-rw-r--r--src/status-provider-emesene.c346
-rw-r--r--src/status-provider-emesene.h56
-rw-r--r--src/status-provider-mc5.c308
-rw-r--r--src/status-provider-mc5.h56
-rw-r--r--src/status-provider-mc5.list1
-rw-r--r--src/status-provider-pidgin.c433
-rw-r--r--src/status-provider-pidgin.h56
-rw-r--r--src/status-provider-pidgin.list1
-rw-r--r--src/status-provider-telepathy.c385
-rw-r--r--src/status-provider-telepathy.h56
-rw-r--r--src/status-provider-telepathy.list1
-rw-r--r--src/status-provider.c101
-rw-r--r--src/status-provider.h81
18 files changed, 2492 insertions, 11 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 8597d77..c631436 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,6 +1,12 @@
+BUILT_SOURCES =
+EXTRA_DIST =
+CLEANFILES =
+DISTCLEANFILES =
+
libexec_PROGRAMS = indicator-messages-service
+
######################################
# Building the messages indicator
######################################
@@ -44,7 +50,11 @@ indicator_messages_service_SOURCES = \
seen-db.c \
seen-db.h \
dirs.h \
- dbus-data.h
+ dbus-data.h \
+ \
+ status-items.c \
+ status-items.h
+
indicator_messages_service_CFLAGS = \
$(APPLET_CFLAGS) \
-Wall \
@@ -52,8 +62,12 @@ indicator_messages_service_CFLAGS = \
-Wl,-z,defs \
-Wl,--as-needed \
-Werror \
- -DG_LOG_DOMAIN=\"Indicator-Messages\"
-indicator_messages_service_LDADD = $(APPLET_LIBS)
+ -DG_LOG_DOMAIN=\"Indicator-Messages\" \
+ -DSTATUS_PROVIDER_DIR=\"$(STATUS_PROVIDER_DIR)\"
+
+indicator_messages_service_LDADD = \
+ $(APPLET_LIBS) \
+ libindicator-messages-status-provider.la
gen-%.xml.h: %.xml
@echo "Building $@ from $<"
@@ -65,13 +79,198 @@ gen-%.xml.c: %.xml
@sed -e "s:\":\\\\\":g" -e s:^:\": -e s:\$$:\\\\n\": $< >> $@
@echo ";" >> $@
-BUILT_SOURCES = \
+BUILT_SOURCES += \
gen-messages-service.xml.h \
gen-messages-service.xml.c
-CLEANFILES = \
- $(BUILT_SOURCES)
-
-EXTRA_DIST = \
+EXTRA_DIST += \
messages-service.xml
+######################################
+# Status Provider Library
+######################################
+
+STATUS_PROVIDER_API_VERSION = 1
+STATUS_PROVIDER_DIR = $(libexecdir)/status-providers/$(STATUS_PROVIDER_API_VERSION)
+statusprovidersdir = $(STATUS_PROVIDER_DIR)
+statusproviders_LTLIBRARIES =
+
+EXTRA_DIST += \
+ indicator-messages-status-provider-0.5.pc.in.in
+CLEANFILES += \
+ indicator-messages-status-provider-0.5.pc
+
+pkgconfig_DATA = indicator-messages-status-provider-0.5.pc
+pkgconfigdir = $(libdir)/pkgconfig
+
+%.pc: %.pc.in
+ sed \
+ -e "s|\@status_provider_dir\@|$(STATUS_PROVIDER_DIR)|" \
+ -e "s|\@status_provider_api_version\@|$(STATUS_PROVIDER_API_VERSION)|" \
+ $< > $@
+
+lib_LTLIBRARIES = \
+ libindicator-messages-status-provider.la
+
+libindicator_messages_status_provider_la_HEADERS = \
+ status-provider.h
+
+libindicator_messages_status_provider_la_SOURCES = \
+ $(libindicator_messages_status_provider_HEADERS) \
+ status-provider.c
+
+libindicator_messages_status_provider_ladir = \
+ $(includedir)/libindicator-messages-status-provider-$(STATUS_PROVIDER_API_VERSION)/
+
+libindicator_messages_status_provider_la_LDFLAGS = \
+ -version-info $(STATUS_PROVIDER_API_VERSION):0:0 \
+ -no-undefined \
+ -export-symbols-regex "^[^_].*"
+
+libindicator_messages_status_provider_la_LIBADD = \
+ $(APPLET_LIBS)
+
+libindicator_messages_status_provider_la_CFLAGS = \
+ $(APPLET_CFLAGS) \
+ -Wall -Werror
+
+######################################
+# Status provider: Pidgin
+######################################
+
+statusproviders_LTLIBRARIES += libpidgin.la
+libpidgin_la_SOURCES = \
+ status-provider-pidgin.h \
+ status-provider-pidgin.c \
+ status-provider-pidgin-marshal.h \
+ status-provider-pidgin-marshal.c
+libpidgin_la_CFLAGS = \
+ $(APPLET_CFLAGS) \
+ $(STATUS_PROVIDER_PIDGIN_CFLAGS) \
+ -Wall -Werror \
+ -DG_LOG_DOMAIN=\"Status-Provider-Pidgin\"
+libpidgin_la_LIBADD = \
+ libindicator-messages-status-provider.la \
+ $(APPLET_LIBS) \
+ $(STATUS_PROVIDER_PIDGIN_LIBS)
+libpidgin_la_LDFLAGS = -module -avoid-version
+
+status-provider-pidgin-marshal.h: $(srcdir)/status-provider-pidgin.list
+ glib-genmarshal --header \
+ --prefix=_status_provider_pidgin_marshal $(srcdir)/status-provider-pidgin.list \
+ > status-provider-pidgin-marshal.h
+
+status-provider-pidgin-marshal.c: $(srcdir)/status-provider-pidgin.list
+ glib-genmarshal --body \
+ --prefix=_status_provider_pidgin_marshal $(srcdir)/status-provider-pidgin.list \
+ > status-provider-pidgin-marshal.c
+
+BUILT_SOURCES += \
+ status-provider-pidgin-marshal.h \
+ status-provider-pidgin-marshal.c
+
+EXTRA_DIST += \
+ status-provider-pidgin.list
+
+######################################
+# Status provider: Mission Control 4
+######################################
+
+statusproviders_LTLIBRARIES += libtelepathy.la
+libtelepathy_la_SOURCES = \
+ status-provider-telepathy.h \
+ status-provider-telepathy.c \
+ status-provider-telepathy-marshal.h \
+ status-provider-telepathy-marshal.c
+libtelepathy_la_CFLAGS = \
+ $(APPLET_CFLAGS) \
+ $(STATUS_PROVIDER_TELEPATHY_CFLAGS) \
+ -Wall -Werror \
+ -DG_LOG_DOMAIN=\"Status-Provider-Telepathy\"
+libtelepathy_la_LIBADD = \
+ libindicator-messages-status-provider.la \
+ $(APPLET_LIBS) \
+ $(STATUS_PROVIDER_TELEPATHY_LIBS)
+libtelepathy_la_LDFLAGS = -module -avoid-version
+
+status-provider-telepathy-marshal.h: $(srcdir)/status-provider-telepathy.list
+ glib-genmarshal --header \
+ --prefix=_status_provider_telepathy_marshal $(srcdir)/status-provider-telepathy.list \
+ > status-provider-telepathy-marshal.h
+
+status-provider-telepathy-marshal.c: $(srcdir)/status-provider-telepathy.list
+ glib-genmarshal --body \
+ --prefix=_status_provider_telepathy_marshal $(srcdir)/status-provider-telepathy.list \
+ > status-provider-telepathy-marshal.c
+
+BUILT_SOURCES += \
+ status-provider-telepathy-marshal.h \
+ status-provider-telepathy-marshal.c
+
+EXTRA_DIST += \
+ status-provider-telepathy.list
+
+######################################
+# Status provider: Mission Control 5
+######################################
+
+statusproviders_LTLIBRARIES += libmc5.la
+libmc5_la_SOURCES = \
+ status-provider-mc5.h \
+ status-provider-mc5.c \
+ status-provider-mc5-marshal.h \
+ status-provider-mc5-marshal.c
+libmc5_la_CFLAGS = \
+ $(APPLET_CFLAGS) \
+ $(STATUS_PROVIDER_MC5_CFLAGS) \
+ -Wall -Werror \
+ -DG_LOG_DOMAIN=\"Status-Provider-MC5\"
+libmc5_la_LIBADD = \
+ libindicator-messages-status-provider.la \
+ $(APPLET_LIBS) \
+ $(STATUS_PROVIDER_MC5_LIBS)
+libmc5_la_LDFLAGS = -module -avoid-version
+
+status-provider-mc5-marshal.h: $(srcdir)/status-provider-mc5.list
+ glib-genmarshal --header \
+ --prefix=_status_provider_mc5_marshal $(srcdir)/status-provider-mc5.list \
+ > status-provider-mc5-marshal.h
+
+status-provider-mc5-marshal.c: $(srcdir)/status-provider-mc5.list
+ glib-genmarshal --body \
+ --prefix=_status_provider_mc5_marshal $(srcdir)/status-provider-mc5.list \
+ > status-provider-mc5-marshal.c
+
+BUILT_SOURCES += \
+ status-provider-mc5-marshal.h \
+ status-provider-mc5-marshal.c
+
+EXTRA_DIST += \
+ status-provider-mc5.list
+
+######################################
+# Status provider: Emesene
+######################################
+
+statusproviders_LTLIBRARIES += libemesene.la
+libemesene_la_SOURCES = \
+ status-provider-emesene.h \
+ status-provider-emesene.c
+libemesene_la_CFLAGS = \
+ $(APPLET_CFLAGS) \
+ $(STATUS_PROVIDER_EMESENE_CFLAGS) \
+ -Wall -Werror \
+ -DG_LOG_DOMAIN=\"Status-Provider-Emesene\"
+libemesene_la_LIBADD = \
+ libindicator-messages-status-provider.la \
+ $(APPLET_LIBS) \
+ $(STATUS_PROVIDER_EMESENE_LIBS)
+libemesene_la_LDFLAGS = -module -avoid-version
+
+######################################
+# Extras
+######################################
+
+CLEANFILES += \
+ $(BUILT_SOURCES)
+
diff --git a/src/indicator-messages-status-provider-0.5.pc.in.in b/src/indicator-messages-status-provider-0.5.pc.in.in
new file mode 100644
index 0000000..3fe4cf2
--- /dev/null
+++ b/src/indicator-messages-status-provider-0.5.pc.in.in
@@ -0,0 +1,15 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+bindir=@bindir@
+includedir=@includedir@
+
+statusproviderdir=@status_provider_dir@
+
+Cflags: -I${includedir}/indicator-messages-status-provider-0.@status_provider_api_version@
+Requires: gobject-2.0
+Libs: -L${libdir} -lindicator-messages-status-provider
+
+Name: indicator-messages-status-provider
+Description: Status providers for the indicator-messages menu.
+Version: @VERSION@
diff --git a/src/messages-service.c b/src/messages-service.c
index e3352e8..63549e3 100644
--- a/src/messages-service.c
+++ b/src/messages-service.c
@@ -40,6 +40,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#include "dirs.h"
#include "messages-service-dbus.h"
#include "seen-db.h"
+#include "status-items.h"
static IndicatorService * service = NULL;
static IndicateListener * listener = NULL;
@@ -47,6 +48,7 @@ static GList * serverList = NULL;
static GList * launcherList = NULL;
static DbusmenuMenuitem * root_menuitem = NULL;
+static DbusmenuMenuitem * status_separator = NULL;
static GMainLoop * mainloop = NULL;
static MessageServiceDbus * dbus_interface = NULL;
@@ -836,6 +838,11 @@ resort_menu (DbusmenuMenuitem * menushell)
DbusmenuMenuitem * last_separator = NULL;
g_debug("Reordering Menu:");
+
+ if (DBUSMENU_IS_MENUITEM(status_separator)) {
+ position = dbusmenu_menuitem_get_position(status_separator, root_menuitem) + 1;
+ g_debug("\tPriming with location of status separator: %d", position);
+ }
for (serverentry = serverList; serverentry != NULL; serverentry = serverentry->next) {
serverList_t * si = (serverList_t *)serverentry->data;
@@ -1432,13 +1439,21 @@ service_shutdown (IndicatorService * service, gpointer user_data)
return;
}
+static void
+status_update_callback (void)
+{
+ return;
+}
+
/* Oh, if you don't know what main() is for
we really shouldn't be talking. */
int
main (int argc, char ** argv)
{
+ /* Glib init */
g_type_init();
+ /* Create the Indicator Service interface */
service = indicator_service_new_version(INDICATOR_MESSAGES_DBUS_NAME, 1);
g_signal_connect(service, INDICATOR_SERVICE_SIGNAL_SHUTDOWN, G_CALLBACK(service_shutdown), NULL);
@@ -1448,31 +1463,50 @@ main (int argc, char ** argv)
bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
textdomain (GETTEXT_PACKAGE);
+ /* Create the Seen DB */
seen_db_init();
+ /* Bring up the service DBus interface */
dbus_interface = message_service_dbus_new();
- listener = indicate_listener_ref_default();
- serverList = NULL;
-
+ /* Build the base menu */
root_menuitem = dbusmenu_menuitem_new();
DbusmenuServer * server = dbusmenu_server_new(INDICATOR_MESSAGES_DBUS_OBJECT);
dbusmenu_server_set_root(server, root_menuitem);
+ /* Add status items */
+ GList * statusitems = status_items_build(&status_update_callback);
+ while (statusitems != NULL) {
+ dbusmenu_menuitem_child_append(root_menuitem, DBUSMENU_MENUITEM(statusitems->data));
+ statusitems = g_list_next(statusitems);
+ }
+ status_separator = dbusmenu_menuitem_new();
+ dbusmenu_menuitem_property_set(status_separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR);
+ dbusmenu_menuitem_child_append(root_menuitem, status_separator);
+
+ /* Start up the libindicate listener */
+ listener = indicate_listener_ref_default();
+ serverList = NULL;
+
g_signal_connect(listener, INDICATE_LISTENER_SIGNAL_INDICATOR_ADDED, G_CALLBACK(indicator_added), root_menuitem);
g_signal_connect(listener, INDICATE_LISTENER_SIGNAL_INDICATOR_REMOVED, G_CALLBACK(indicator_removed), root_menuitem);
g_signal_connect(listener, INDICATE_LISTENER_SIGNAL_SERVER_ADDED, G_CALLBACK(server_added), root_menuitem);
g_signal_connect(listener, INDICATE_LISTENER_SIGNAL_SERVER_REMOVED, G_CALLBACK(server_removed), root_menuitem);
+ /* Find launchers by looking through the config directories
+ in the idle loop */
g_idle_add(blacklist_init, NULL);
g_idle_add(build_launchers, SYSTEM_APPS_DIR);
g_idle_add(build_launchers, SYSTEM_APPS_DIR_OLD);
gchar * userdir = g_build_filename(g_get_user_config_dir(), USER_APPS_DIR, NULL);
g_idle_add(build_launchers, userdir);
+ /* Let's run a mainloop */
mainloop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(mainloop);
+ /* Clean up */
+ status_items_cleanup();
g_free(userdir);
return 0;
diff --git a/src/status-items.c b/src/status-items.c
new file mode 100644
index 0000000..25a7aa2
--- /dev/null
+++ b/src/status-items.c
@@ -0,0 +1,314 @@
+/*
+Code to build and maintain the status adjustment menuitems.
+
+Copyright 2011 Canonical Ltd.
+
+Authors:
+ Ted Gould <ted@canonical.com>
+
+This program is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License version 3, as published
+by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranties of
+MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+#include <libdbusmenu-glib/dbusmenu-glib.h>
+
+#include "status-items.h"
+#include "status-provider.h"
+
+static const gchar * status_strings [STATUS_PROVIDER_STATUS_LAST] = {
+ /* STATUS_PROVIDER_STATUS_ONLINE, */ N_("Available"),
+ /* STATUS_PROVIDER_STATUS_AWAY, */ N_("Away"),
+ /* STATUS_PROVIDER_STATUS_DND */ N_("Busy"),
+ /* STATUS_PROVIDER_STATUS_INVISIBLE */ N_("Invisible"),
+ /* STATUS_PROVIDER_STATUS_OFFLINE, */ N_("Offline"),
+ /* STATUS_PROVIDER_STATUS_DISCONNECTED*/ N_("Offline")
+};
+
+static const gchar * status_icons[STATUS_PROVIDER_STATUS_LAST] = {
+ /* STATUS_PROVIDER_STATUS_ONLINE, */ "user-available",
+ /* STATUS_PROVIDER_STATUS_AWAY, */ "user-away",
+ /* STATUS_PROVIDER_STATUS_DND, */ "user-busy",
+ /* STATUS_PROVIDER_STATUS_INVISIBLE, */ "user-invisible",
+ /* STATUS_PROVIDER_STATUS_OFFLINE */ "user-offline",
+ /* STATUS_PROVIDER_STATUS_DISCONNECTED */ "user-offline-panel"
+};
+
+static const gchar * panel_icons[STATUS_PROVIDER_STATUS_LAST] = {
+ /* STATUS_PROVIDER_STATUS_ONLINE, */ "indicator-messages-user-available",
+ /* STATUS_PROVIDER_STATUS_AWAY, */ "indicator-messages-user-away",
+ /* STATUS_PROVIDER_STATUS_DND, */ "indicator-messages-user-busy",
+ /* STATUS_PROVIDER_STATUS_INVISIBLE, */ "indicator-messages-user-invisible",
+ /* STATUS_PROVIDER_STATUS_OFFLINE */ "indicator-messages-user-offline",
+ /* STATUS_PROVIDER_STATUS_DISCONNECTED */ "indicator-messages-user-disconnected"
+};
+
+static const gchar * panel_active_icons[STATUS_PROVIDER_STATUS_LAST] = {
+ /* STATUS_PROVIDER_STATUS_ONLINE, */ "indicator-messages-new-user-available",
+ /* STATUS_PROVIDER_STATUS_AWAY, */ "indicator-messages-new-user-away",
+ /* STATUS_PROVIDER_STATUS_DND, */ "indicator-messages-new-user-busy",
+ /* STATUS_PROVIDER_STATUS_INVISIBLE, */ "indicator-messages-new-user-invisible",
+ /* STATUS_PROVIDER_STATUS_OFFLINE */ "indicator-messages-new-user-offline",
+ /* STATUS_PROVIDER_STATUS_DISCONNECTED */ "indicator-messages-new-user-disconnected"
+};
+
+/* Prototypes */
+static gboolean provider_directory_parse (gpointer dir);
+static gboolean load_status_provider (gpointer dir);
+static void user_status_change (DbusmenuMenuitem * item, guint timestamp, gpointer pstatus);
+
+/* Globals */
+static StatusProviderStatus current_status = STATUS_PROVIDER_STATUS_DISCONNECTED;
+static GList * menuitems = NULL;
+static GList * status_providers = NULL;
+static StatusUpdateFunc update_func = NULL;
+
+/* Build the inital status items and start kicking off the async code
+ for handling all the statuses */
+GList *
+status_items_build (StatusUpdateFunc status_update_func)
+{
+ int i;
+ for (i = STATUS_PROVIDER_STATUS_ONLINE; i < STATUS_PROVIDER_STATUS_DISCONNECTED; i++) {
+ DbusmenuMenuitem * item = dbusmenu_menuitem_new();
+
+ dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, _(status_strings[i]));
+ dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_ICON_NAME, status_icons[i]);
+
+ dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
+ dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_ENABLED, FALSE);
+
+ dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE, DBUSMENU_MENUITEM_TOGGLE_RADIO);
+ dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED);
+
+ g_signal_connect(G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(user_status_change), GINT_TO_POINTER(i));
+
+ menuitems = g_list_append(menuitems, item);
+ }
+
+ update_func = status_update_func;
+
+ const gchar * status_providers_env = g_getenv("INDICATOR_MESSAGES_STATUS_PROVIDER_DIR");
+ if (status_providers_env == NULL) {
+ g_idle_add(provider_directory_parse, STATUS_PROVIDER_DIR);
+ } else {
+ g_idle_add(provider_directory_parse, (gpointer)status_providers_env);
+ }
+
+ return menuitems;
+}
+
+/* Clean up our globals and stop with all this allocation
+ of memory */
+void
+status_items_cleanup (void)
+{
+ while (status_providers != NULL) {
+ StatusProvider * sprovider = STATUS_PROVIDER(status_providers->data);
+ g_object_unref(sprovider);
+ status_providers = g_list_remove(status_providers, sprovider);
+ }
+
+ return;
+}
+
+/* Get the icon that should be shown on the panel */
+const gchar *
+status_current_panel_icon (gboolean alert)
+{
+ if (alert) {
+ return panel_active_icons[current_status];
+ } else {
+ return panel_icons[current_status];
+ }
+}
+
+/* Update status from all the providers */
+static void
+update_status (void)
+{
+ StatusProviderStatus status = STATUS_PROVIDER_STATUS_DISCONNECTED;
+ GList * provider;
+
+ for (provider = status_providers; provider != NULL; provider = g_list_next(provider)) {
+ StatusProviderStatus localstatus = status_provider_get_status(STATUS_PROVIDER(provider->data));
+
+ if (localstatus < status) {
+ status = localstatus;
+ }
+ }
+
+ if (status == current_status) {
+ return;
+ }
+
+ current_status = status;
+
+ if (update_func != NULL) {
+ update_func();
+ }
+
+ GList * menu;
+ int i;
+ for (menu = menuitems, i = 0; menu != NULL && i < STATUS_PROVIDER_STATUS_DISCONNECTED; menu = g_list_next(menu), i++) {
+ /* If we're the seleced status or if we're disconnected
+ show the user that we're offline */
+ if (i == current_status || (current_status == STATUS_PROVIDER_STATUS_DISCONNECTED && i == STATUS_PROVIDER_STATUS_OFFLINE)) {
+ dbusmenu_menuitem_property_set_int(DBUSMENU_MENUITEM(menu->data), DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED);
+ } else {
+ dbusmenu_menuitem_property_set_int(DBUSMENU_MENUITEM(menu->data), DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED);
+ }
+
+ if (current_status == STATUS_PROVIDER_STATUS_DISCONNECTED) {
+ dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(menu->data), DBUSMENU_MENUITEM_PROP_ENABLED, FALSE);
+ } else {
+ dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(menu->data), DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
+ }
+ }
+
+ return;
+}
+
+/* Handle the user requesting a status change */
+static void
+user_status_change (DbusmenuMenuitem * item, guint timestamp, gpointer pstatus)
+{
+ StatusProviderStatus status = GPOINTER_TO_INT(pstatus);
+ GList * provider;
+
+ /* Set each provider to this status */
+ for (provider = status_providers; provider != NULL; provider = g_list_next(provider)) {
+ status_provider_set_status(STATUS_PROVIDER(provider->data), status);
+ }
+
+ /* See what we really are now */
+ update_status();
+ return;
+}
+
+/* Start parsing a directory and setting up the entires in the idle loop */
+static gboolean
+provider_directory_parse (gpointer directory)
+{
+ const gchar * dirname = (const gchar *)directory;
+ g_debug("Looking for status providers in: %s", dirname);
+
+ if (!g_file_test(dirname, G_FILE_TEST_EXISTS)) {
+ return FALSE;
+ }
+
+ GDir * dir = g_dir_open(dirname, 0, NULL);
+ if (dir == NULL) {
+ return FALSE;
+ }
+
+ const gchar * name;
+ while ((name = g_dir_read_name(dir)) != NULL) {
+ if (!g_str_has_suffix(name, G_MODULE_SUFFIX)) {
+ continue;
+ }
+
+ gchar * fullname = g_build_filename(dirname, name, NULL);
+ g_idle_add(load_status_provider, fullname);
+ }
+
+ g_dir_close(dir);
+
+ return FALSE;
+}
+
+/* Close the module as an idle function so that we know
+ it's all cleaned up */
+static gboolean
+module_destroy_in_idle_helper (gpointer data)
+{
+ GModule * module = (GModule *)data;
+ if (module != NULL) {
+ g_debug("Unloading module: %s", g_module_name(module));
+ g_module_close(module);
+ }
+ return FALSE;
+}
+
+/* Set up an idle function to close the module */
+static void
+module_destroy_in_idle (gpointer data)
+{
+ g_idle_add_full(G_PRIORITY_LOW, module_destroy_in_idle_helper, data, NULL);
+ return;
+}
+
+/* Load a particular status provider */
+static gboolean
+load_status_provider (gpointer dir)
+{
+ gchar * provider = (gchar *)dir;
+
+ if (!g_file_test(provider, G_FILE_TEST_EXISTS)) {
+ goto exit_final;
+ }
+
+ g_debug("Loading status provider: %s", provider);
+
+ GModule * module;
+
+ module = g_module_open(provider, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
+ if (module == NULL) {
+ g_warning("Unable to module for: %s", provider);
+ goto exit_module_fail;
+ }
+
+ /* Got it */
+ GType (*type_func) (void);
+ if (!g_module_symbol(module, STATUS_PROVIDER_EXPORT_S, (gpointer *)&type_func)) {
+ g_warning("Unable to find type symbol in: %s", provider);
+ goto exit_module_fail;
+ }
+
+ GType provider_type = type_func();
+ if (provider_type == 0) {
+ g_warning("Unable to create type from: %s", provider);
+ goto exit_module_fail;
+ }
+
+ StatusProvider * sprovider = STATUS_PROVIDER(g_object_new(provider_type, NULL));
+ if (sprovider == NULL) {
+ g_warning("Unable to build provider from: %s", provider);
+ goto exit_module_fail;
+ }
+
+ /* On update let's talk to all of them and create the aggregate
+ value to export */
+ g_signal_connect(G_OBJECT(sprovider), STATUS_PROVIDER_SIGNAL_STATUS_CHANGED, G_CALLBACK(update_status), NULL);
+
+ /* Attach the module object to the status provider so
+ that when the status provider is free'd the module
+ is close automatically. */
+ g_object_set_data_full(G_OBJECT(sprovider), "status-provider-module", module, module_destroy_in_idle);
+
+ status_providers = g_list_prepend(status_providers, sprovider);
+
+ /* Force and update every time just so we know we're
+ in a consistent state*/
+ update_status();
+
+ goto exit_final;
+
+exit_module_fail:
+ g_module_close(module);
+
+exit_final:
+ g_free(provider);
+ return FALSE;
+}
diff --git a/src/status-items.h b/src/status-items.h
new file mode 100644
index 0000000..fe7900c
--- /dev/null
+++ b/src/status-items.h
@@ -0,0 +1,38 @@
+/*
+Code to build and maintain the status adjustment menuitems.
+
+Copyright 2011 Canonical Ltd.
+
+Authors:
+ Ted Gould <ted@canonical.com>
+
+This program is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License version 3, as published
+by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranties of
+MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __STATUS_ITEMS_H__
+#define __STATUS_ITEMS_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef void (*StatusUpdateFunc) (void);
+
+GList * status_items_build (StatusUpdateFunc update_func);
+const gchar * status_current_panel_icon (gboolean alert);
+void status_items_cleanup (void);
+
+G_END_DECLS
+
+#endif /* __STATUS_ITEMS_H__ */
+
diff --git a/src/status-provider-emesene.c b/src/status-provider-emesene.c
new file mode 100644
index 0000000..29a8a22
--- /dev/null
+++ b/src/status-provider-emesene.c
@@ -0,0 +1,346 @@
+/*
+A small wrapper utility to load indicators and put them as menu items
+into the gnome-panel using it's applet interface.
+
+Copyright 2011 Canonical Ltd.
+
+Authors:
+ Stefano Candori <stefano.candori@gmail.com>
+
+This program is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License version 3, as published
+by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranties of
+MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "status-provider.h"
+#include "status-provider-emesene.h"
+
+#include <dbus/dbus-glib.h>
+
+typedef enum {
+ EM_STATUS_ONLINE,
+ EM_STATUS_OFFLINE,
+ EM_STATUS_BUSY,
+ EM_STATUS_AWAY,
+ EM_STATUS_IDLE
+} em_status_t;
+
+static const StatusProviderStatus em_to_sp_map[] = {
+ /* EM_STATUS_ONLINE, */ STATUS_PROVIDER_STATUS_ONLINE,
+ /* EM_STATUS_OFFLINE, */ STATUS_PROVIDER_STATUS_OFFLINE,
+ /* EM_STATUS_BUSY, */ STATUS_PROVIDER_STATUS_DND,
+ /* EM_STATUS_AWAY, */ STATUS_PROVIDER_STATUS_AWAY,
+ /* EM_STATUS_IDLE, */ STATUS_PROVIDER_STATUS_AWAY
+};
+
+static const em_status_t sp_to_em_map[STATUS_PROVIDER_STATUS_LAST] = {
+ /* STATUS_PROVIDER_STATUS_ONLINE, */ EM_STATUS_ONLINE,
+ /* STATUS_PROVIDER_STATUS_AWAY, */ EM_STATUS_AWAY,
+ /* STATUS_PROVIDER_STATUS_DND */ EM_STATUS_BUSY,
+ /* STATUS_PROVIDER_STATUS_INVISIBLE*/ EM_STATUS_OFFLINE,
+ /* STATUS_PROVIDER_STATUS_OFFLINE */ EM_STATUS_OFFLINE,
+ /* STATUS_PROVIDER_STATUS_DISCONNECTED*/ EM_STATUS_OFFLINE
+};
+
+typedef struct _StatusProviderEmesenePrivate StatusProviderEmesenePrivate;
+struct _StatusProviderEmesenePrivate {
+ DBusGProxy * proxy;
+ DBusGProxy * dbus_proxy;
+ em_status_t em_status;
+};
+
+#define STATUS_PROVIDER_EMESENE_GET_PRIVATE(o) \
+(G_TYPE_INSTANCE_GET_PRIVATE ((o), STATUS_PROVIDER_EMESENE_TYPE, StatusProviderEmesenePrivate))
+
+/* Prototypes */
+/* GObject stuff */
+static void status_provider_emesene_class_init (StatusProviderEmeseneClass *klass);
+static void status_provider_emesene_init (StatusProviderEmesene *self);
+static void status_provider_emesene_dispose (GObject *object);
+static void status_provider_emesene_finalize (GObject *object);
+/* Internal Funcs */
+static void set_status (StatusProvider * sp, StatusProviderStatus status);
+static StatusProviderStatus get_status (StatusProvider * sp);
+static void setup_emesene_proxy (StatusProviderEmesene * self);
+static void dbus_namechange (DBusGProxy * proxy, const gchar * name, const gchar * prev, const gchar * new, StatusProviderEmesene * self);
+
+G_DEFINE_TYPE (StatusProviderEmesene, status_provider_emesene, STATUS_PROVIDER_TYPE);
+
+STATUS_PROVIDER_EXPORT_TYPE(STATUS_PROVIDER_EMESENE_TYPE)
+
+static void
+status_provider_emesene_class_init (StatusProviderEmeseneClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (StatusProviderEmesenePrivate));
+
+ object_class->dispose = status_provider_emesene_dispose;
+ object_class->finalize = status_provider_emesene_finalize;
+
+ StatusProviderClass * spclass = STATUS_PROVIDER_CLASS(klass);
+
+ spclass->set_status = set_status;
+ spclass->get_status = get_status;
+
+ return;
+}
+
+static void
+status_cb (DBusGProxy * proxy, DBusGProxyCall * call, gpointer userdata)
+{
+ StatusProviderEmesene * spe = STATUS_PROVIDER_EMESENE(userdata);
+ StatusProviderEmesenePrivate * priv = STATUS_PROVIDER_EMESENE_GET_PRIVATE(spe);
+
+ GError * error = NULL;
+ gint status = 0;
+ if (!dbus_g_proxy_end_call(proxy, call, &error, G_TYPE_INT, &status, G_TYPE_INVALID)) {
+ g_warning("Unable to get status from Emesene: %s", error->message);
+ g_error_free(error);
+ return;
+ }
+
+ priv->em_status = status;
+ g_signal_emit(G_OBJECT(spe), STATUS_PROVIDER_SIGNAL_STATUS_CHANGED_ID, 0, em_to_sp_map[priv->em_status], TRUE);
+ return;
+}
+
+static void
+changed_status (DBusGProxy * proxy, gint status, StatusProviderEmesene * spe)
+{
+ StatusProviderEmesenePrivate * priv = STATUS_PROVIDER_EMESENE_GET_PRIVATE(spe);
+ g_debug("Emesene changed status to %d", status);
+ priv->em_status = status;
+ g_signal_emit(G_OBJECT(spe), STATUS_PROVIDER_SIGNAL_STATUS_CHANGED_ID, 0, em_to_sp_map[priv->em_status], TRUE);
+ return;
+}
+
+static void
+proxy_destroy (DBusGProxy * proxy, StatusProviderEmesene * spe)
+{
+ StatusProviderEmesenePrivate * priv = STATUS_PROVIDER_EMESENE_GET_PRIVATE(spe);
+
+ priv->proxy = NULL;
+ priv->em_status = EM_STATUS_OFFLINE;
+
+ g_signal_emit(G_OBJECT(spe), STATUS_PROVIDER_SIGNAL_STATUS_CHANGED_ID, 0, em_to_sp_map[priv->em_status], TRUE);
+ return;
+}
+
+static void
+status_provider_emesene_init (StatusProviderEmesene *self)
+{
+ StatusProviderEmesenePrivate * priv = STATUS_PROVIDER_EMESENE_GET_PRIVATE(self);
+
+ priv->proxy = NULL;
+ priv->em_status = EM_STATUS_OFFLINE;
+
+ DBusGConnection * bus = dbus_g_bus_get(DBUS_BUS_SESSION, NULL);
+ g_return_if_fail(bus != NULL); /* Can't do anymore DBus stuff without this,
+ all non-DBus stuff should be done */
+
+ GError * error = NULL;
+
+ /* Set up the dbus Proxy */
+ priv->dbus_proxy = dbus_g_proxy_new_for_name_owner (bus,
+ DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS,
+ &error);
+ if (error != NULL) {
+ g_warning("Unable to connect to DBus events: %s", error->message);
+ g_error_free(error);
+ return;
+ }
+
+ /* Configure the name owner changing */
+ dbus_g_proxy_add_signal(priv->dbus_proxy, "NameOwnerChanged",
+ G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
+ G_TYPE_INVALID);
+ dbus_g_proxy_connect_signal(priv->dbus_proxy, "NameOwnerChanged",
+ G_CALLBACK(dbus_namechange),
+ self, NULL);
+
+ setup_emesene_proxy(self);
+
+ return;
+}
+
+/* Watch to see if the Emesene comes up on Dbus */
+static void
+dbus_namechange (DBusGProxy * proxy, const gchar * name, const gchar * prev, const gchar * new, StatusProviderEmesene * self)
+{
+ g_return_if_fail(name != NULL);
+ g_return_if_fail(new != NULL);
+
+ if (g_strcmp0(name, "org.emesene.Service") == 0) {
+ setup_emesene_proxy(self);
+ }
+ return;
+}
+
+/* Setup the Emesene proxy so that we can talk to it
+ and get signals from it. */
+static void
+setup_emesene_proxy (StatusProviderEmesene * self)
+{
+ StatusProviderEmesenePrivate * priv = STATUS_PROVIDER_EMESENE_GET_PRIVATE(self);
+
+ if (priv->proxy != NULL) {
+ g_debug("Doh!We were asked to set up a Emesene proxy when we already had one.");
+ return;
+ }
+
+ DBusGConnection * bus = dbus_g_bus_get(DBUS_BUS_SESSION, NULL);
+ g_return_if_fail(bus != NULL); /* Can't do anymore DBus stuff without this,
+ all non-DBus stuff should be done */
+
+ GError * error = NULL;
+
+ /* Set up the Emesene Proxy */
+ priv->proxy = dbus_g_proxy_new_for_name_owner (bus,
+ "org.emesene.Service",
+ "/org/emesene/Service",
+ "org.emesene.Service",
+ &error);
+ /* Report any errors */
+ if (error != NULL) {
+ g_debug("Unable to get Emesene proxy: %s", error->message);
+ g_error_free(error);
+ }
+
+ /* If we have a proxy, let's start using it */
+ if (priv->proxy != NULL) {
+ /* Set the proxy to NULL if it's destroyed */
+ g_object_add_weak_pointer (G_OBJECT(priv->proxy), (gpointer *)&priv->proxy);
+ /* If it's destroyed, let's clean up as well */
+ g_signal_connect(G_OBJECT(priv->proxy), "destroy",
+ G_CALLBACK(proxy_destroy), self);
+
+ /* Watching for the status change coming from the
+ Emesene side of things. */
+ g_debug("Adding Emesene Signals");
+ dbus_g_proxy_add_signal (priv->proxy,
+ "status_changed",
+ G_TYPE_INT,
+ G_TYPE_INVALID);
+ dbus_g_proxy_connect_signal(priv->proxy,
+ "status_changed",
+ G_CALLBACK(changed_status),
+ (void *)self,
+ NULL);
+
+ /* Get the current status to update our cached
+ value of the status. */
+ dbus_g_proxy_begin_call(priv->proxy,
+ "get_status",
+ status_cb,
+ self,
+ NULL,
+ G_TYPE_INVALID);
+ }
+
+ return;
+}
+
+static void
+status_provider_emesene_dispose (GObject *object)
+{
+ StatusProviderEmesenePrivate * priv = STATUS_PROVIDER_EMESENE_GET_PRIVATE(object);
+
+ if (priv->proxy != NULL) {
+ g_object_unref(priv->proxy);
+ priv->proxy = NULL;
+ }
+
+ G_OBJECT_CLASS (status_provider_emesene_parent_class)->dispose (object);
+ return;
+}
+
+static void
+status_provider_emesene_finalize (GObject *object)
+{
+
+ G_OBJECT_CLASS (status_provider_emesene_parent_class)->finalize (object);
+ return;
+}
+
+/**
+ status_provider_emesene_new:
+
+ Creates a new #StatusProviderEmesene object. No parameters or anything
+ like that. Just a convience function.
+
+ Return value: A new instance of #StatusProviderEmesene
+*/
+StatusProvider *
+status_provider_emesene_new (void)
+{
+ return STATUS_PROVIDER(g_object_new(STATUS_PROVIDER_EMESENE_TYPE, NULL));
+}
+
+/* Takes the status provided generically for Status providers
+ and turns it into a Emesene status and sends it to Emesene. */
+static void
+set_status (StatusProvider * sp, StatusProviderStatus status)
+{
+ g_return_if_fail(IS_STATUS_PROVIDER_EMESENE(sp));
+ StatusProviderEmesenePrivate * priv = STATUS_PROVIDER_EMESENE_GET_PRIVATE(sp);
+
+ g_debug("Emesene set status to %d", status);
+ if (priv->proxy == NULL) {
+ return;
+ }
+
+ priv->em_status = sp_to_em_map[status];
+
+ gboolean ret = FALSE;
+ GError * error = NULL;
+
+ ret = dbus_g_proxy_call(priv->proxy,
+ "set_status", &error,
+ G_TYPE_INT, priv->em_status,
+ G_TYPE_INVALID,
+ G_TYPE_INVALID);
+
+ if (!ret) {
+ if (error != NULL) {
+ g_warning("Emesene unable to change to status: %s", error->message);
+ g_error_free(error);
+ } else {
+ g_warning("Emesene unable to change to status");
+ }
+ error = NULL;
+ }
+
+ g_signal_emit(G_OBJECT(sp), STATUS_PROVIDER_SIGNAL_STATUS_CHANGED_ID, 0, em_to_sp_map[priv->em_status], TRUE);
+ return;
+}
+
+/* Takes the cached Emesene status and makes it into the generic
+ Status provider status. If there is no Emesene proxy then it
+ returns the disconnected state. */
+static StatusProviderStatus
+get_status (StatusProvider * sp)
+{
+ g_return_val_if_fail(IS_STATUS_PROVIDER_EMESENE(sp), STATUS_PROVIDER_STATUS_DISCONNECTED);
+ StatusProviderEmesenePrivate * priv = STATUS_PROVIDER_EMESENE_GET_PRIVATE(sp);
+
+ if (priv->proxy == NULL) {
+ return STATUS_PROVIDER_STATUS_DISCONNECTED;
+ }
+
+ return em_to_sp_map[priv->em_status];
+}
diff --git a/src/status-provider-emesene.h b/src/status-provider-emesene.h
new file mode 100644
index 0000000..2309684
--- /dev/null
+++ b/src/status-provider-emesene.h
@@ -0,0 +1,56 @@
+/*
+A small wrapper utility to load indicators and put them as menu items
+into the gnome-panel using it's applet interface.
+
+Copyright 20011 Canonical Ltd.
+
+Authors:
+ Stefano Candori <stefano.candori@gmail.com>
+
+This program is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License version 3, as published
+by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranties of
+MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __STATUS_PROVIDER_EMESENE_H__
+#define __STATUS_PROVIDER_EMESENE_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "status-provider.h"
+
+G_BEGIN_DECLS
+
+#define STATUS_PROVIDER_EMESENE_TYPE (status_provider_emesene_get_type ())
+#define STATUS_PROVIDER_EMESENE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), STATUS_PROVIDER_EMESENE_TYPE, StatusProviderEmesene))
+#define STATUS_PROVIDER_EMESENE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), STATUS_PROVIDER_EMESENE_TYPE, StatusProviderEmeseneClass))
+#define IS_STATUS_PROVIDER_EMESENE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), STATUS_PROVIDER_EMESENE_TYPE))
+#define IS_STATUS_PROVIDER_EMESENE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), STATUS_PROVIDER_EMESENE_TYPE))
+#define STATUS_PROVIDER_EMESENE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), STATUS_PROVIDER_EMESENE_TYPE, StatusProviderEmeseneClass))
+
+
+typedef struct _StatusProviderEmeseneClass StatusProviderEmeseneClass;
+struct _StatusProviderEmeseneClass {
+ StatusProviderClass parent_class;
+};
+
+typedef struct _StatusProviderEmesene StatusProviderEmesene;
+struct _StatusProviderEmesene {
+ StatusProvider parent;
+};
+
+GType status_provider_emesene_get_type (void);
+StatusProvider * status_provider_emesene_new (void);
+
+G_END_DECLS
+
+#endif
diff --git a/src/status-provider-mc5.c b/src/status-provider-mc5.c
new file mode 100644
index 0000000..e70496c
--- /dev/null
+++ b/src/status-provider-mc5.c
@@ -0,0 +1,308 @@
+/*
+A small wrapper utility to load indicators and put them as menu items
+into the gnome-panel using it's applet interface.
+
+Copyright 2009 Canonical Ltd.
+
+Authors:
+ Ted Gould <ted@canonical.com>
+
+This program is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License version 3, as published
+by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranties of
+MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <telepathy-glib/account-manager.h>
+
+#include "status-provider.h"
+#include "status-provider-mc5.h"
+#include "status-provider-mc5-marshal.h"
+
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-bindings.h>
+
+static gchar * sp_to_mc_map[STATUS_PROVIDER_STATUS_LAST] = {
+ /* STATUS_PROVIDER_STATUS_ONLINE, */ "available",
+ /* STATUS_PROVIDER_STATUS_AWAY, */ "away",
+ /* STATUS_PROVIDER_STATUS_DND */ "busy",
+ /* STATUS_PROVIDER_STATUS_INVISIBLE*/ "hidden",
+ /* STATUS_PROVIDER_STATUS_OFFLINE */ "offline",
+ /* STATUS_PROVIDER_STATUS_DISCONNECTED*/NULL
+};
+
+static TpConnectionPresenceType sp_to_tp_map[STATUS_PROVIDER_STATUS_LAST] = {
+ /* STATUS_PROVIDER_STATUS_ONLINE, */ TP_CONNECTION_PRESENCE_TYPE_AVAILABLE,
+ /* STATUS_PROVIDER_STATUS_AWAY, */ TP_CONNECTION_PRESENCE_TYPE_AWAY,
+ /* STATUS_PROVIDER_STATUS_DND */ TP_CONNECTION_PRESENCE_TYPE_BUSY,
+ /* STATUS_PROVIDER_STATUS_INVISIBLE*/ TP_CONNECTION_PRESENCE_TYPE_HIDDEN,
+ /* STATUS_PROVIDER_STATUS_OFFLINE */ TP_CONNECTION_PRESENCE_TYPE_OFFLINE,
+ /* STATUS_PROVIDER_STATUS_DISCONNECTED*/ TP_CONNECTION_PRESENCE_TYPE_UNSET
+};
+
+static StatusProviderStatus tp_to_sp_map[TP_CONNECTION_PRESENCE_TYPE_ERROR + 1] = {
+ /* TP_CONNECTION_PRESENCE_TYPE_UNSET */ STATUS_PROVIDER_STATUS_DISCONNECTED,
+ /* TP_CONNECTION_PRESENCE_TYPE_OFFLINE */ STATUS_PROVIDER_STATUS_OFFLINE,
+ /* TP_CONNECTION_PRESENCE_TYPE_AVAILABLE */ STATUS_PROVIDER_STATUS_ONLINE,
+ /* TP_CONNECTION_PRESENCE_TYPE_AWAY */ STATUS_PROVIDER_STATUS_AWAY,
+ /* TP_CONNECTION_PRESENCE_TYPE_EXTENDED_AWAY */ STATUS_PROVIDER_STATUS_AWAY,
+ /* TP_CONNECTION_PRESENCE_TYPE_HIDDEN */ STATUS_PROVIDER_STATUS_INVISIBLE,
+ /* TP_CONNECTION_PRESENCE_TYPE_BUSY */ STATUS_PROVIDER_STATUS_DND,
+ /* TP_CONNECTION_PRESENCE_TYPE_UNKNOWN */ STATUS_PROVIDER_STATUS_DISCONNECTED,
+ /* TP_CONNECTION_PRESENCE_TYPE_ERROR */ STATUS_PROVIDER_STATUS_DISCONNECTED
+};
+
+typedef struct _StatusProviderMC5Private StatusProviderMC5Private;
+struct _StatusProviderMC5Private {
+ TpAccountManager * manager;
+ StatusProviderStatus status;
+ DBusGProxy * dbus_proxy;
+};
+
+#define STATUS_PROVIDER_MC5_GET_PRIVATE(o) \
+(G_TYPE_INSTANCE_GET_PRIVATE ((o), STATUS_PROVIDER_MC5_TYPE, StatusProviderMC5Private))
+#define MC5_WELL_KNOWN_NAME "org.freedesktop.Telepathy.AccountManager"
+
+/* Prototypes */
+/* GObject stuff */
+static void status_provider_mc5_class_init (StatusProviderMC5Class *klass);
+static void status_provider_mc5_init (StatusProviderMC5 *self);
+static void status_provider_mc5_dispose (GObject *object);
+static void status_provider_mc5_finalize (GObject *object);
+/* Internal Funcs */
+static void set_status (StatusProvider * sp, StatusProviderStatus status);
+static StatusProviderStatus get_status (StatusProvider * sp);
+static void presence_changed (TpAccountManager * eam, guint type, const gchar * type_str, const gchar * message, StatusProviderMC5 * sp);
+static void dbus_namechange (DBusGProxy * proxy, const gchar * name, const gchar * prev, const gchar * new, StatusProviderMC5 * self);
+static void mc5_exists_cb (DBusGProxy * proxy, gboolean exists, GError * error, gpointer userdata);
+
+G_DEFINE_TYPE (StatusProviderMC5, status_provider_mc5, STATUS_PROVIDER_TYPE);
+
+STATUS_PROVIDER_EXPORT_TYPE(STATUS_PROVIDER_MC5_TYPE)
+
+/* Create the class. We over ride a few functions but nothing
+ really shocking. Most interesting is the set and get status. */
+static void
+status_provider_mc5_class_init (StatusProviderMC5Class *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (StatusProviderMC5Private));
+
+ object_class->dispose = status_provider_mc5_dispose;
+ object_class->finalize = status_provider_mc5_finalize;
+
+ StatusProviderClass * spclass = STATUS_PROVIDER_CLASS(klass);
+
+ spclass->set_status = set_status;
+ spclass->get_status = get_status;
+
+ return;
+}
+
+/* Build our telepathy account manager instance if we don't
+ have one. */
+static void
+build_eam (StatusProviderMC5 * self)
+{
+ StatusProviderMC5Private * priv = STATUS_PROVIDER_MC5_GET_PRIVATE(self);
+
+ if (priv->manager != NULL) {
+ return;
+ }
+
+ priv->manager = tp_account_manager_dup();
+ g_signal_connect(G_OBJECT(priv->manager), "most-available-presence-changed", G_CALLBACK(presence_changed), self);
+
+ return;
+}
+
+/* Creating an instance of the status provider. We set the variables
+ and create an TpAccountManager object. It does all the hard
+ work in this module of tracking MissionControl and enumerating the
+ accounts and all that jazz. */
+static void
+status_provider_mc5_init (StatusProviderMC5 *self)
+{
+ StatusProviderMC5Private * priv = STATUS_PROVIDER_MC5_GET_PRIVATE(self);
+
+ priv->status = STATUS_PROVIDER_STATUS_DISCONNECTED;
+ priv->manager = NULL;
+
+ DBusGConnection * bus = dbus_g_bus_get(DBUS_BUS_SESSION, NULL);
+ g_return_if_fail(bus != NULL); /* Can't do anymore DBus stuff without this,
+ all non-DBus stuff should be done */
+
+ GError * error = NULL;
+
+ /* Set up the dbus Proxy */
+ priv->dbus_proxy = dbus_g_proxy_new_for_name_owner (bus,
+ DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS,
+ &error);
+ if (error != NULL) {
+ g_warning("Unable to connect to DBus events: %s", error->message);
+ g_error_free(error);
+ return;
+ }
+
+ /* Configure the name owner changing */
+ dbus_g_proxy_add_signal(priv->dbus_proxy, "NameOwnerChanged",
+ G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
+ G_TYPE_INVALID);
+ dbus_g_proxy_connect_signal(priv->dbus_proxy, "NameOwnerChanged",
+ G_CALLBACK(dbus_namechange),
+ self, NULL);
+
+ org_freedesktop_DBus_name_has_owner_async(priv->dbus_proxy, MC5_WELL_KNOWN_NAME, mc5_exists_cb, self);
+
+ return;
+}
+
+/* Unref the account manager and move on. Sadly, we're
+ leaving the show. */
+static void
+status_provider_mc5_dispose (GObject *object)
+{
+ StatusProviderMC5Private * priv = STATUS_PROVIDER_MC5_GET_PRIVATE(object);
+
+ if (priv->manager != NULL) {
+ g_object_unref(priv->manager);
+ priv->manager = NULL;
+ }
+
+ if (priv->dbus_proxy != NULL) {
+ g_object_unref(priv->dbus_proxy);
+ priv->dbus_proxy = NULL;
+ }
+
+ G_OBJECT_CLASS (status_provider_mc5_parent_class)->dispose (object);
+ return;
+}
+
+/* Pass to superclass */
+static void
+status_provider_mc5_finalize (GObject *object)
+{
+
+ G_OBJECT_CLASS (status_provider_mc5_parent_class)->finalize (object);
+ return;
+}
+
+/* Watch for MC5 Coming on and off the bus. */
+static void
+dbus_namechange (DBusGProxy * proxy, const gchar * name, const gchar * prev, const gchar * new, StatusProviderMC5 * self)
+{
+ /* g_debug("DBUS NAMECHANGE: %s %s %s", name, prev, new); */
+
+ if (prev[0] == '\0' && g_strcmp0(name, MC5_WELL_KNOWN_NAME) == 0) {
+ g_debug("MC5 Coming online");
+ build_eam(self);
+ }
+ if (new[0] == '\0' && g_strcmp0(name, MC5_WELL_KNOWN_NAME) == 0) {
+ g_debug("MC5 going offline");
+ StatusProviderMC5Private * priv = STATUS_PROVIDER_MC5_GET_PRIVATE(self);
+ if (priv->manager != NULL) {
+ g_object_unref(priv->manager);
+ priv->manager = NULL;
+ }
+
+ priv->status = STATUS_PROVIDER_STATUS_DISCONNECTED;
+ g_signal_emit(G_OBJECT(self), STATUS_PROVIDER_SIGNAL_STATUS_CHANGED_ID, 0, priv->status, TRUE);
+ }
+
+ return;
+}
+
+/* Callback for the Dbus command to do HasOwner on
+ the MC5 service. If it exists, we want to have an
+ account manager. */
+static void
+mc5_exists_cb (DBusGProxy * proxy, gboolean exists, GError * error, gpointer userdata)
+{
+ if (error) {
+ g_warning("Unable to check if MC5 is running: %s", error->message);
+ return;
+ }
+
+ if (exists) {
+ build_eam(STATUS_PROVIDER_MC5(userdata));
+ }
+
+ return;
+}
+
+/**
+ status_provider_mc5_new:
+
+ Creates a new #StatusProviderMC5 object. No parameters or anything
+ like that. Just a convience function.
+
+ Return value: A new instance of #StatusProviderMC5
+*/
+StatusProvider *
+status_provider_mc5_new (void)
+{
+ return STATUS_PROVIDER(g_object_new(STATUS_PROVIDER_MC5_TYPE, NULL));
+}
+
+/* Setting the status in the empathy account manager. We're
+ basically requesting a global status. This may or may not
+ get applied to all accounts. It's really the best we can
+ hope to do. */
+static void
+set_status (StatusProvider * sp, StatusProviderStatus status)
+{
+ StatusProviderMC5Private * priv = STATUS_PROVIDER_MC5_GET_PRIVATE(sp);
+
+ build_eam(STATUS_PROVIDER_MC5(sp));
+ tp_account_manager_set_all_requested_presences(priv->manager, sp_to_tp_map[status], sp_to_mc_map[status], "");
+
+ return;
+}
+
+/* Gets the status, uses the cached value that we have. Asking
+ would just be painful. */
+static StatusProviderStatus
+get_status (StatusProvider * sp)
+{
+ g_return_val_if_fail(IS_STATUS_PROVIDER_MC5(sp), STATUS_PROVIDER_STATUS_DISCONNECTED);
+ StatusProviderMC5Private * priv = STATUS_PROVIDER_MC5_GET_PRIVATE(sp);
+
+ if (priv->manager == NULL) {
+ return STATUS_PROVIDER_STATUS_DISCONNECTED;
+ }
+
+ return priv->status;
+}
+
+/* A signal handler for when the TpAccountManager believes
+ that the global status has changed. It roughly calculates this
+ by finding the most available of all accounts that are active. */
+static void
+presence_changed (TpAccountManager * eam, guint type, const gchar * type_str, const gchar * message, StatusProviderMC5 * sp)
+{
+ StatusProviderMC5Private * priv = STATUS_PROVIDER_MC5_GET_PRIVATE(sp);
+
+ g_debug("MC5 Status changed: %d %s %s", type, type_str, message);
+
+ if (priv->status != tp_to_sp_map[type]) {
+ priv->status = tp_to_sp_map[type];
+ g_signal_emit(G_OBJECT(sp), STATUS_PROVIDER_SIGNAL_STATUS_CHANGED_ID, 0, priv->status, TRUE);
+ }
+
+ return;
+}
+
diff --git a/src/status-provider-mc5.h b/src/status-provider-mc5.h
new file mode 100644
index 0000000..4d5659d
--- /dev/null
+++ b/src/status-provider-mc5.h
@@ -0,0 +1,56 @@
+/*
+A small wrapper utility to load indicators and put them as menu items
+into the gnome-panel using it's applet interface.
+
+Copyright 2009 Canonical Ltd.
+
+Authors:
+ Ted Gould <ted@canonical.com>
+
+This program is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License version 3, as published
+by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranties of
+MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __STATUS_PROVIDER_MC5_H__
+#define __STATUS_PROVIDER_MC5_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "status-provider.h"
+
+G_BEGIN_DECLS
+
+#define STATUS_PROVIDER_MC5_TYPE (status_provider_mc5_get_type ())
+#define STATUS_PROVIDER_MC5(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), STATUS_PROVIDER_MC5_TYPE, StatusProviderMC5))
+#define STATUS_PROVIDER_MC5_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), STATUS_PROVIDER_MC5_TYPE, StatusProviderMC5Class))
+#define IS_STATUS_PROVIDER_MC5(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), STATUS_PROVIDER_MC5_TYPE))
+#define IS_STATUS_PROVIDER_MC5_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), STATUS_PROVIDER_MC5_TYPE))
+#define STATUS_PROVIDER_MC5_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), STATUS_PROVIDER_MC5_TYPE, StatusProviderMC5Class))
+
+
+typedef struct _StatusProviderMC5Class StatusProviderMC5Class;
+struct _StatusProviderMC5Class {
+ StatusProviderClass parent_class;
+};
+
+typedef struct _StatusProviderMC5 StatusProviderMC5;
+struct _StatusProviderMC5 {
+ StatusProvider parent;
+};
+
+GType status_provider_mc5_get_type (void);
+StatusProvider * status_provider_mc5_new (void);
+
+G_END_DECLS
+
+#endif
diff --git a/src/status-provider-mc5.list b/src/status-provider-mc5.list
new file mode 100644
index 0000000..5ab45bf
--- /dev/null
+++ b/src/status-provider-mc5.list
@@ -0,0 +1 @@
+VOID:UINT,STRING
diff --git a/src/status-provider-pidgin.c b/src/status-provider-pidgin.c
new file mode 100644
index 0000000..6c73d56
--- /dev/null
+++ b/src/status-provider-pidgin.c
@@ -0,0 +1,433 @@
+/*
+A small wrapper utility to load indicators and put them as menu items
+into the gnome-panel using it's applet interface.
+
+Copyright 2009 Canonical Ltd.
+
+Authors:
+ Ted Gould <ted@canonical.com>
+
+This program is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License version 3, as published
+by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranties of
+MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "status-provider.h"
+#include "status-provider-pidgin.h"
+#include "status-provider-pidgin-marshal.h"
+
+#include <dbus/dbus-glib.h>
+
+typedef enum {
+ PG_STATUS_UNKNOWN,
+ PG_STATUS_OFFLINE,
+ PG_STATUS_AVAILABLE,
+ PG_STATUS_UNAVAILABLE,
+ PG_STATUS_INVISIBLE,
+ PG_STATUS_AWAY,
+ PG_STATUS_EXTENDEND_AWAY,
+ PG_STATUS_MOBILE,
+ PG_STATUS_TUNE
+} pg_status_t;
+
+static const StatusProviderStatus pg_to_sp_map[] = {
+ /* PG_STATUS_UNKNOWN, */ STATUS_PROVIDER_STATUS_OFFLINE,
+ /* PG_STATUS_OFFLINE, */ STATUS_PROVIDER_STATUS_OFFLINE,
+ /* PG_STATUS_AVAILABLE, */ STATUS_PROVIDER_STATUS_ONLINE,
+ /* PG_STATUS_UNAVAILABLE, */ STATUS_PROVIDER_STATUS_DND,
+ /* PG_STATUS_INVISIBLE, */ STATUS_PROVIDER_STATUS_INVISIBLE,
+ /* PG_STATUS_AWAY, */ STATUS_PROVIDER_STATUS_AWAY,
+ /* PG_STATUS_EXTENDEND_AWAY, */ STATUS_PROVIDER_STATUS_AWAY,
+ /* PG_STATUS_MOBILE, */ STATUS_PROVIDER_STATUS_OFFLINE,
+ /* PG_STATUS_TUNE */ STATUS_PROVIDER_STATUS_OFFLINE
+};
+
+static const pg_status_t sp_to_pg_map[STATUS_PROVIDER_STATUS_LAST] = {
+ /* STATUS_PROVIDER_STATUS_ONLINE, */ PG_STATUS_AVAILABLE,
+ /* STATUS_PROVIDER_STATUS_AWAY, */ PG_STATUS_AWAY,
+ /* STATUS_PROVIDER_STATUS_DND */ PG_STATUS_UNAVAILABLE,
+ /* STATUS_PROVIDER_STATUS_INVISIBLE*/ PG_STATUS_INVISIBLE,
+ /* STATUS_PROVIDER_STATUS_OFFLINE */ PG_STATUS_OFFLINE,
+ /* STATUS_PROVIDER_STATUS_DISCONNECTED*/ PG_STATUS_OFFLINE
+};
+
+typedef struct _StatusProviderPidginPrivate StatusProviderPidginPrivate;
+struct _StatusProviderPidginPrivate {
+ DBusGProxy * proxy;
+ DBusGProxy * dbus_proxy;
+ pg_status_t pg_status;
+};
+
+#define STATUS_PROVIDER_PIDGIN_GET_PRIVATE(o) \
+(G_TYPE_INSTANCE_GET_PRIVATE ((o), STATUS_PROVIDER_PIDGIN_TYPE, StatusProviderPidginPrivate))
+
+/* Prototypes */
+/* GObject stuff */
+static void status_provider_pidgin_class_init (StatusProviderPidginClass *klass);
+static void status_provider_pidgin_init (StatusProviderPidgin *self);
+static void status_provider_pidgin_dispose (GObject *object);
+static void status_provider_pidgin_finalize (GObject *object);
+/* Internal Funcs */
+static void set_status (StatusProvider * sp, StatusProviderStatus status);
+static StatusProviderStatus get_status (StatusProvider * sp);
+static void setup_pidgin_proxy (StatusProviderPidgin * self);
+static void dbus_namechange (DBusGProxy * proxy, const gchar * name, const gchar * prev, const gchar * new, StatusProviderPidgin * self);
+
+G_DEFINE_TYPE (StatusProviderPidgin, status_provider_pidgin, STATUS_PROVIDER_TYPE);
+
+STATUS_PROVIDER_EXPORT_TYPE(STATUS_PROVIDER_PIDGIN_TYPE)
+
+static void
+status_provider_pidgin_class_init (StatusProviderPidginClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (StatusProviderPidginPrivate));
+
+ object_class->dispose = status_provider_pidgin_dispose;
+ object_class->finalize = status_provider_pidgin_finalize;
+
+ StatusProviderClass * spclass = STATUS_PROVIDER_CLASS(klass);
+
+ spclass->set_status = set_status;
+ spclass->get_status = get_status;
+
+ return;
+}
+
+static void
+type_cb (DBusGProxy * proxy, DBusGProxyCall * call, gpointer userdata)
+{
+ GError * error = NULL;
+ gint status = 0;
+ if (!dbus_g_proxy_end_call(proxy, call, &error, G_TYPE_INT, &status, G_TYPE_INVALID)) {
+ g_warning("Unable to get type from Pidgin: %s", error->message);
+ g_error_free(error);
+ return;
+ }
+
+ StatusProviderPidginPrivate * priv = STATUS_PROVIDER_PIDGIN_GET_PRIVATE(userdata);
+ if (status != priv->pg_status) {
+ priv->pg_status = status;
+
+ g_signal_emit(G_OBJECT(userdata), STATUS_PROVIDER_SIGNAL_STATUS_CHANGED_ID, 0, pg_to_sp_map[priv->pg_status], TRUE);
+ }
+
+ return;
+}
+
+static void
+saved_status_to_type (StatusProviderPidgin * spp, gint savedstatus)
+{
+ StatusProviderPidginPrivate * priv = STATUS_PROVIDER_PIDGIN_GET_PRIVATE(spp);
+
+ g_debug("Pidgin figuring out type for %d", savedstatus);
+ dbus_g_proxy_begin_call(priv->proxy,
+ "PurpleSavedstatusGetType", type_cb, spp, NULL,
+ G_TYPE_INT, savedstatus, G_TYPE_INVALID);
+
+ return;
+}
+
+static void
+savedstatus_cb (DBusGProxy * proxy, DBusGProxyCall * call, gpointer userdata)
+{
+ GError * error = NULL;
+ gint status = 0;
+ if (!dbus_g_proxy_end_call(proxy, call, &error, G_TYPE_INT, &status, G_TYPE_INVALID)) {
+ g_warning("Unable to get saved status from Pidgin: %s", error->message);
+ g_error_free(error);
+ return;
+ }
+
+ saved_status_to_type(STATUS_PROVIDER_PIDGIN(userdata), status);
+ return;
+}
+
+
+static void
+changed_status (DBusGProxy * proxy, gint savedstatus, GError ** error, StatusProviderPidgin * spp)
+{
+ saved_status_to_type(spp, savedstatus);
+ return;
+}
+
+static void
+proxy_destroy (DBusGProxy * proxy, StatusProviderPidgin * spp)
+{
+ StatusProviderPidginPrivate * priv = STATUS_PROVIDER_PIDGIN_GET_PRIVATE(spp);
+
+ priv->proxy = NULL;
+ priv->pg_status = PG_STATUS_OFFLINE;
+
+ g_signal_emit(G_OBJECT(spp), STATUS_PROVIDER_SIGNAL_STATUS_CHANGED_ID, 0, pg_to_sp_map[priv->pg_status], TRUE);
+ return;
+}
+
+static void
+status_provider_pidgin_init (StatusProviderPidgin *self)
+{
+ StatusProviderPidginPrivate * priv = STATUS_PROVIDER_PIDGIN_GET_PRIVATE(self);
+
+ priv->proxy = NULL;
+ priv->pg_status = PG_STATUS_OFFLINE;
+
+ DBusGConnection * bus = dbus_g_bus_get(DBUS_BUS_SESSION, NULL);
+ g_return_if_fail(bus != NULL); /* Can't do anymore DBus stuff without this,
+ all non-DBus stuff should be done */
+
+ GError * error = NULL;
+
+ /* Set up the dbus Proxy */
+ priv->dbus_proxy = dbus_g_proxy_new_for_name_owner (bus,
+ DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS,
+ &error);
+ if (error != NULL) {
+ g_warning("Unable to connect to DBus events: %s", error->message);
+ g_error_free(error);
+ return;
+ }
+
+ /* Configure the name owner changing */
+ dbus_g_proxy_add_signal(priv->dbus_proxy, "NameOwnerChanged",
+ G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
+ G_TYPE_INVALID);
+ dbus_g_proxy_connect_signal(priv->dbus_proxy, "NameOwnerChanged",
+ G_CALLBACK(dbus_namechange),
+ self, NULL);
+
+ setup_pidgin_proxy(self);
+
+ return;
+}
+
+/* Watch to see if the Pidgin comes up on Dbus */
+static void
+dbus_namechange (DBusGProxy * proxy, const gchar * name, const gchar * prev, const gchar * new, StatusProviderPidgin * self)
+{
+ g_return_if_fail(name != NULL);
+ g_return_if_fail(new != NULL);
+
+ if (g_strcmp0(name, "im.pidgin.purple.PurpleService") == 0) {
+ setup_pidgin_proxy(self);
+ }
+ return;
+}
+
+/* Setup the Pidgin proxy so that we can talk to it
+ and get signals from it. */
+static void
+setup_pidgin_proxy (StatusProviderPidgin * self)
+{
+ StatusProviderPidginPrivate * priv = STATUS_PROVIDER_PIDGIN_GET_PRIVATE(self);
+
+ if (priv->proxy != NULL) {
+ g_debug("Odd, we were asked to set up a Pidgin proxy when we already had one.");
+ return;
+ }
+
+ DBusGConnection * bus = dbus_g_bus_get(DBUS_BUS_SESSION, NULL);
+ g_return_if_fail(bus != NULL); /* Can't do anymore DBus stuff without this,
+ all non-DBus stuff should be done */
+
+ GError * error = NULL;
+
+ /* Set up the Pidgin Proxy */
+ priv->proxy = dbus_g_proxy_new_for_name_owner (bus,
+ "im.pidgin.purple.PurpleService",
+ "/im/pidgin/purple/PurpleObject",
+ "im.pidgin.purple.PurpleInterface",
+ &error);
+ /* Report any errors */
+ if (error != NULL) {
+ g_debug("Unable to get Pidgin proxy: %s", error->message);
+ g_error_free(error);
+ }
+
+ /* If we have a proxy, let's start using it */
+ if (priv->proxy != NULL) {
+ /* Set the proxy to NULL if it's destroyed */
+ g_object_add_weak_pointer (G_OBJECT(priv->proxy), (gpointer *)&priv->proxy);
+ /* If it's destroyed, let's clean up as well */
+ g_signal_connect(G_OBJECT(priv->proxy), "destroy",
+ G_CALLBACK(proxy_destroy), self);
+
+ /* Watching for the status change coming from the
+ Pidgin side of things. */
+ g_debug("Adding Pidgin Signals");
+ dbus_g_object_register_marshaller(_status_provider_pidgin_marshal_VOID__INT_INT,
+ G_TYPE_NONE,
+ G_TYPE_INT,
+ G_TYPE_INT,
+ G_TYPE_INVALID);
+ dbus_g_proxy_add_signal (priv->proxy,
+ "SavedstatusChanged",
+ G_TYPE_INT,
+ G_TYPE_INT,
+ G_TYPE_INVALID);
+ dbus_g_proxy_connect_signal(priv->proxy,
+ "SavedstatusChanged",
+ G_CALLBACK(changed_status),
+ (void *)self,
+ NULL);
+
+ /* Get the current status to update our cached
+ value of the status. */
+ dbus_g_proxy_begin_call(priv->proxy,
+ "PurpleSavedstatusGetCurrent",
+ savedstatus_cb,
+ self,
+ NULL,
+ G_TYPE_INVALID);
+ }
+
+ return;
+}
+
+static void
+status_provider_pidgin_dispose (GObject *object)
+{
+ StatusProviderPidginPrivate * priv = STATUS_PROVIDER_PIDGIN_GET_PRIVATE(object);
+
+ if (priv->proxy != NULL) {
+ g_object_unref(priv->proxy);
+ priv->proxy = NULL;
+ }
+
+ G_OBJECT_CLASS (status_provider_pidgin_parent_class)->dispose (object);
+ return;
+}
+
+static void
+status_provider_pidgin_finalize (GObject *object)
+{
+
+ G_OBJECT_CLASS (status_provider_pidgin_parent_class)->finalize (object);
+ return;
+}
+
+/**
+ status_provider_pidgin_new:
+
+ Creates a new #StatusProviderPidgin object. No parameters or anything
+ like that. Just a convience function.
+
+ Return value: A new instance of #StatusProviderPidgin
+*/
+StatusProvider *
+status_provider_pidgin_new (void)
+{
+ return STATUS_PROVIDER(g_object_new(STATUS_PROVIDER_PIDGIN_TYPE, NULL));
+}
+
+/* Takes the status provided generically for Status providers
+ and turns it into a Pidgin status and sends it to Pidgin. */
+static void
+set_status (StatusProvider * sp, StatusProviderStatus status)
+{
+ gchar * message = "";
+
+ g_return_if_fail(IS_STATUS_PROVIDER_PIDGIN(sp));
+ StatusProviderPidginPrivate * priv = STATUS_PROVIDER_PIDGIN_GET_PRIVATE(sp);
+
+ g_debug("\tPidgin set status to %d", status);
+ if (priv->proxy == NULL) {
+ return;
+ }
+
+ priv->pg_status = sp_to_pg_map[status];
+ gint status_val = 0;
+ gboolean ret = FALSE;
+ GError * error = NULL;
+
+ ret = dbus_g_proxy_call(priv->proxy,
+ "PurpleSavedstatusFindTransientByTypeAndMessage", &error,
+ G_TYPE_INT, priv->pg_status,
+ G_TYPE_STRING, message,
+ G_TYPE_INVALID,
+ G_TYPE_INT, &status_val,
+ G_TYPE_INVALID);
+
+ if (!ret) {
+ if (error != NULL) {
+ g_error_free(error);
+ }
+ error = NULL;
+ status_val = 0;
+ g_debug("No Pidgin saved status to apply");
+ }
+
+ if (status_val == 0) {
+ ret = dbus_g_proxy_call(priv->proxy,
+ "PurpleSavedstatusNew", &error,
+ G_TYPE_STRING, message,
+ G_TYPE_INT, priv->pg_status,
+ G_TYPE_INVALID,
+ G_TYPE_INT, &status_val,
+ G_TYPE_INVALID);
+
+ if (!ret) {
+ status_val = 0;
+ if (error != NULL) {
+ g_warning("Unable to create Pidgin status for %d: %s", status, error->message);
+ g_error_free(error);
+ } else {
+ g_warning("Unable to create Pidgin status for %d", status);
+ }
+ error = NULL;
+ }
+ }
+
+ if (status_val == 0) {
+ return;
+ }
+
+ ret = dbus_g_proxy_call(priv->proxy,
+ "PurpleSavedstatusActivate", &error,
+ G_TYPE_INT, status_val,
+ G_TYPE_INVALID,
+ G_TYPE_INVALID);
+
+ if (!ret) {
+ if (error != NULL) {
+ g_warning("Pidgin unable to change to status: %s", error->message);
+ g_error_free(error);
+ } else {
+ g_warning("Pidgin unable to change to status");
+ }
+ error = NULL;
+ }
+
+ g_signal_emit(G_OBJECT(sp), STATUS_PROVIDER_SIGNAL_STATUS_CHANGED_ID, 0, pg_to_sp_map[priv->pg_status], TRUE);
+ return;
+}
+
+/* Takes the cached Pidgin status and makes it into the generic
+ Status provider status. If there is no Pidgin proxy then it
+ returns the disconnected state. */
+static StatusProviderStatus
+get_status (StatusProvider * sp)
+{
+ g_return_val_if_fail(IS_STATUS_PROVIDER_PIDGIN(sp), STATUS_PROVIDER_STATUS_DISCONNECTED);
+ StatusProviderPidginPrivate * priv = STATUS_PROVIDER_PIDGIN_GET_PRIVATE(sp);
+
+ if (priv->proxy == NULL) {
+ return STATUS_PROVIDER_STATUS_DISCONNECTED;
+ }
+
+ return pg_to_sp_map[priv->pg_status];
+}
diff --git a/src/status-provider-pidgin.h b/src/status-provider-pidgin.h
new file mode 100644
index 0000000..54b1718
--- /dev/null
+++ b/src/status-provider-pidgin.h
@@ -0,0 +1,56 @@
+/*
+A small wrapper utility to load indicators and put them as menu items
+into the gnome-panel using it's applet interface.
+
+Copyright 2009 Canonical Ltd.
+
+Authors:
+ Ted Gould <ted@canonical.com>
+
+This program is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License version 3, as published
+by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranties of
+MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __STATUS_PROVIDER_PIDGIN_H__
+#define __STATUS_PROVIDER_PIDGIN_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "status-provider.h"
+
+G_BEGIN_DECLS
+
+#define STATUS_PROVIDER_PIDGIN_TYPE (status_provider_pidgin_get_type ())
+#define STATUS_PROVIDER_PIDGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), STATUS_PROVIDER_PIDGIN_TYPE, StatusProviderPidgin))
+#define STATUS_PROVIDER_PIDGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), STATUS_PROVIDER_PIDGIN_TYPE, StatusProviderPidginClass))
+#define IS_STATUS_PROVIDER_PIDGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), STATUS_PROVIDER_PIDGIN_TYPE))
+#define IS_STATUS_PROVIDER_PIDGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), STATUS_PROVIDER_PIDGIN_TYPE))
+#define STATUS_PROVIDER_PIDGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), STATUS_PROVIDER_PIDGIN_TYPE, StatusProviderPidginClass))
+
+
+typedef struct _StatusProviderPidginClass StatusProviderPidginClass;
+struct _StatusProviderPidginClass {
+ StatusProviderClass parent_class;
+};
+
+typedef struct _StatusProviderPidgin StatusProviderPidgin;
+struct _StatusProviderPidgin {
+ StatusProvider parent;
+};
+
+GType status_provider_pidgin_get_type (void);
+StatusProvider * status_provider_pidgin_new (void);
+
+G_END_DECLS
+
+#endif
diff --git a/src/status-provider-pidgin.list b/src/status-provider-pidgin.list
new file mode 100644
index 0000000..1f953dd
--- /dev/null
+++ b/src/status-provider-pidgin.list
@@ -0,0 +1 @@
+VOID:INT,INT
diff --git a/src/status-provider-telepathy.c b/src/status-provider-telepathy.c
new file mode 100644
index 0000000..c8e89da
--- /dev/null
+++ b/src/status-provider-telepathy.c
@@ -0,0 +1,385 @@
+/*
+A small wrapper utility to load indicators and put them as menu items
+into the gnome-panel using it's applet interface.
+
+Copyright 2009 Canonical Ltd.
+
+Authors:
+ Ted Gould <ted@canonical.com>
+
+This program is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License version 3, as published
+by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranties of
+MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "status-provider.h"
+#include "status-provider-telepathy.h"
+#include "status-provider-telepathy-marshal.h"
+
+#include <dbus/dbus-glib.h>
+
+typedef enum {
+ MC_STATUS_UNSET,
+ MC_STATUS_OFFLINE,
+ MC_STATUS_AVAILABLE,
+ MC_STATUS_AWAY,
+ MC_STATUS_EXTENDED_AWAY,
+ MC_STATUS_HIDDEN,
+ MC_STATUS_DND
+} mc_status_t;
+
+static StatusProviderStatus mc_to_sp_map[] = {
+ /* MC_STATUS_UNSET, */ STATUS_PROVIDER_STATUS_OFFLINE,
+ /* MC_STATUS_OFFLINE, */ STATUS_PROVIDER_STATUS_OFFLINE,
+ /* MC_STATUS_AVAILABLE, */ STATUS_PROVIDER_STATUS_ONLINE,
+ /* MC_STATUS_AWAY, */ STATUS_PROVIDER_STATUS_AWAY,
+ /* MC_STATUS_EXTENDED_AWAY, */ STATUS_PROVIDER_STATUS_AWAY,
+ /* MC_STATUS_HIDDEN, */ STATUS_PROVIDER_STATUS_INVISIBLE,
+ /* MC_STATUS_DND */ STATUS_PROVIDER_STATUS_DND
+};
+
+static mc_status_t sp_to_mc_map[] = {
+ /* STATUS_PROVIDER_STATUS_ONLINE, */ MC_STATUS_AVAILABLE,
+ /* STATUS_PROVIDER_STATUS_AWAY, */ MC_STATUS_AWAY,
+ /* STATUS_PROVIDER_STATUS_DND */ MC_STATUS_DND,
+ /* STATUS_PROVIDER_STATUS_INVISIBLE*/ MC_STATUS_HIDDEN,
+ /* STATUS_PROVIDER_STATUS_OFFLINE */ MC_STATUS_OFFLINE,
+ /* STATUS_PROVIDER_STATUS_DISCONNECTED*/MC_STATUS_OFFLINE
+};
+
+typedef struct _StatusProviderTelepathyPrivate StatusProviderTelepathyPrivate;
+struct _StatusProviderTelepathyPrivate {
+ DBusGProxy * proxy;
+ DBusGProxy * dbus_proxy;
+ mc_status_t mc_status;
+};
+
+#define STATUS_PROVIDER_TELEPATHY_GET_PRIVATE(o) \
+(G_TYPE_INSTANCE_GET_PRIVATE ((o), STATUS_PROVIDER_TELEPATHY_TYPE, StatusProviderTelepathyPrivate))
+
+/* Prototypes */
+/* GObject stuff */
+static void status_provider_telepathy_class_init (StatusProviderTelepathyClass *klass);
+static void status_provider_telepathy_init (StatusProviderTelepathy *self);
+static void status_provider_telepathy_dispose (GObject *object);
+static void status_provider_telepathy_finalize (GObject *object);
+/* Internal Funcs */
+static void build_telepathy_proxy (StatusProviderTelepathy * self);
+static void dbus_namechange (DBusGProxy * proxy, const gchar * name, const gchar * prev, const gchar * new, StatusProviderTelepathy * self);
+static void set_status (StatusProvider * sp, StatusProviderStatus status);
+static StatusProviderStatus get_status (StatusProvider * sp);
+static void changed_status (DBusGProxy * proxy, guint status, gchar * message, StatusProvider * sp);
+static void proxy_destroy (DBusGProxy * proxy, StatusProvider * sp);
+static void get_status_async (DBusGProxy * proxy, DBusGProxyCall * call, gpointer userdata);
+
+G_DEFINE_TYPE (StatusProviderTelepathy, status_provider_telepathy, STATUS_PROVIDER_TYPE);
+
+STATUS_PROVIDER_EXPORT_TYPE(STATUS_PROVIDER_TELEPATHY_TYPE)
+
+static void
+status_provider_telepathy_class_init (StatusProviderTelepathyClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (StatusProviderTelepathyPrivate));
+
+ object_class->dispose = status_provider_telepathy_dispose;
+ object_class->finalize = status_provider_telepathy_finalize;
+
+ StatusProviderClass * spclass = STATUS_PROVIDER_CLASS(klass);
+
+ spclass->set_status = set_status;
+ spclass->get_status = get_status;
+
+ return;
+}
+
+
+static void
+status_provider_telepathy_init (StatusProviderTelepathy *self)
+{
+ StatusProviderTelepathyPrivate * priv = STATUS_PROVIDER_TELEPATHY_GET_PRIVATE(self);
+
+ priv->proxy = NULL;
+ priv->dbus_proxy = NULL;
+ priv->mc_status = MC_STATUS_OFFLINE;
+
+ GError * error = NULL;
+
+ /* Grabbing the session bus */
+ DBusGConnection * bus = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
+ if (bus == NULL) {
+ g_warning("Unable to connect to Session Bus: %s", error == NULL ? "No message" : error->message);
+ g_error_free(error);
+ return;
+ }
+
+ /* Set up the dbus Proxy */
+ priv->dbus_proxy = dbus_g_proxy_new_for_name_owner (bus,
+ DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS,
+ &error);
+ if (error != NULL) {
+ g_warning("Unable to connect to DBus events: %s", error->message);
+ g_error_free(error);
+ return;
+ }
+
+ /* Configure the name owner changing */
+ dbus_g_proxy_add_signal(priv->dbus_proxy, "NameOwnerChanged",
+ G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
+ G_TYPE_INVALID);
+ dbus_g_proxy_connect_signal(priv->dbus_proxy, "NameOwnerChanged",
+ G_CALLBACK(dbus_namechange),
+ self, NULL);
+
+ build_telepathy_proxy(self);
+
+ return;
+}
+
+/* Builds up the proxy to Mission Control and configures all of the
+ signals for getting info from the proxy. Also does a call to get
+ the inital value of the status. */
+static void
+build_telepathy_proxy (StatusProviderTelepathy * self)
+{
+ g_debug("Building Telepathy Proxy");
+ StatusProviderTelepathyPrivate * priv = STATUS_PROVIDER_TELEPATHY_GET_PRIVATE(self);
+
+ if (priv->proxy != NULL) {
+ g_debug("Hmm, being asked to build a proxy we alredy have.");
+ return;
+ }
+
+ GError * error = NULL;
+
+ /* Grabbing the session bus */
+ DBusGConnection * session_bus = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
+ if (session_bus == NULL) {
+ g_warning("Unable to connect to Session Bus: %s", error == NULL ? "No message" : error->message);
+ g_error_free(error);
+ return;
+ }
+
+ /* Get the proxy to Mission Control */
+ priv->proxy = dbus_g_proxy_new_for_name_owner(session_bus,
+ "org.freedesktop.Telepathy.MissionControl",
+ "/org/freedesktop/Telepathy/MissionControl",
+ "org.freedesktop.Telepathy.MissionControl",
+ &error);
+
+ if (priv->proxy != NULL) {
+ /* If it goes, we set the proxy to NULL */
+ g_object_add_weak_pointer (G_OBJECT(priv->proxy), (gpointer *)&priv->proxy);
+ /* And we clean up other variables associated */
+ g_signal_connect(G_OBJECT(priv->proxy), "destroy",
+ G_CALLBACK(proxy_destroy), self);
+
+ /* Set up the signal handler for watching when status changes. */
+ dbus_g_object_register_marshaller(_status_provider_telepathy_marshal_VOID__UINT_STRING,
+ G_TYPE_NONE,
+ G_TYPE_UINT,
+ G_TYPE_STRING,
+ G_TYPE_INVALID);
+ dbus_g_proxy_add_signal (priv->proxy,
+ "PresenceChanged",
+ G_TYPE_UINT,
+ G_TYPE_STRING,
+ G_TYPE_INVALID);
+ dbus_g_proxy_connect_signal(priv->proxy,
+ "PresenceChanged",
+ G_CALLBACK(changed_status),
+ (void *)self,
+ NULL);
+
+ /* Do a get here, to init the status */
+ dbus_g_proxy_begin_call(priv->proxy,
+ "GetStatus",
+ get_status_async,
+ self,
+ NULL,
+ G_TYPE_INVALID);
+ } else {
+ g_warning("Unable to connect to Mission Control");
+ if (error != NULL) {
+ g_error_free(error);
+ }
+ }
+
+ return;
+}
+
+/* Watch to see if the Mission Control comes up on Dbus */
+static void
+dbus_namechange (DBusGProxy * proxy, const gchar * name, const gchar * prev, const gchar * new, StatusProviderTelepathy * self)
+{
+ g_return_if_fail(name != NULL);
+ g_return_if_fail(new != NULL);
+
+ if (g_strcmp0(name, "org.freedesktop.Telepathy.MissionControl") == 0) {
+ build_telepathy_proxy(self);
+ }
+ return;
+}
+
+static void
+status_provider_telepathy_dispose (GObject *object)
+{
+ StatusProviderTelepathyPrivate * priv = STATUS_PROVIDER_TELEPATHY_GET_PRIVATE(object);
+
+ if (priv->proxy != NULL) {
+ g_object_unref(priv->proxy);
+ priv->proxy = NULL;
+ }
+
+ G_OBJECT_CLASS (status_provider_telepathy_parent_class)->dispose (object);
+ return;
+}
+
+static void
+status_provider_telepathy_finalize (GObject *object)
+{
+
+ G_OBJECT_CLASS (status_provider_telepathy_parent_class)->finalize (object);
+ return;
+}
+
+/**
+ status_provider_telepathy_new:
+
+ Creates a new #StatusProviderTelepathy object. No parameters or anything
+ like that. Just a convience function.
+
+ Return value: A new instance of #StatusProviderTelepathy
+*/
+StatusProvider *
+status_provider_telepathy_new (void)
+{
+ return STATUS_PROVIDER(g_object_new(STATUS_PROVIDER_TELEPATHY_TYPE, NULL));
+}
+
+static void
+set_status (StatusProvider * sp, StatusProviderStatus status)
+{
+ StatusProviderTelepathyPrivate * priv = STATUS_PROVIDER_TELEPATHY_GET_PRIVATE(sp);
+ if (priv->proxy == NULL) {
+ priv->mc_status = MC_STATUS_OFFLINE;
+ return;
+ }
+
+ priv->mc_status = sp_to_mc_map[status];
+
+ guint mcstatus = MC_STATUS_UNSET;
+ gboolean ret = FALSE;
+ GError * error = NULL;
+
+ ret = dbus_g_proxy_call(priv->proxy,
+ "GetPresence", &error,
+ G_TYPE_INVALID,
+ G_TYPE_UINT, &priv->mc_status,
+ G_TYPE_INVALID);
+
+ /* If we can't get the get call to work, let's not set */
+ if (!ret) {
+ if (error != NULL) {
+ g_error_free(error);
+ }
+ return;
+ }
+
+ /* If the get call doesn't return a status, that means that there
+ are no clients connected. We don't want to connect them by telling
+ MC that we're going online -- we'd like to be more passive than that. */
+ if (mcstatus == MC_STATUS_UNSET) {
+ return;
+ }
+
+ ret = dbus_g_proxy_call(priv->proxy,
+ "SetPresence", &error,
+ G_TYPE_UINT, priv->mc_status,
+ G_TYPE_STRING, "",
+ G_TYPE_INVALID,
+ G_TYPE_INVALID);
+
+ if (!ret) {
+ if (error != NULL) {
+ g_warning("Unable to set Mission Control Presence: %s", error->message);
+ g_error_free(error);
+ } else {
+ g_warning("Unable to set Mission Control Presence");
+ }
+ return;
+ }
+
+ return;
+}
+
+static StatusProviderStatus
+get_status (StatusProvider * sp)
+{
+ g_return_val_if_fail(IS_STATUS_PROVIDER_TELEPATHY(sp), STATUS_PROVIDER_STATUS_DISCONNECTED);
+ StatusProviderTelepathyPrivate * priv = STATUS_PROVIDER_TELEPATHY_GET_PRIVATE(sp);
+
+ if (priv->proxy == NULL) {
+ return STATUS_PROVIDER_STATUS_DISCONNECTED;
+ }
+
+ return mc_to_sp_map[priv->mc_status];
+}
+
+static void
+changed_status (DBusGProxy * proxy, guint status, gchar * message, StatusProvider * sp)
+{
+ StatusProviderTelepathyPrivate * priv = STATUS_PROVIDER_TELEPATHY_GET_PRIVATE(sp);
+ priv->mc_status = status;
+ g_signal_emit(G_OBJECT(sp), STATUS_PROVIDER_SIGNAL_STATUS_CHANGED_ID, 0, mc_to_sp_map[priv->mc_status], TRUE);
+}
+
+static void
+proxy_destroy (DBusGProxy * proxy, StatusProvider * sp)
+{
+ g_debug("Signal: Mission Control proxy destroyed");
+ g_signal_emit(G_OBJECT(sp), STATUS_PROVIDER_SIGNAL_STATUS_CHANGED_ID, 0, STATUS_PROVIDER_STATUS_OFFLINE, TRUE);
+ return;
+}
+
+static void
+get_status_async (DBusGProxy * proxy, DBusGProxyCall * call, gpointer userdata)
+{
+ GError * error = NULL;
+ guint status = 0;
+ if (!dbus_g_proxy_end_call(proxy, call, &error, G_TYPE_UINT, &status, G_TYPE_INVALID)) {
+ g_warning("Unable to get type from Mission Control: %s", error->message);
+ g_error_free(error);
+ return;
+ }
+
+ StatusProviderTelepathyPrivate * priv = STATUS_PROVIDER_TELEPATHY_GET_PRIVATE(userdata);
+
+ gboolean changed = FALSE;
+ if (status != priv->mc_status) {
+ changed = TRUE;
+ }
+
+ priv->mc_status = status;
+
+ if (changed) {
+ g_signal_emit(G_OBJECT(userdata), STATUS_PROVIDER_SIGNAL_STATUS_CHANGED_ID, 0, mc_to_sp_map[priv->mc_status], TRUE);
+ }
+
+ return;
+}
diff --git a/src/status-provider-telepathy.h b/src/status-provider-telepathy.h
new file mode 100644
index 0000000..a67ee40
--- /dev/null
+++ b/src/status-provider-telepathy.h
@@ -0,0 +1,56 @@
+/*
+A small wrapper utility to load indicators and put them as menu items
+into the gnome-panel using it's applet interface.
+
+Copyright 2009 Canonical Ltd.
+
+Authors:
+ Ted Gould <ted@canonical.com>
+
+This program is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License version 3, as published
+by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranties of
+MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __STATUS_PROVIDER_TELEPATHY_H__
+#define __STATUS_PROVIDER_TELEPATHY_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "status-provider.h"
+
+G_BEGIN_DECLS
+
+#define STATUS_PROVIDER_TELEPATHY_TYPE (status_provider_telepathy_get_type ())
+#define STATUS_PROVIDER_TELEPATHY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), STATUS_PROVIDER_TELEPATHY_TYPE, StatusProviderTelepathy))
+#define STATUS_PROVIDER_TELEPATHY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), STATUS_PROVIDER_TELEPATHY_TYPE, StatusProviderTelepathyClass))
+#define IS_STATUS_PROVIDER_TELEPATHY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), STATUS_PROVIDER_TELEPATHY_TYPE))
+#define IS_STATUS_PROVIDER_TELEPATHY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), STATUS_PROVIDER_TELEPATHY_TYPE))
+#define STATUS_PROVIDER_TELEPATHY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), STATUS_PROVIDER_TELEPATHY_TYPE, StatusProviderTelepathyClass))
+
+
+typedef struct _StatusProviderTelepathyClass StatusProviderTelepathyClass;
+struct _StatusProviderTelepathyClass {
+ StatusProviderClass parent_class;
+};
+
+typedef struct _StatusProviderTelepathy StatusProviderTelepathy;
+struct _StatusProviderTelepathy {
+ StatusProvider parent;
+};
+
+GType status_provider_telepathy_get_type (void);
+StatusProvider * status_provider_telepathy_new (void);
+
+G_END_DECLS
+
+#endif
diff --git a/src/status-provider-telepathy.list b/src/status-provider-telepathy.list
new file mode 100644
index 0000000..5ab45bf
--- /dev/null
+++ b/src/status-provider-telepathy.list
@@ -0,0 +1 @@
+VOID:UINT,STRING
diff --git a/src/status-provider.c b/src/status-provider.c
new file mode 100644
index 0000000..1139e54
--- /dev/null
+++ b/src/status-provider.c
@@ -0,0 +1,101 @@
+/*
+A small wrapper utility to load indicators and put them as menu items
+into the gnome-panel using it's applet interface.
+
+Copyright 2009 Canonical Ltd.
+
+Authors:
+ Ted Gould <ted@canonical.com>
+
+This program is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License version 3, as published
+by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranties of
+MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "status-provider.h"
+
+/* Signals */
+enum {
+ STATUS_CHANGED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+/* GObject Boilerplate */
+static void status_provider_class_init (StatusProviderClass *klass);
+static void status_provider_init (StatusProvider *self);
+
+G_DEFINE_TYPE (StatusProvider, status_provider, G_TYPE_OBJECT);
+
+static void
+status_provider_class_init (StatusProviderClass *klass)
+{
+ // GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ klass->status_changed = NULL;
+
+ klass->set_status = NULL;
+ klass->get_status = NULL;
+
+ /**
+ StatusProvider::status-changed:
+ @arg0: The #StatusProvider object.
+ @arg1: The new status #StatusProviderStatus
+
+ Should be emitted by subclasses everytime that the status
+ changes externally to us.
+ */
+ signals[STATUS_CHANGED] = g_signal_new(STATUS_PROVIDER_SIGNAL_STATUS_CHANGED,
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(StatusProviderClass, status_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__UINT,
+ G_TYPE_NONE, 1, G_TYPE_UINT);
+
+ return;
+}
+
+static void
+status_provider_init (StatusProvider *self)
+{
+
+ return;
+}
+
+void
+status_provider_set_status (StatusProvider * sp, StatusProviderStatus status)
+{
+ g_return_if_fail(IS_STATUS_PROVIDER(sp));
+
+ StatusProviderClass * class = STATUS_PROVIDER_GET_CLASS(sp);
+ g_return_if_fail(class != NULL);
+ g_return_if_fail(class->set_status != NULL);
+
+ return class->set_status(sp, status);
+}
+
+StatusProviderStatus
+status_provider_get_status (StatusProvider * sp)
+{
+ g_return_val_if_fail(IS_STATUS_PROVIDER(sp), STATUS_PROVIDER_STATUS_OFFLINE);
+
+ StatusProviderClass * class = STATUS_PROVIDER_GET_CLASS(sp);
+ g_return_val_if_fail(class->get_status != NULL, STATUS_PROVIDER_STATUS_OFFLINE);
+
+ return class->get_status(sp);
+}
+
diff --git a/src/status-provider.h b/src/status-provider.h
new file mode 100644
index 0000000..45433fc
--- /dev/null
+++ b/src/status-provider.h
@@ -0,0 +1,81 @@
+/*
+A small wrapper utility to load indicators and put them as menu items
+into the gnome-panel using it's applet interface.
+
+Copyright 2009 Canonical Ltd.
+
+Authors:
+ Ted Gould <ted@canonical.com>
+
+This program is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License version 3, as published
+by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranties of
+MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __STATUS_PROVIDER_H__
+#define __STATUS_PROVIDER_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define STATUS_PROVIDER_EXPORT_TYPE(x) GType status_provider_export_type (void) { return (x); }
+#define STATUS_PROVIDER_EXPORT_S "status_provider_export_type"
+
+#define STATUS_PROVIDER_TYPE (status_provider_get_type ())
+#define STATUS_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), STATUS_PROVIDER_TYPE, StatusProvider))
+#define STATUS_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), STATUS_PROVIDER_TYPE, StatusProviderClass))
+#define IS_STATUS_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), STATUS_PROVIDER_TYPE))
+#define IS_STATUS_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), STATUS_PROVIDER_TYPE))
+#define STATUS_PROVIDER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), STATUS_PROVIDER_TYPE, StatusProviderClass))
+
+typedef enum
+{
+ STATUS_PROVIDER_STATUS_ONLINE,
+ STATUS_PROVIDER_STATUS_AWAY,
+ STATUS_PROVIDER_STATUS_DND,
+ STATUS_PROVIDER_STATUS_INVISIBLE,
+ STATUS_PROVIDER_STATUS_OFFLINE,
+ STATUS_PROVIDER_STATUS_DISCONNECTED,
+ /* Leave as last */
+ STATUS_PROVIDER_STATUS_LAST
+}
+StatusProviderStatus;
+
+#define STATUS_PROVIDER_SIGNAL_STATUS_CHANGED "status-changed"
+#define STATUS_PROVIDER_SIGNAL_STATUS_CHANGED_ID (g_signal_lookup(STATUS_PROVIDER_SIGNAL_STATUS_CHANGED, STATUS_PROVIDER_TYPE))
+
+typedef struct _StatusProvider StatusProvider;
+struct _StatusProvider {
+ GObject parent;
+};
+
+typedef struct _StatusProviderClass StatusProviderClass;
+struct _StatusProviderClass {
+ GObjectClass parent_class;
+
+ /* Signals */
+ void (*status_changed) (StatusProviderStatus newstatus);
+
+ /* Virtual Functions */
+ void (*set_status) (StatusProvider * sp, StatusProviderStatus newstatus);
+ StatusProviderStatus (*get_status) (StatusProvider * sp);
+};
+
+GType status_provider_get_type (void);
+
+void status_provider_set_status (StatusProvider * sp, StatusProviderStatus status);
+StatusProviderStatus status_provider_get_status (StatusProvider * sp);
+
+G_END_DECLS
+
+#endif