From 5996de39f38da7d605a999100a6c4a571ad6b66e Mon Sep 17 00:00:00 2001 From: Allan LeSage Date: Tue, 27 Mar 2012 15:18:20 -0500 Subject: Also cleaning up coverage instrumentation (*.gcno) on clean-local. --- Makefile.am.coverage | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Makefile.am.coverage b/Makefile.am.coverage index 9c59b95..2bc3f33 100644 --- a/Makefile.am.coverage +++ b/Makefile.am.coverage @@ -1,14 +1,18 @@ # Coverage targets -.PHONY: clean-gcda \ +.PHONY: clean-gcno clean-gcda \ coverage-html generate-coverage-html clean-coverage-html \ coverage-gcovr generate-coverage-gcovr clean-coverage-gcovr -clean-local: clean-coverage-html clean-coverage-gcovr +clean-local: clean-gcno clean-coverage-html clean-coverage-gcovr if HAVE_GCOV +clean-gcno: + @echo Removing old coverage instrumentation + -find -name '*.gcno' -print | xargs -r rm + clean-gcda: @echo Removing old coverage results -find -name '*.gcda' -print | xargs -r rm -- cgit v1.2.3 From 77386961444d5d06387f3024f2116654f17d3690 Mon Sep 17 00:00:00 2001 From: Allan LeSage Date: Tue, 27 Mar 2012 16:21:31 -0500 Subject: Pedantic name change for gcovr xml results. --- Makefile.am.coverage | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.am.coverage b/Makefile.am.coverage index 2bc3f33..fb97747 100644 --- a/Makefile.am.coverage +++ b/Makefile.am.coverage @@ -38,10 +38,10 @@ coverage-gcovr: clean-gcda generate-coverage-gcovr: @echo Generating coverage GCOVR report - $(GCOVR) -x -r $(top_builddir) -o $(top_builddir)/coverage.gcovr + $(GCOVR) -x -r $(top_builddir) -o $(top_builddir)/coverage.xml clean-coverage-gcovr: clean-gcda - -rm -rf $(top_builddir)/coverage.gcovr + -rm -rf $(top_builddir)/coverage.xml endif # HAVE_GCOVR -- cgit v1.2.3 From 00edffe61a1131953899f2eae35d31e25871fa4c Mon Sep 17 00:00:00 2001 From: Allan LeSage Date: Mon, 16 Apr 2012 13:32:10 -0500 Subject: Adjusted enabling tests to Charles suggestion (removed xyes=xyes). --- configure.ac | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index a429d17..8261207 100644 --- a/configure.ac +++ b/configure.ac @@ -124,8 +124,21 @@ AC_SUBST(COVERAGE_LDFLAGS) # Google Test framework ########################### -m4_include([m4/gtest.m4]) -CHECK_GTEST +AC_ARG_ENABLE([tests], + [AS_HELP_STRING([--disable-tests], [Disable test scripts and tools (default=auto)])], + [enable_tests=${enableval}], + [enable_tests=auto]) +if test "x$enable_tests" != "xno"; then + m4_include([m4/gtest.m4]) + CHECK_GTEST + if test "x$enable_tests" = "xauto"; then + enable_tests=${have_gtest} + elif test "x$enable_tests" = "xyes" && test "x$have_gtest" != "xyes"; then + AC_MSG_ERROR([tests were requested but gtest is not installed.]) + fi +fi +AM_CONDITIONAL([BUILD_TESTS],[test "x$enable_tests" = "xyes"]) + ########################### # Check to see if we're local @@ -229,5 +242,6 @@ Messaging Indicator Configuration: Prefix: $prefix Indicator Dir: $INDICATORDIR + gtest: $enable_tests gcov: $use_gcov ]) -- cgit v1.2.3 From 9b11f86a4b7b2b3f4cb0ee38ba819233cb256e07 Mon Sep 17 00:00:00 2001 From: Allan LeSage Date: Mon, 16 Apr 2012 13:39:54 -0500 Subject: Removed obsolete testing configure. --- configure.ac | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/configure.ac b/configure.ac index 8261207..552b80b 100644 --- a/configure.ac +++ b/configure.ac @@ -76,15 +76,6 @@ AS_IF([test "x$with_gtk" = x3], AC_SUBST(APPLET_CFLAGS) AC_SUBST(APPLET_LIBS) -########################### -# Test Dependencies -########################### - -AC_ARG_ENABLE([tests], - AC_HELP_STRING([--disable-tests], [Disable test scripts and tools]),, - [enable_tests=auto]) -AM_CONDITIONAL(BUILD_TESTS, test xyes = xyes) - ########################### # Status Provider Deps ########################### @@ -139,7 +130,6 @@ if test "x$enable_tests" != "xno"; then fi AM_CONDITIONAL([BUILD_TESTS],[test "x$enable_tests" = "xyes"]) - ########################### # Check to see if we're local ########################### -- cgit v1.2.3 From 56a4d5f27d805247eb44f29e2d644353cd4f5f15 Mon Sep 17 00:00:00 2001 From: Allan LeSage Date: Tue, 17 Apr 2012 10:25:46 -0500 Subject: Clarified tabination. --- configure.ac | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/configure.ac b/configure.ac index 552b80b..3d3f5ab 100644 --- a/configure.ac +++ b/configure.ac @@ -116,17 +116,17 @@ AC_SUBST(COVERAGE_LDFLAGS) ########################### AC_ARG_ENABLE([tests], - [AS_HELP_STRING([--disable-tests], [Disable test scripts and tools (default=auto)])], - [enable_tests=${enableval}], - [enable_tests=auto]) + [AS_HELP_STRING([--disable-tests], [Disable test scripts and tools (default=auto)])], + [enable_tests=${enableval}], + [enable_tests=auto]) if test "x$enable_tests" != "xno"; then - m4_include([m4/gtest.m4]) - CHECK_GTEST - if test "x$enable_tests" = "xauto"; then - enable_tests=${have_gtest} - elif test "x$enable_tests" = "xyes" && test "x$have_gtest" != "xyes"; then - AC_MSG_ERROR([tests were requested but gtest is not installed.]) - fi + m4_include([m4/gtest.m4]) + CHECK_GTEST + if test "x$enable_tests" = "xauto"; then + enable_tests=${have_gtest} + elif test "x$enable_tests" = "xyes" && test "x$have_gtest" != "xyes"; then + AC_MSG_ERROR([tests were requested but gtest is not installed.]) + fi fi AM_CONDITIONAL([BUILD_TESTS],[test "x$enable_tests" = "xyes"]) -- cgit v1.2.3 From c144388a3c09049d97d39e14a3812557f385da54 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 7 May 2012 14:41:28 -0700 Subject: Remove gtk2 support --- configure.ac | 40 +++++++--------------------- src/indicator-messages.c | 69 ------------------------------------------------ 2 files changed, 9 insertions(+), 100 deletions(-) diff --git a/configure.ac b/configure.ac index 77ad41b..ca879a1 100644 --- a/configure.ac +++ b/configure.ac @@ -38,8 +38,7 @@ AC_PROG_CXX # Dependencies ########################### -GTK_REQUIRED_VERSION=2.12 -GTK3_REQUIRED_VERSION=3.0 +GTK_REQUIRED_VERSION=3.0 GIO_UNIX_REQUIRED_VERSION=2.18 PANEL_REQUIRED_VERSION=2.0.0 INDICATE_REQUIRED_VERSION=0.6.90 @@ -47,32 +46,14 @@ INDICATOR_REQUIRED_VERSION=0.3.19 DBUSMENUGTK_REQUIRED_VERSION=0.5.90 GLIB_REQUIRED_VERSION=2.31.20 -AC_ARG_WITH([gtk], - [AS_HELP_STRING([--with-gtk], - [Which version of gtk to use for the indicator @<:@default=3@:>@])], - [], - [with_gtk=3]) - -AS_IF([test "x$with_gtk" = x3], - [PKG_CHECK_MODULES(APPLET, gtk+-3.0 >= $GTK3_REQUIRED_VERSION - gio-unix-2.0 >= $GIO_UNIX_REQUIRED_VERSION - indicator3-0.4 >= $INDICATOR_REQUIRED_VERSION - indicate-0.7 >= $INDICATE_REQUIRED_VERSION - dbusmenu-gtk3-0.4 >= $DBUSMENUGTK_REQUIRED_VERSION - glib-2.0 >= $GLIB_REQUIRED_VERSION - gmodule-2.0 >= $GLIB_REQUIRED_VERSION) - ], - [test "x$with_gtk" = x2], - [PKG_CHECK_MODULES(APPLET, gtk+-2.0 >= $GTK_REQUIRED_VERSION - gio-unix-2.0 >= $GIO_UNIX_REQUIRED_VERSION - indicator-0.4 >= $INDICATOR_REQUIRED_VERSION - indicate-0.7 >= $INDICATE_REQUIRED_VERSION - dbusmenu-gtk-0.4 >= $DBUSMENUGTK_REQUIRED_VERSION - glib-2.0 >= $GLIB_REQUIRED_VERSION - gmodule-2.0 >= $GLIB_REQUIRED_VERSION) - ], - [AC_MSG_FAILURE([Value for --with-indicator-gtk was neither 2 nor 3])] -) +PKG_CHECK_MODULES(APPLET, gtk+-3.0 >= $GTK_REQUIRED_VERSION + gio-unix-2.0 >= $GIO_UNIX_REQUIRED_VERSION + indicator3-0.4 >= $INDICATOR_REQUIRED_VERSION + indicate-0.7 >= $INDICATE_REQUIRED_VERSION + dbusmenu-gtk3-0.4 >= $DBUSMENUGTK_REQUIRED_VERSION + glib-2.0 >= $GLIB_REQUIRED_VERSION + gmodule-2.0 >= $GLIB_REQUIRED_VERSION) + AC_SUBST(APPLET_CFLAGS) AC_SUBST(APPLET_LIBS) @@ -144,9 +125,6 @@ AC_ARG_ENABLE(localinstall, AS_HELP_STRING([--enable-localinstall], [install all if test "x$with_localinstall" = "xyes"; then INDICATORDIR="${libdir}/indicators/2/" INDICATORICONSDIR="${datadir}/libindicate/icons/" -elif test "x$with_gtk" = x2; then - INDICATORDIR=`$PKG_CONFIG --variable=indicatordir indicator-0.4` - INDICATORICONSDIR=`$PKG_CONFIG --variable=iconsdir indicator-0.4` else INDICATORDIR=`$PKG_CONFIG --variable=indicatordir indicator3-0.4` INDICATORICONSDIR=`$PKG_CONFIG --variable=iconsdir indicator3-0.4` diff --git a/src/indicator-messages.c b/src/indicator-messages.c index 748b73b..32f97f7 100644 --- a/src/indicator-messages.c +++ b/src/indicator-messages.c @@ -410,16 +410,9 @@ application_prop_change_cb (DbusmenuMenuitem * mi, gchar * prop, GVariant * valu } /* Draws a triangle on the left, using fg[STATE_TYPE] color. */ -#if GTK_CHECK_VERSION(3, 0, 0) static gboolean application_triangle_draw_cb (GtkWidget *widget, cairo_t *cr, gpointer data) { -#else -static gboolean -application_triangle_draw_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data) -{ - cairo_t *cr; -#endif GtkAllocation allocation; GtkStyle *style; int x, y, arrow_width, arrow_height; @@ -438,20 +431,10 @@ application_triangle_draw_cb (GtkWidget *widget, GdkEventExpose *event, gpointer arrow_width = 5; /* the pixel-based reference triangle is 5x9 */ arrow_height = 9; gtk_widget_get_allocation (widget, &allocation); -#if GTK_CHECK_VERSION(3, 0, 0) x = 0; y = allocation.height/2.0 - (double)arrow_height/2.0; -#else - x = allocation.x; - y = allocation.y + allocation.height/2.0 - (double)arrow_height/2.0; -#endif -#if GTK_CHECK_VERSION(3, 0, 0) cairo_save (cr); -#else - /* initialize cairo drawing area */ - cr = (cairo_t*) gdk_cairo_create (gtk_widget_get_window (widget)); -#endif /* set line width */ cairo_set_line_width (cr, 1.0); @@ -466,12 +449,7 @@ application_triangle_draw_cb (GtkWidget *widget, GdkEventExpose *event, gpointer style->fg[gtk_widget_get_state(widget)].blue/65535.0); cairo_fill (cr); -#if GTK_CHECK_VERSION(3, 0, 0) cairo_restore (cr); -#else - /* remember to destroy cairo context to avoid leaks */ - cairo_destroy (cr); -#endif return FALSE; } @@ -479,16 +457,12 @@ application_triangle_draw_cb (GtkWidget *widget, GdkEventExpose *event, gpointer static gint gtk_widget_get_font_size (GtkWidget *widget) { -#if GTK_CHECK_VERSION(3, 0, 0) const PangoFontDescription *font; font = gtk_style_context_get_font (gtk_widget_get_style_context (widget), gtk_widget_get_state_flags (widget)); return pango_font_description_get_size (font) / PANGO_SCALE; -#else - return 12; -#endif } /* Custom function to draw rounded rectangle with max radius */ @@ -506,16 +480,9 @@ custom_cairo_rounded_rectangle (cairo_t *cr, } /* Draws a rounded rectangle with text inside. */ -#if GTK_CHECK_VERSION(3, 0, 0) static gboolean numbers_draw_cb (GtkWidget *widget, cairo_t *cr, gpointer data) { -#else -static gboolean -numbers_draw_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data) -{ - cairo_t *cr; -#endif GtkAllocation allocation; GtkStyle *style; double x, y, w, h; @@ -535,13 +502,8 @@ numbers_draw_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data) /* set arrow position / dimensions */ gtk_widget_get_allocation (widget, &allocation); -#if GTK_CHECK_VERSION(3, 0, 0) x = 0; y = 0; -#else - x = allocation.x; - y = allocation.y; -#endif w = allocation.width; h = allocation.height; @@ -552,12 +514,7 @@ numbers_draw_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data) if (layout_extents.width == 0) return TRUE; -#if GTK_CHECK_VERSION(3, 0, 0) cairo_save (cr); -#else - /* initialize cairo drawing area */ - cr = (cairo_t*) gdk_cairo_create (gtk_widget_get_window (widget)); -#endif /* set line width */ cairo_set_line_width (cr, 1.0); @@ -577,12 +534,7 @@ numbers_draw_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data) pango_cairo_layout_path (cr, layout); cairo_fill (cr); -#if GTK_CHECK_VERSION(3, 0, 0) cairo_restore (cr); -#else - /* remember to destroy cairo context to avoid leaks */ - cairo_destroy (cr); -#endif return TRUE; } @@ -599,11 +551,7 @@ new_application_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbu gint padding = 4; gtk_widget_style_get(GTK_WIDGET(gmi), "toggle-spacing", &padding, NULL); -#if GTK_CHECK_VERSION(3, 0, 0) GtkWidget * hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, padding); -#else - GtkWidget * hbox = gtk_hbox_new(FALSE, padding); -#endif GtkWidget * icon = gtk_image_new_from_icon_name(dbusmenu_menuitem_property_get(newitem, APPLICATION_MENUITEM_PROP_ICON), GTK_ICON_SIZE_MENU); gtk_misc_set_alignment(GTK_MISC(icon), 1.0 /* right aligned */, 0.5); @@ -623,11 +571,7 @@ new_application_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbu /* Make sure we can handle the label changing */ g_signal_connect(G_OBJECT(newitem), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(application_prop_change_cb), label); g_signal_connect(G_OBJECT(newitem), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(application_icon_change_cb), icon); -#if GTK_CHECK_VERSION(3, 0, 0) g_signal_connect_after(G_OBJECT (gmi), "draw", G_CALLBACK (application_triangle_draw_cb), newitem); -#else - g_signal_connect_after(G_OBJECT (gmi), "expose_event", G_CALLBACK (application_triangle_draw_cb), newitem); -#endif return TRUE; } @@ -709,11 +653,7 @@ new_indicator_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbusm gint font_size = gtk_widget_get_font_size (GTK_WIDGET (gmi)); gtk_widget_style_get(GTK_WIDGET(gmi), "toggle-spacing", &padding, NULL); -#if GTK_CHECK_VERSION(3, 0, 0) GtkWidget * hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, padding); -#else - GtkWidget * hbox = gtk_hbox_new(FALSE, padding); -#endif /* Icon, probably someone's face or avatar on an IM */ mi_data->icon = gtk_image_new(); @@ -723,9 +663,7 @@ new_indicator_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbusm gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height); gtk_widget_set_size_request(GTK_WIDGET (gmi), -1, height + 4); -#if GTK_CHECK_VERSION(3, 0, 0) gtk_widget_set_margin_left (hbox, width + padding); -#endif GdkPixbuf * pixbuf = dbusmenu_menuitem_property_get_image(newitem, INDICATOR_MENUITEM_PROP_ICON); if (pixbuf != NULL) { @@ -769,21 +707,14 @@ new_indicator_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbusm "is-lozenge", GINT_TO_POINTER (dbusmenu_menuitem_property_get_bool (newitem, INDICATOR_MENUITEM_PROP_RIGHT_IS_LOZENGE))); /* install extra decoration overlay */ -#if GTK_CHECK_VERSION(3, 0, 0) g_signal_connect (G_OBJECT (mi_data->right), "draw", G_CALLBACK (numbers_draw_cb), NULL); -#else - g_signal_connect (G_OBJECT (mi_data->right), "expose_event", - G_CALLBACK (numbers_draw_cb), NULL); -#endif gtk_misc_set_alignment(GTK_MISC(mi_data->right), 1.0, 0.5); gtk_box_pack_start(GTK_BOX(hbox), mi_data->right, FALSE, FALSE, padding + font_size/2.0); gtk_label_set_width_chars (GTK_LABEL (mi_data->right), 2); -#if GTK_CHECK_VERSION(3, 0, 0) gtk_style_context_add_class (gtk_widget_get_style_context (mi_data->right), "accelerator"); -#endif gtk_widget_show(mi_data->right); gtk_container_add(GTK_CONTAINER(gmi), hbox); -- cgit v1.2.3 From 583033cb8dbf95d224bc9cc4bf4d4d097b7950f3 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Fri, 18 May 2012 23:26:54 +0200 Subject: Remove default applications This gets rid of the "Set Up " sections for Email, Chat, and Broadcast. Also, default apps don't get to override the icon and names anymore. Every app gets its real name and icon displayed. Overriding the icon with X-Ayatana-Messaging-Menu-Icon is still possible. --- src/Makefile.am | 2 - src/app-menu-item.c | 48 ++++++++----------- src/dbus-data.h | 4 ++ src/default-applications.c | 116 --------------------------------------------- src/default-applications.h | 34 ------------- src/launcher-menu-item.c | 36 ++------------ test/Makefile.am | 3 -- 7 files changed, 26 insertions(+), 217 deletions(-) delete mode 100644 src/default-applications.c delete mode 100644 src/default-applications.h diff --git a/src/Makefile.am b/src/Makefile.am index 6617b49..0f923c7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -37,8 +37,6 @@ libmessaging_la_LDFLAGS = \ ###################################### indicator_messages_service_SOURCES = \ - default-applications.h \ - default-applications.c \ messages-service.c \ messages-service-dbus.c \ messages-service-dbus.h \ diff --git a/src/app-menu-item.c b/src/app-menu-item.c index ef3fbc0..3fb3ab8 100644 --- a/src/app-menu-item.c +++ b/src/app-menu-item.c @@ -30,7 +30,6 @@ with this program. If not, see . #include #include "app-menu-item.h" #include "dbus-data.h" -#include "default-applications.h" #include "seen-db.h" enum { @@ -257,11 +256,7 @@ static void update_label (AppMenuItem * self) { AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self); - const gchar * name = get_default_name(priv->desktop); - - if (name == NULL) { - name = app_menu_item_get_name(self); - } + const gchar * name = app_menu_item_get_name(self); if (priv->unreadcount > 0) { /* TRANSLATORS: This is the name of the program and the number of indicators. So it @@ -345,36 +340,31 @@ desktop_cb (IndicateListener * listener, IndicateListenerServer * server, const update_label(self); - const gchar * def_icon = get_default_icon(priv->desktop); - if (def_icon == NULL) { - gchar * iconstr = NULL; + gchar * iconstr = NULL; - /* Check for the over ride key and see if we should be using that - icon. If we can't get it, then go back to the app info */ - if (g_key_file_has_key(priv->keyfile, G_KEY_FILE_DESKTOP_GROUP, ICON_KEY, NULL) && iconstr == NULL) { - GError * error = NULL; + /* Check for the over ride key and see if we should be using that + icon. If we can't get it, then go back to the app info */ + if (g_key_file_has_key(priv->keyfile, G_KEY_FILE_DESKTOP_GROUP, ICON_KEY, NULL) && iconstr == NULL) { + GError * error = NULL; - iconstr = g_key_file_get_string(priv->keyfile, G_KEY_FILE_DESKTOP_GROUP, ICON_KEY, &error); - - if (error != NULL) { - /* Can't figure out why this would happen, but sure, let's print something */ - g_warning("Error getting '" ICON_KEY "' from desktop file: %s", error->message); - g_error_free(error); - } - } + iconstr = g_key_file_get_string(priv->keyfile, G_KEY_FILE_DESKTOP_GROUP, ICON_KEY, &error); - /* For some reason that didn't work, let's try the app info */ - if (iconstr == NULL) { - GIcon * icon = g_app_info_get_icon(priv->appinfo); - iconstr = g_icon_to_string(icon); + if (error != NULL) { + /* Can't figure out why this would happen, but sure, let's print something */ + g_warning("Error getting '" ICON_KEY "' from desktop file: %s", error->message); + g_error_free(error); } + } - dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), APPLICATION_MENUITEM_PROP_ICON, iconstr); - g_free(iconstr); - } else { - dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), APPLICATION_MENUITEM_PROP_ICON, def_icon); + /* For some reason that didn't work, let's try the app info */ + if (iconstr == NULL) { + GIcon * icon = g_app_info_get_icon(priv->appinfo); + iconstr = g_icon_to_string(icon); } + dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), APPLICATION_MENUITEM_PROP_ICON, iconstr); + g_free(iconstr); + g_signal_emit(G_OBJECT(self), signals[NAME_CHANGED], 0, app_menu_item_get_name(self), TRUE); return; diff --git a/src/dbus-data.h b/src/dbus-data.h index fac732e..1e82ded 100644 --- a/src/dbus-data.h +++ b/src/dbus-data.h @@ -21,4 +21,8 @@ #define MAX_NUMBER_OF_INDICATORS 7 +/* Used for override icons in the normal case, but didn't + have a better place to put it. */ +#define ICON_KEY "X-Ayatana-Messaging-Menu-Icon" + #endif /* __DBUS_DATA_H__ */ diff --git a/src/default-applications.c b/src/default-applications.c deleted file mode 100644 index 0382e4d..0000000 --- a/src/default-applications.c +++ /dev/null @@ -1,116 +0,0 @@ -/* -Looking for the default applications. A quick lookup. - -Copyright 2010 Canonical Ltd. - -Authors: - Ted Gould - -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 . -*/ - -#include -#include -#include -#include -#include "default-applications.h" - -struct default_db_t { - const gchar * desktop_file; - const gchar * uri_scheme; - const gchar * name; - const gchar * setupname; - const gchar * icon; -}; - -struct default_db_t default_db[] = { - {NULL, "mailto", N_("Mail"), N_("Set Up Mail..."), "applications-email-panel"}, - {"empathy.desktop", NULL, N_("Chat"), N_("Set Up Chat..."), "applications-chat-panel"}, - {"gwibber.desktop", NULL, N_("Broadcast"), N_("Set Up Broadcast Account..."), "applications-microblogging-panel"}, -}; - -static struct default_db_t * -get_default_helper (const gchar * desktop_path) -{ - g_return_val_if_fail(desktop_path != NULL, NULL); - gchar * basename = g_path_get_basename(desktop_path); - g_return_val_if_fail(basename != NULL, NULL); - - gboolean found = FALSE; - gint i; - gint length = G_N_ELEMENTS(default_db); - for (i = 0; i < length && !found; i++) { - if (default_db[i].desktop_file) { - if (g_strcmp0(default_db[i].desktop_file, basename) == 0) { - found = TRUE; - } - } else if (default_db[i].uri_scheme) { - GAppInfo *info = g_app_info_get_default_for_uri_scheme(default_db[i].uri_scheme); - if (!info) { - continue; - } - - const gchar * filename = g_desktop_app_info_get_filename(G_DESKTOP_APP_INFO(info)); - if (!filename) { - g_object_unref(info); - continue; - } - - gchar * default_basename = g_path_get_basename(filename); - g_object_unref(info); - if (g_strcmp0(default_basename, basename) == 0) { - found = TRUE; - } - - g_free(default_basename); - } - } - - g_free(basename); - - if (found) { - return &default_db[i - 1]; - } - - return NULL; -} - -const gchar * -get_default_name (const gchar * desktop_path) -{ - struct default_db_t * db = get_default_helper(desktop_path); - - if (db == NULL) - return NULL; - return db->name; -} - -const gchar * -get_default_setup (const gchar * desktop_path) -{ - struct default_db_t * db = get_default_helper(desktop_path); - - if (db == NULL) - return NULL; - return db->setupname; -} - -const gchar * -get_default_icon (const gchar * desktop_path) -{ - struct default_db_t * db = get_default_helper(desktop_path); - - if (db == NULL) - return NULL; - return db->icon; -} diff --git a/src/default-applications.h b/src/default-applications.h deleted file mode 100644 index df52b38..0000000 --- a/src/default-applications.h +++ /dev/null @@ -1,34 +0,0 @@ -/* -Looking for the default applications. A quick lookup. - -Copyright 2010 Canonical Ltd. - -Authors: - Ted Gould - -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 . -*/ - -#ifndef DEFAULT_APPLICATIONS_H__ -#define DEFAULT_APPLICATIONS_H__ 1 - -/* Used for override icons in the normal case, but didn't - have a better place to put it. */ -#define ICON_KEY "X-Ayatana-Messaging-Menu-Icon" - -const gchar * get_default_name (const gchar * desktop_path); -const gchar * get_default_setup (const gchar * desktop_path); -const gchar * get_default_icon (const gchar * desktop_path); - -#endif /* DEFAULT_APPLICATIONS_H__ */ - diff --git a/src/launcher-menu-item.c b/src/launcher-menu-item.c index 91cbbb8..5e10da4 100644 --- a/src/launcher-menu-item.c +++ b/src/launcher-menu-item.c @@ -30,7 +30,6 @@ with this program. If not, see . #include #include "launcher-menu-item.h" #include "dbus-data.h" -#include "default-applications.h" #include "seen-db.h" enum { @@ -175,26 +174,9 @@ launcher_menu_item_new (const gchar * desktop_file) app info that we've parsed */ g_debug("\tName: %s", launcher_menu_item_get_name(self)); - const gchar * default_name = NULL; - - if (seen_db_seen(desktop_file)) { - default_name = get_default_name(desktop_file); - } else { - default_name = get_default_setup(desktop_file); - } - - if (default_name == NULL) { - dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_LABEL, launcher_menu_item_get_name(self)); - } else { - dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_LABEL, _(default_name)); - } + dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_LABEL, launcher_menu_item_get_name(self)); - gchar * iconstr; - if (default_name == NULL) { - iconstr = launcher_menu_item_get_icon(self); - } else { - iconstr = g_strdup(get_default_icon(desktop_file)); - } + gchar * iconstr = launcher_menu_item_get_icon(self); dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_ICON_NAME, iconstr); g_free(iconstr); dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE); @@ -357,19 +339,7 @@ launcher_menu_item_set_eclipsed (LauncherMenuItem * li, gboolean eclipsed) /* If we're being reshown let's re-evaluate how we should be showing the label */ if (!eclipsed) { - const gchar * default_name = NULL; - - if (seen_db_seen(priv->desktop)) { - default_name = get_default_name(priv->desktop); - } else { - default_name = get_default_setup(priv->desktop); - } - - if (default_name == NULL) { - dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(li), DBUSMENU_MENUITEM_PROP_LABEL, launcher_menu_item_get_name(li)); - } else { - dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(li), DBUSMENU_MENUITEM_PROP_LABEL, _(default_name)); - } + dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(li), DBUSMENU_MENUITEM_PROP_LABEL, launcher_menu_item_get_name(li)); } return; diff --git a/test/Makefile.am b/test/Makefile.am index 1d28dc4..09bd861 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -39,8 +39,6 @@ lib_LTLIBRARIES = \ libindicator-messages-service.la libindicator_messages_service_la_HEADERS = \ - $(top_srcdir)/src/default-applications.h \ - $(top_srcdir)/src/messages-service-dbus.h \ $(top_srcdir)/src/gen-messages-service.xml.h \ $(top_srcdir)/src/im-menu-item.h \ $(top_srcdir)/src/app-menu-item.h \ @@ -51,7 +49,6 @@ libindicator_messages_service_la_HEADERS = \ $(top_srcdir)/src/status-items.h libindicator_messages_service_la_SOURCES = \ - $(top_srcdir)/src/default-applications.c \ $(top_srcdir)/src/messages-service.c \ $(top_srcdir)/src/messages-service-dbus.c \ $(top_srcdir)/src/gen-messages-service.xml.c \ -- cgit v1.2.3 From ab416588f88aa199193f234220f102788c0493c0 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Fri, 18 May 2012 23:41:22 +0200 Subject: Remove the seen db It was only really used to figure out whether one of the default apps was ever running, so that "Set up..." or the app name and actions would be shown in the menu. Since there are no default apps anymore, this is not needed either. --- src/Makefile.am | 2 - src/app-menu-item.c | 3 - src/launcher-menu-item.c | 33 ++++----- src/messages-service.c | 4 -- src/seen-db.c | 177 ----------------------------------------------- src/seen-db.h | 31 --------- test/Makefile.am | 2 - 7 files changed, 15 insertions(+), 237 deletions(-) delete mode 100644 src/seen-db.c delete mode 100644 src/seen-db.h diff --git a/src/Makefile.am b/src/Makefile.am index 0f923c7..8d48047 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -48,8 +48,6 @@ indicator_messages_service_SOURCES = \ app-menu-item.h \ launcher-menu-item.c \ launcher-menu-item.h \ - seen-db.c \ - seen-db.h \ dirs.h \ dbus-data.h \ \ diff --git a/src/app-menu-item.c b/src/app-menu-item.c index 3fb3ab8..f7b1469 100644 --- a/src/app-menu-item.c +++ b/src/app-menu-item.c @@ -30,7 +30,6 @@ with this program. If not, see . #include #include "app-menu-item.h" #include "dbus-data.h" -#include "seen-db.h" enum { COUNT_CHANGED, @@ -325,8 +324,6 @@ desktop_cb (IndicateListener * listener, IndicateListenerServer * server, const return; } - seen_db_add(value); - priv->appinfo = G_APP_INFO(g_desktop_app_info_new_from_filename(value)); g_return_if_fail(priv->appinfo != NULL); diff --git a/src/launcher-menu-item.c b/src/launcher-menu-item.c index 5e10da4..fd04f52 100644 --- a/src/launcher-menu-item.c +++ b/src/launcher-menu-item.c @@ -30,7 +30,6 @@ with this program. If not, see . #include #include "launcher-menu-item.h" #include "dbus-data.h" -#include "seen-db.h" enum { NAME_CHANGED, @@ -184,23 +183,21 @@ launcher_menu_item_new (const gchar * desktop_file) g_signal_connect(G_OBJECT(self), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(activate_cb), NULL); /* Start to build static shortcuts */ - if (seen_db_seen(desktop_file)) { - priv->ids = indicator_desktop_shortcuts_new(priv->desktop, "Messaging Menu"); - const gchar ** nicks = indicator_desktop_shortcuts_get_nicks(priv->ids); - gint i; - for (i = 0; nicks[i] != NULL; i++) { - DbusmenuMenuitem * mi = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set(mi, DBUSMENU_MENUITEM_PROP_TYPE, APPLICATION_MENUITEM_TYPE); - g_object_set_data(G_OBJECT(mi), NICK_DATA, (gpointer)nicks[i]); - - gchar *name = indicator_desktop_shortcuts_nick_get_name(priv->ids, nicks[i]); - dbusmenu_menuitem_property_set(mi, DBUSMENU_MENUITEM_PROP_LABEL, name); - g_free(name); - - g_signal_connect(G_OBJECT(mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(nick_activate_cb), self); - - priv->shortcuts = g_list_append(priv->shortcuts, mi); - } + priv->ids = indicator_desktop_shortcuts_new(priv->desktop, "Messaging Menu"); + const gchar ** nicks = indicator_desktop_shortcuts_get_nicks(priv->ids); + gint i; + for (i = 0; nicks[i] != NULL; i++) { + DbusmenuMenuitem * mi = dbusmenu_menuitem_new(); + dbusmenu_menuitem_property_set(mi, DBUSMENU_MENUITEM_PROP_TYPE, APPLICATION_MENUITEM_TYPE); + g_object_set_data(G_OBJECT(mi), NICK_DATA, (gpointer)nicks[i]); + + gchar *name = indicator_desktop_shortcuts_nick_get_name(priv->ids, nicks[i]); + dbusmenu_menuitem_property_set(mi, DBUSMENU_MENUITEM_PROP_LABEL, name); + g_free(name); + + g_signal_connect(G_OBJECT(mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(nick_activate_cb), self); + + priv->shortcuts = g_list_append(priv->shortcuts, mi); } /* Check to see if we should be eclipsed */ diff --git a/src/messages-service.c b/src/messages-service.c index 078cee3..2188ab0 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -39,7 +39,6 @@ with this program. If not, see . #include "dbus-data.h" #include "dirs.h" #include "messages-service-dbus.h" -#include "seen-db.h" #include "status-items.h" static IndicatorService * service = NULL; @@ -1533,9 +1532,6 @@ 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(); diff --git a/src/seen-db.c b/src/seen-db.c deleted file mode 100644 index 57765cc..0000000 --- a/src/seen-db.c +++ /dev/null @@ -1,177 +0,0 @@ -/* -A small database of which desktop files we've seen. - -Copyright 2010 Canonical Ltd. - -Authors: - Ted Gould - -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 . -*/ - -#include "seen-db.h" - -#define GROUP_NAME "Seen Database" -#define KEY_NAME "DesktopFiles" - -GHashTable * seendb = NULL; -gchar * filename = NULL; -gchar * dirname = NULL; -guint write_process = 0; - -/* Build the hashtable and then see if we have a keyfile that - we can get the history of desktop files we've seen. */ -void -seen_db_init(void) -{ - g_return_if_fail(seendb == NULL); - - seendb = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); - - /* Build the filename for the seen database. We're putting - it in the cache directory because it could get deleted and - it really wouldn't be a big deal. */ - if (dirname == NULL) { - dirname = g_build_filename(g_get_user_cache_dir(), "indicators", "messages", NULL); - } - if (filename == NULL) { - filename = g_build_filename(dirname, "seen-db.keyfile", NULL); - } - - if (g_file_test(filename, G_FILE_TEST_EXISTS)) { - GKeyFile * keyfile = g_key_file_new(); - - /* Load from file */ - if (!g_key_file_load_from_file(keyfile, filename, G_KEY_FILE_NONE, NULL)) { - g_key_file_free(keyfile); - keyfile = NULL; - } - - /* Check for keys */ - if (keyfile != NULL && !g_key_file_has_key(keyfile, GROUP_NAME, KEY_NAME, NULL)) { - g_warning("Seen DB '%s' does not have key '%s' in group '%s'", filename, KEY_NAME, GROUP_NAME); - g_key_file_free(keyfile); - keyfile = NULL; - } - - /* Grab them and put in DB */ - if (keyfile != NULL) { - gchar ** desktops = g_key_file_get_string_list(keyfile, GROUP_NAME, KEY_NAME, NULL, NULL); - gint i = 0; - - while (desktops[i] != NULL) { - g_hash_table_insert(seendb, - g_strdup(desktops[i]), - GINT_TO_POINTER(TRUE)); - i++; - } - - g_strfreev(desktops); - } - - /* Clean up our file */ - if (keyfile != NULL) { - g_key_file_free(keyfile); - } - } - - return; -} - -/* A function to write out the seen database after it's been - modified for a while. */ -static gboolean -write_seen_db (gpointer user_data) -{ - write_process = 0; - - /* Build up the key file */ - GKeyFile * keyfile = g_key_file_new(); - GArray * desktops = g_array_new(FALSE, FALSE, sizeof(gchar *)); - - /* Get the keys from the hashtable and make them - into an array */ - if (keyfile != NULL) { - GList * desktop_keys = g_hash_table_get_keys(seendb); - GList * head = NULL; - - for (head = desktop_keys; head != NULL; head = g_list_next(head)) { - g_array_append_val(desktops, head->data); - } - - g_list_free(desktop_keys); - } - - /* Use the array to dump the strings into the keyfile */ - g_key_file_set_string_list(keyfile, - GROUP_NAME, - KEY_NAME, - (const gchar * const *)desktops->data, - desktops->len); - g_array_free(desktops, TRUE); - - /* Dump the key file to string */ - gchar * keydump = NULL; - gsize keydumplen = 0; - keydump = g_key_file_to_data(keyfile, &keydumplen, NULL); - g_key_file_free(keyfile); - - /* Ensure the directory exists */ - if (g_mkdir_with_parents(dirname, 0700) != 0) { - g_warning("Unable to make directory: %s", dirname); - g_free(keydump); - return FALSE; - } - - /* Dump out the file */ - GError * error = NULL; - if (!g_file_set_contents(filename, keydump, keydumplen, &error)) { - g_warning("Unable to write out file '%s': %s", filename, error->message); - g_error_free(error); - } - - /* Clean up */ - g_free(keydump); - - return FALSE; -} - -/* Add a new desktop file to the seen database. Also sets up a timer - to do the write out. */ -void -seen_db_add (const gchar * desktop) -{ - /* If this is a new one, let's set up the timer. If - there's already one clear it. */ - if (!seen_db_seen(desktop)) { - if (write_process != 0) { - g_source_remove(write_process); - write_process = 0; - } - - write_process = g_timeout_add_seconds(60, write_seen_db, NULL); - } - - g_hash_table_insert(seendb, - g_strdup(desktop), - GINT_TO_POINTER(TRUE)); - - return; -} - -/* Checks to see if a desktop file has been seen. */ -gboolean -seen_db_seen (const gchar * desktop) -{ - return GPOINTER_TO_INT(g_hash_table_lookup(seendb, desktop)); -} diff --git a/src/seen-db.h b/src/seen-db.h deleted file mode 100644 index a998ff0..0000000 --- a/src/seen-db.h +++ /dev/null @@ -1,31 +0,0 @@ -/* -A small database of which desktop files we've seen. - -Copyright 2010 Canonical Ltd. - -Authors: - Ted Gould - -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 . -*/ - -#ifndef SEEN_DB_H__ -#define SEEN_DB_H__ 1 - -#include - -void seen_db_init(void); -void seen_db_add (const gchar * desktop); -gboolean seen_db_seen (const gchar * desktop); - -#endif /* SEEN_DB_H__ */ diff --git a/test/Makefile.am b/test/Makefile.am index 09bd861..466de1e 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -43,7 +43,6 @@ libindicator_messages_service_la_HEADERS = \ $(top_srcdir)/src/im-menu-item.h \ $(top_srcdir)/src/app-menu-item.h \ $(top_srcdir)/src/launcher-menu-item.h \ - $(top_srcdir)/src/seen-db.h \ $(top_srcdir)/src/dirs.h \ $(top_srcdir)/src/dbus-data.h \ $(top_srcdir)/src/status-items.h @@ -55,7 +54,6 @@ libindicator_messages_service_la_SOURCES = \ $(top_srcdir)/src/im-menu-item.c \ $(top_srcdir)/src/app-menu-item.c \ $(top_srcdir)/src/launcher-menu-item.c \ - $(top_srcdir)/src/seen-db.c \ $(top_srcdir)/src/status-items.c libindicator_messages_service_ladir = \ -- cgit v1.2.3 From 14716e2d8d8bf7ccd8ba3ee2e9607a718bf2ff66 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 21 May 2012 16:45:58 +0200 Subject: Use a gsettings list for finding out which apps should appear in the menu Previously, this was handled by looking for .desktop files in various system and user directories. The messaging menu should not display any applications by default anymore, so a simple per-user gsettings list suffices. A neat side effect is that the hairy blacklist handling is not needed anymore, either. Small regression: apps are not configurable at runtime anymore (settings key is not listened to for changes). --- configure.ac | 2 + data/Makefile.am | 7 +- data/com.canonical.indicator.messages.gschema.xml | 12 + src/Makefile.am | 1 - src/dirs.h | 4 - src/messages-service.c | 506 +--------------------- test/Makefile.am | 1 - 7 files changed, 43 insertions(+), 490 deletions(-) create mode 100644 data/com.canonical.indicator.messages.gschema.xml delete mode 100644 src/dirs.h diff --git a/configure.ac b/configure.ac index ca879a1..148259d 100644 --- a/configure.ac +++ b/configure.ac @@ -57,6 +57,8 @@ PKG_CHECK_MODULES(APPLET, gtk+-3.0 >= $GTK_REQUIRED_VERSION AC_SUBST(APPLET_CFLAGS) AC_SUBST(APPLET_LIBS) +GLIB_GSETTINGS + ########################### # Status Provider Deps ########################### diff --git a/data/Makefile.am b/data/Makefile.am index 351601b..488ce05 100644 --- a/data/Makefile.am +++ b/data/Makefile.am @@ -6,6 +6,11 @@ dbus_services_DATA = indicator-messages.service %.service: %.service.in sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@ -EXTRA_DIST = indicator-messages.service.in +gsettings_SCHEMAS = com.canonical.indicator.messages.gschema.xml +@GSETTINGS_RULES@ + +EXTRA_DIST = \ + $(gsettings_SCHEMAS) \ + indicator-messages.service.in CLEANFILES = indicator-messages.service diff --git a/data/com.canonical.indicator.messages.gschema.xml b/data/com.canonical.indicator.messages.gschema.xml new file mode 100644 index 0000000..d9165cd --- /dev/null +++ b/data/com.canonical.indicator.messages.gschema.xml @@ -0,0 +1,12 @@ + + + + List of applications that are shown in the messaging menu + + Applications corresponding to the desktop file ids in this list are shown in the messaging menu. + + [] + + + + diff --git a/src/Makefile.am b/src/Makefile.am index 8d48047..fa8c7a5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -48,7 +48,6 @@ indicator_messages_service_SOURCES = \ app-menu-item.h \ launcher-menu-item.c \ launcher-menu-item.h \ - dirs.h \ dbus-data.h \ \ status-items.c \ diff --git a/src/dirs.h b/src/dirs.h deleted file mode 100644 index ca322f0..0000000 --- a/src/dirs.h +++ /dev/null @@ -1,4 +0,0 @@ -#define SYSTEM_APPS_DIR "/usr/share/indicators/messages/applications" -#define SYSTEM_APPS_DIR_OLD "/etc/indicators/messages/applications" -#define USER_APPS_DIR "indicators/messages/applications" -#define USER_BLACKLIST_DIR "indicators/messages/applications-blacklist" diff --git a/src/messages-service.c b/src/messages-service.c index 2188ab0..12b1ded 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -28,6 +28,7 @@ with this program. If not, see . #include #include #include +#include #include #include @@ -37,7 +38,6 @@ with this program. If not, see . #include "app-menu-item.h" #include "launcher-menu-item.h" #include "dbus-data.h" -#include "dirs.h" #include "messages-service-dbus.h" #include "status-items.h" @@ -49,6 +49,7 @@ static GList * launcherList = NULL; static DbusmenuMenuitem * root_menuitem = NULL; static DbusmenuMenuitem * status_separator = NULL; static DbusmenuMenuitem * clear_attention = NULL; +static GSettings *settings; static GMainLoop * mainloop = NULL; static MessageServiceDbus * dbus_interface = NULL; @@ -66,18 +67,8 @@ static void indicator_removed (IndicateListener * listener, IndicateListenerServ static void check_eclipses (AppMenuItem * ai); static void remove_eclipses (AppMenuItem * ai); static gboolean build_launcher (gpointer data); -static gboolean build_launcher_keyfile (gpointer data); static void build_launcher_core (const gchar * desktop); static gboolean build_launchers (gpointer data); -static gboolean blacklist_init (gpointer data); -static gboolean blacklist_add (gpointer data); -static gchar * desktop_file_from_keyfile (const gchar * definition_file); -static gboolean blacklist_keyfile_add (gpointer udata); -static void blacklist_add_core (gchar * desktop, gchar * definition); -static gboolean blacklist_remove (gpointer data); -static void blacklist_dir_changed (GFileMonitor * monitor, GFile * file, GFile * other_file, GFileMonitorEvent event_type, gpointer user_data); -static void app_dir_changed (GFileMonitor * monitor, GFile * file, GFile * other_file, GFileMonitorEvent event_type, gpointer user_data); -static gboolean destroy_launcher (gpointer data); static void check_hidden (void); @@ -219,311 +210,6 @@ launcherList_count (void) return count; } -/* - * Black List - */ - -static GHashTable * blacklist = NULL; -static GFileMonitor * blacklistdirmon = NULL; - -/* Initialize the black list and start to setup - handlers for it. */ -static gboolean -blacklist_init (gpointer data) -{ - blacklist = g_hash_table_new_full(g_str_hash, g_str_equal, - g_free, g_free); - - gchar * blacklistdir = g_build_filename(g_get_user_config_dir(), USER_BLACKLIST_DIR, NULL); - g_debug("Looking at blacklist: %s", blacklistdir); - if (!g_file_test(blacklistdir, G_FILE_TEST_IS_DIR)) { - g_free(blacklistdir); - return FALSE; - } - - GFile * filedir = g_file_new_for_path(blacklistdir); - blacklistdirmon = g_file_monitor_directory(filedir, G_FILE_MONITOR_NONE, NULL, NULL); - if (blacklistdirmon != NULL) { - g_signal_connect(G_OBJECT(blacklistdirmon), "changed", G_CALLBACK(blacklist_dir_changed), NULL); - } - - GError * error = NULL; - GDir * dir = g_dir_open(blacklistdir, 0, &error); - if (dir == NULL) { - g_warning("Unable to open blacklist directory (%s): %s", blacklistdir, error == NULL ? "No Message" : error->message); - g_error_free(error); - g_free(blacklistdir); - return FALSE; - } - - const gchar * filename = NULL; - while ((filename = g_dir_read_name(dir)) != NULL) { - g_debug("Found file: %s", filename); - gchar * path = g_build_filename(blacklistdir, filename, NULL); - if (g_str_has_suffix(path, "keyfile")) { - g_idle_add(blacklist_keyfile_add, path); - } else { - g_idle_add(blacklist_add, path); - } - } - - g_dir_close(dir); - g_free(blacklistdir); - - return FALSE; -} - -/* Parses through a keyfile to find the desktop file entry and - pushes them into the blacklist. */ -static gboolean -blacklist_keyfile_add (gpointer udata) -{ - gchar * definition_file = (gchar *)udata; - gchar * desktopfile = desktop_file_from_keyfile(definition_file); - if (desktopfile != NULL) { - blacklist_add_core(desktopfile, definition_file); - g_free(desktopfile); - } - return FALSE; -} - -/* Takes a keyfile and finds the desktop file in it for - us. With some error handling. */ -static gchar * -desktop_file_from_keyfile (const gchar * definition_file) -{ - GKeyFile * keyfile = g_key_file_new(); - GError * error = NULL; - - if (!g_key_file_load_from_file(keyfile, definition_file, G_KEY_FILE_NONE, &error)) { - g_warning("Unable to load keyfile '%s' because: %s", definition_file, error == NULL ? "unknown" : error->message); - g_error_free(error); - g_key_file_free(keyfile); - return NULL; - } - - if (!g_key_file_has_group(keyfile, DESKTOP_FILE_GROUP)) { - g_warning("Unable to use keyfile '%s' as it has no '" DESKTOP_FILE_GROUP "' group.", definition_file); - g_key_file_free(keyfile); - return NULL; - } - - if (!g_key_file_has_key(keyfile, DESKTOP_FILE_GROUP, DESKTOP_FILE_KEY_DESKTOP, &error)) { - g_warning("Unable to use keyfile '%s' as there is no key '" DESKTOP_FILE_KEY_DESKTOP "' in the group '" DESKTOP_FILE_GROUP "' because: %s", definition_file, error == NULL ? "unknown" : error->message); - g_error_free(error); - g_key_file_free(keyfile); - return NULL; - } - - gchar * desktopfile = g_key_file_get_string(keyfile, DESKTOP_FILE_GROUP, DESKTOP_FILE_KEY_DESKTOP, &error); - g_key_file_free(keyfile); - return desktopfile; -} - -/* Check if path is a symlink and return its target if it is */ -static gchar * -get_symlink_target (const gchar *path) -{ - GFile *file; - GFileInfo *fileinfo; - gchar *target = NULL; - - file = g_file_new_for_path (path); - - fileinfo = g_file_query_info (file, "standard::is-symlink", - G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, - NULL, NULL); - g_object_unref (file); - - if (!fileinfo) - return NULL; - - if (g_file_info_get_is_symlink (fileinfo)) - target = g_strdup (g_file_info_get_symlink_target (fileinfo)); - - g_object_unref (fileinfo); - return target; -} - -/* Add a definition file into the black list and eclipse - any launchers that have the same file. */ -static gboolean -blacklist_add (gpointer udata) -{ - gchar * definition_file = (gchar *)udata; - gchar * symlink_target = get_symlink_target (definition_file); - gchar * contents = NULL; - - if (symlink_target) - { - blacklist_add_core (symlink_target, definition_file); - g_free (symlink_target); - } - else if (g_str_has_suffix (definition_file, ".desktop")) - { - blacklist_add_core(definition_file, definition_file); - } - else if (g_file_get_contents (definition_file, &contents, NULL, NULL)) - { - gchar *trimmed = pango_trim_string (contents); - blacklist_add_core (trimmed, definition_file); - g_free (trimmed); - g_free (contents); - } - else - g_warning ("invalid blacklist entry: %s", definition_file); - - return FALSE; -} - -/* This takes a desktop file and tries to add it to the black - list for applications in the messaging menu. If it can, - then the launcher item gets marked as eclipsed and hidden - from the user. */ -static void -blacklist_add_core (gchar * desktop, gchar * definition) -{ - gchar *basename = g_path_get_basename(desktop); - - /* Check for conflicts */ - gpointer data = g_hash_table_lookup(blacklist, basename); - if (data != NULL) { - gchar * oldfile = (gchar *)data; - if (!g_strcmp0(oldfile, definition)) { - g_warning("Already added file '%s'", oldfile); - } else { - g_warning("Already have desktop file '%s' in blacklist file '%s' not adding from '%s'", desktop, oldfile, definition); - } - - g_free(basename); - return; - } - - /* Actually blacklist this thing */ - g_hash_table_insert(blacklist, g_strdup(basename), g_strdup(definition)); - g_debug("Adding Blacklist item '%s' for desktop '%s'", definition, desktop); - - /* Go through and eclipse folks */ - GList * launcher; - for (launcher = launcherList; launcher != NULL; launcher = launcher->next) { - launcherList_t * item = (launcherList_t *)launcher->data; - gchar * item_basename = g_path_get_basename(launcher_menu_item_get_desktop(item->menuitem)); - if (!g_strcmp0(basename, item_basename)) { - launcher_menu_item_set_eclipsed(item->menuitem, TRUE); - dbusmenu_menuitem_property_set_bool(item->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE); - } - g_free(item_basename); - } - - check_hidden(); - /* Shouldn't need a resort here as hiding shouldn't cause things to - move other than this item disappearing. */ - - g_free(basename); - return; -} - -/* Remove a black list item based on the definition file - and uneclipse those launchers blocked by it. */ -static gboolean -blacklist_remove (gpointer data) -{ - gchar * definition_file = (gchar *)data; - g_debug("Removing: %s", definition_file); - - GHashTableIter iter; - gpointer key, value; - gboolean found = FALSE; - - g_hash_table_iter_init(&iter, blacklist); - while (g_hash_table_iter_next(&iter, &key, &value)) { - if (!g_strcmp0((gchar *)value, definition_file)) { - found = TRUE; - break; - } - } - - if (!found) { - g_debug("\tNot found!"); - return FALSE; - } - - GList * launcheritem; - for (launcheritem = launcherList; launcheritem != NULL; launcheritem = launcheritem->next) { - launcherList_t * li = (launcherList_t *)launcheritem->data; - if (!g_strcmp0(launcher_menu_item_get_desktop(li->menuitem), (gchar *)key)) { - GList * serveritem; - for (serveritem = serverList; serveritem != NULL; serveritem = serveritem->next) { - serverList_t * si = (serverList_t *)serveritem->data; - if (!g_strcmp0(app_menu_item_get_desktop(si->menuitem), (gchar *)key)) { - break; - } - } - if (serveritem == NULL) { - launcher_menu_item_set_eclipsed(li->menuitem, FALSE); - dbusmenu_menuitem_property_set_bool(li->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE); - } - } - } - - if (!g_hash_table_remove(blacklist, key)) { - g_warning("Unable to remove '%s' with value '%s'", definition_file, (gchar *)key); - } - - check_hidden(); - resort_menu(root_menuitem); - - return FALSE; -} - -/* Check to see if a particular desktop file is - in the blacklist. */ -static gboolean -blacklist_check (const gchar * desktop_file) -{ - gchar *basename = g_path_get_basename(desktop_file); - gboolean found; - - g_debug("Checking blacklist for: %s", basename); - - if (blacklist && g_hash_table_lookup(blacklist, basename)) { - g_debug("\tFound!"); - found = TRUE; - } - else - found = FALSE; - - g_free(basename); - return found; -} - -/* A callback everytime the blacklist directory changes - in some way. It needs to handle that. */ -static void -blacklist_dir_changed (GFileMonitor * monitor, GFile * file, GFile * other_file, GFileMonitorEvent event_type, gpointer user_data) -{ - g_debug("Blacklist directory changed!"); - - switch (event_type) { - case G_FILE_MONITOR_EVENT_DELETED: { - gchar * path = g_file_get_path(file); - g_debug("\tDelete: %s", path); - g_idle_add(blacklist_remove, path); - break; - } - case G_FILE_MONITOR_EVENT_CREATED: { - gchar * path = g_file_get_path(file); - g_debug("\tCreate: %s", path); - g_idle_add(blacklist_add, path); - break; - } - default: - break; - } - - return; -} - /* * More code */ @@ -1186,36 +872,6 @@ indicator_removed (IndicateListener * listener, IndicateListenerServer * server, return; } -static void -app_dir_changed (GFileMonitor * monitor, GFile * file, GFile * other_file, GFileMonitorEvent event_type, gpointer user_data) -{ - gchar * directory = (gchar *)user_data; - g_debug("Application directory changed: %s", directory); - - switch (event_type) { - case G_FILE_MONITOR_EVENT_DELETED: { - gchar * path = g_file_get_path(file); - g_debug("\tDelete: %s", path); - g_idle_add(destroy_launcher, path); - break; - } - case G_FILE_MONITOR_EVENT_CREATED: { - gchar * path = g_file_get_path(file); - g_debug("\tCreate: %s", path); - if (g_str_has_suffix(path, "keyfile")) { - g_idle_add(build_launcher_keyfile, path); - } else { - g_idle_add(build_launcher, path); - } - break; - } - default: - break; - } - - return; -} - /* Check to see if a new desktop file causes any of the launchers to be eclipsed by a running process */ @@ -1251,8 +907,6 @@ remove_eclipses (AppMenuItem * ai) const gchar * aidesktop = app_menu_item_get_desktop(ai); if (aidesktop == NULL) return; - if (blacklist_check(aidesktop)) return; - GList * llitem; for (llitem = launcherList; llitem != NULL; llitem = llitem->next) { launcherList_t * ll = (launcherList_t *)llitem->data; @@ -1268,108 +922,19 @@ remove_eclipses (AppMenuItem * ai) return; } -/* Remove a launcher from the system. We need to figure - out what it's up to! */ -static gboolean -destroy_launcher (gpointer data) -{ - gchar * appdirentry = (gchar *)data; - - GList * listitem; - GList * direntry; - launcherList_t * li; - gchar * appdir; - - for (listitem = launcherList; listitem != NULL; listitem = listitem->next) { - li = (launcherList_t *)listitem->data; - for (direntry = li->appdiritems; direntry != NULL; direntry = direntry->next) { - appdir = (gchar *)direntry->data; - if (!g_strcmp0(appdir, appdirentry)) { - break; - } - } - - if (direntry != NULL) { - break; - } - } - - if (listitem == NULL) { - g_warning("Removed '%s' by the way of it not seeming to exist anywhere.", appdirentry); - return FALSE; - } - - if (g_list_length(li->appdiritems) > 1) { - /* Just remove this item, and we can move on */ - g_debug("Just removing file entry: %s", appdir); - li->appdiritems = g_list_remove(li->appdiritems, appdir); - g_free(appdir); - return FALSE; - } - - /* Full Destroy */ - g_free(appdir); - g_list_free(li->appdiritems); - - if (li->menuitem != NULL) { - /* If there are shortcuts remove them */ - GList * shortcuts = launcher_menu_item_get_items(li->menuitem); - while (shortcuts != NULL) { - dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(shortcuts->data), DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE); - dbusmenu_menuitem_child_delete(DBUSMENU_MENUITEM(data), DBUSMENU_MENUITEM(shortcuts->data)); - shortcuts = g_list_next(shortcuts); - } - - dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(li->menuitem), DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE); - dbusmenu_menuitem_child_delete(root_menuitem, DBUSMENU_MENUITEM(li->menuitem)); - g_object_unref(G_OBJECT(li->menuitem)); - li->menuitem = NULL; - } - - launcherList = g_list_remove(launcherList, li); - g_free(li); - - return FALSE; -} - /* This function turns a specific file into a menu item and registers it appropriately with everyone */ static gboolean build_launcher (gpointer data) { - /* Read the file get the data */ - gchar * path = (gchar *)data; - g_debug("\tpath: %s", path); - gchar * desktop = NULL; - - g_file_get_contents(path, &desktop, NULL, NULL); + gchar *desktop_id = data; + GDesktopAppInfo *appinfo; - if (desktop == NULL) { - g_free(path); - return FALSE; - } + appinfo = g_desktop_app_info_new (desktop_id); + build_launcher_core(g_desktop_app_info_get_filename (appinfo)); - gchar * trimdesktop = pango_trim_string(desktop); - g_free(desktop); - g_debug("\tcontents: %s", trimdesktop); - - build_launcher_core(trimdesktop); - g_free(trimdesktop); - g_free(path); - return FALSE; -} - -/* Use a key file to find the desktop file. */ -static gboolean -build_launcher_keyfile (gpointer data) -{ - gchar * path = (gchar *)data; - gchar * desktop = desktop_file_from_keyfile (path); - if (desktop != NULL) { - build_launcher_core(desktop); - g_free(desktop); - } - g_free(path); + g_object_unref (appinfo); + g_free (desktop_id); return FALSE; } @@ -1411,10 +976,9 @@ build_launcher_core (const gchar * desktop) } dbusmenu_menuitem_child_append(root_menuitem, DBUSMENU_MENUITEM(ll->separator)); - /* If we're in the black list or we've gotten eclipsed - by something else, hide the item and the separator. */ - if (blacklist_check(launcher_menu_item_get_desktop(ll->menuitem)) || - launcher_menu_item_get_eclipsed(ll->menuitem)) { + /* If we've gotten eclipsed by something else, hide the item + * and the separator. */ + if (launcher_menu_item_get_eclipsed(ll->menuitem)) { launcher_menu_item_set_eclipsed(ll->menuitem, TRUE); dbusmenu_menuitem_property_set_bool(ll->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE); } @@ -1445,39 +1009,19 @@ build_launcher_core (const gchar * desktop) static gboolean build_launchers (gpointer data) { - gchar * directory = (gchar *)data; - - if (!g_file_test(directory, G_FILE_TEST_IS_DIR)) { - return FALSE; - } + gchar **applications = g_settings_get_strv (settings, "applications"); + gchar **app; - GFile * filedir = g_file_new_for_path(directory); - GFileMonitor * dirmon = g_file_monitor_directory(filedir, G_FILE_MONITOR_NONE, NULL, NULL); - if (dirmon != NULL) { - g_signal_connect(G_OBJECT(dirmon), "changed", G_CALLBACK(app_dir_changed), directory); - } + g_return_val_if_fail (applications != NULL, FALSE); - GError * error = NULL; - GDir * dir = g_dir_open(directory, 0, &error); - if (dir == NULL) { - g_warning("Unable to open system apps directory: %s", error->message); - g_error_free(error); - return FALSE; - } - - const gchar * filename = NULL; - while ((filename = g_dir_read_name(dir)) != NULL) { - g_debug("Found file: %s", filename); - gchar * path = g_build_filename(directory, filename, NULL); - if (g_str_has_suffix(path, "keyfile")) { - g_idle_add(build_launcher_keyfile, path); - } else { - g_idle_add(build_launcher, path); - } + for (app = applications; *app; app++) + { + g_idle_add(build_launcher, g_strdup (*app)); } - g_dir_close(dir); launcherList = g_list_sort(launcherList, launcherList_sort); + + g_strfreev (applications); return FALSE; } @@ -1566,13 +1110,9 @@ main (int argc, char ** argv) 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); + settings = g_settings_new ("com.canonical.indicator.messages"); + + g_idle_add(build_launchers, NULL); /* Let's run a mainloop */ mainloop = g_main_loop_new(NULL, FALSE); @@ -1580,7 +1120,7 @@ main (int argc, char ** argv) /* Clean up */ status_items_cleanup(); - g_free(userdir); + g_object_unref (settings); return 0; } diff --git a/test/Makefile.am b/test/Makefile.am index 466de1e..9206036 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -43,7 +43,6 @@ libindicator_messages_service_la_HEADERS = \ $(top_srcdir)/src/im-menu-item.h \ $(top_srcdir)/src/app-menu-item.h \ $(top_srcdir)/src/launcher-menu-item.h \ - $(top_srcdir)/src/dirs.h \ $(top_srcdir)/src/dbus-data.h \ $(top_srcdir)/src/status-items.h -- cgit v1.2.3 From 5faae9360d6836f4b5ab59ef2bbbf7cb624bafc1 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 21 May 2012 19:07:25 +0200 Subject: Move build_launcher_core into build_launcher --- src/messages-service.c | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/src/messages-service.c b/src/messages-service.c index 12b1ded..547e527 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -67,7 +67,6 @@ static void indicator_removed (IndicateListener * listener, IndicateListenerServ static void check_eclipses (AppMenuItem * ai); static void remove_eclipses (AppMenuItem * ai); static gboolean build_launcher (gpointer data); -static void build_launcher_core (const gchar * desktop); static gboolean build_launchers (gpointer data); static void check_hidden (void); @@ -170,7 +169,6 @@ typedef struct _launcherList_t launcherList_t; struct _launcherList_t { LauncherMenuItem * menuitem; DbusmenuMenuitem * separator; - GList * appdiritems; }; static gint @@ -928,21 +926,12 @@ static gboolean build_launcher (gpointer data) { gchar *desktop_id = data; + const gchar *desktop = data; GDesktopAppInfo *appinfo; appinfo = g_desktop_app_info_new (desktop_id); - build_launcher_core(g_desktop_app_info_get_filename (appinfo)); + desktop = g_desktop_app_info_get_filename (appinfo); - g_object_unref (appinfo); - g_free (desktop_id); - return FALSE; -} - -/* The core action of dealing with a desktop file that should - be a launcher */ -static void -build_launcher_core (const gchar * desktop) -{ /* Check to see if we already have a launcher */ GList * listitem; for (listitem = launcherList; listitem != NULL; listitem = listitem->next) { @@ -957,7 +946,6 @@ build_launcher_core (const gchar * desktop) /* Build the item */ launcherList_t * ll = g_new0(launcherList_t, 1); ll->menuitem = launcher_menu_item_new(desktop); - ll->appdiritems = g_list_append(NULL, g_strdup(desktop)); /* Build a separator */ ll->separator = dbusmenu_menuitem_new(); @@ -993,13 +981,11 @@ build_launcher_core (const gchar * desktop) resort_menu(root_menuitem); check_hidden(); - } else { - /* If so add ourselves */ - launcherList_t * ll = (launcherList_t *)listitem->data; - ll->appdiritems = g_list_append(ll->appdiritems, g_strdup(desktop)); } - return; + g_object_unref (appinfo); + g_free (desktop_id); + return FALSE; } /* This function goes through all the launchers that we're -- cgit v1.2.3 From 6d16700bcbf52e66fffba24d8077ea7c09ddc771 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 21 May 2012 20:39:05 +0200 Subject: Allow creating AppMenuItems without initial listener / server --- src/app-menu-item.c | 23 ++++++++++++++++++++--- src/app-menu-item.h | 4 +++- src/messages-service.c | 2 +- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/app-menu-item.c b/src/app-menu-item.c index f7b1469..dd218ee 100644 --- a/src/app-menu-item.c +++ b/src/app-menu-item.c @@ -216,12 +216,29 @@ app_menu_item_finalize (GObject *object) } AppMenuItem * -app_menu_item_new (IndicateListener * listener, IndicateListenerServer * server) +app_menu_item_new () +{ + return g_object_new(APP_MENU_ITEM_TYPE, NULL); +} + +AppMenuItem * +app_menu_item_new_with_server (IndicateListener * listener, IndicateListenerServer * server) { AppMenuItem * self = g_object_new(APP_MENU_ITEM_TYPE, NULL); + app_menu_item_set_server (self, listener, server); + return self; +} +void +app_menu_item_set_server (AppMenuItem *self, + IndicateListener *listener, + IndicateListenerServer *server) +{ AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self); + /* only allow setting this once */ + g_return_if_fail (priv->listener == NULL && priv->server == NULL); + /* Copy the listener so we can use it later */ priv->listener = listener; g_object_ref(G_OBJECT(listener)); @@ -247,8 +264,6 @@ app_menu_item_new (IndicateListener * listener, IndicateListenerServer * server) indicate_listener_server_show_interest(listener, server, INDICATE_INTEREST_INDICATOR_DISPLAY); indicate_listener_server_show_interest(listener, server, INDICATE_INTEREST_INDICATOR_SIGNAL); indicate_listener_set_server_max_indicators(listener, server, MAX_NUMBER_OF_INDICATORS); - - return self; } static void @@ -512,6 +527,8 @@ activate_cb (AppMenuItem * self, guint timestamp, gpointer data) { AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self); + g_return_if_fail (priv->listener != NULL && priv->server != NULL); + indicate_listener_display(priv->listener, priv->server, NULL, timestamp); return; diff --git a/src/app-menu-item.h b/src/app-menu-item.h index d616856..a474de0 100644 --- a/src/app-menu-item.h +++ b/src/app-menu-item.h @@ -59,7 +59,9 @@ struct _AppMenuItem { }; GType app_menu_item_get_type (void); -AppMenuItem * app_menu_item_new (IndicateListener * listener, IndicateListenerServer * server); +AppMenuItem * app_menu_item_new (); +AppMenuItem * app_menu_item_new_with_server (IndicateListener * listener, IndicateListenerServer * server); +void app_menu_item_set_server (AppMenuItem *self, IndicateListener *listener, IndicateListenerServer *server); guint app_menu_item_get_count (AppMenuItem * appitem); IndicateListenerServer * app_menu_item_get_server (AppMenuItem * appitem); const gchar * app_menu_item_get_name (AppMenuItem * appitem); diff --git a/src/messages-service.c b/src/messages-service.c index 547e527..1b01e4b 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -286,7 +286,7 @@ server_added (IndicateListener * listener, IndicateListenerServer * server, gcha } /* Build the Menu item */ - AppMenuItem * menuitem = app_menu_item_new(listener, server); + AppMenuItem * menuitem = app_menu_item_new_with_server (listener, server); /* Build a possible server structure */ serverList_t * sl_item = g_new0(serverList_t, 1); -- cgit v1.2.3 From 73e65ee149aceb99eb90cc26ecc80c9933799bce Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Tue, 22 May 2012 13:14:33 +0200 Subject: app-menu-item: remove unneeded priv variable --- src/app-menu-item.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/app-menu-item.c b/src/app-menu-item.c index dd218ee..629a619 100644 --- a/src/app-menu-item.c +++ b/src/app-menu-item.c @@ -50,7 +50,6 @@ struct _AppMenuItemPrivate gchar * type; GAppInfo * appinfo; - GKeyFile * keyfile; gchar * desktop; guint unreadcount; @@ -128,7 +127,6 @@ app_menu_item_init (AppMenuItem *self) priv->server = NULL; priv->type = NULL; priv->appinfo = NULL; - priv->keyfile = NULL; priv->desktop = NULL; priv->unreadcount = 0; @@ -184,11 +182,6 @@ app_menu_item_dispose (GObject *object) priv->appinfo = NULL; } - if (priv->keyfile != NULL) { - g_object_unref(priv->keyfile); - priv->keyfile = NULL; - } - G_OBJECT_CLASS (app_menu_item_parent_class)->dispose (object); } @@ -324,6 +317,7 @@ desktop_cb (IndicateListener * listener, IndicateListenerServer * server, const g_return_if_fail(IS_APP_MENU_ITEM(data)); AppMenuItem * self = APP_MENU_ITEM(data); AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self); + GKeyFile *keyfile; if (priv->appinfo != NULL) { g_object_unref(G_OBJECT(priv->appinfo)); @@ -342,8 +336,8 @@ desktop_cb (IndicateListener * listener, IndicateListenerServer * server, const priv->appinfo = G_APP_INFO(g_desktop_app_info_new_from_filename(value)); g_return_if_fail(priv->appinfo != NULL); - priv->keyfile = g_key_file_new(); - g_key_file_load_from_file(priv->keyfile, value, G_KEY_FILE_NONE, NULL); + keyfile = g_key_file_new(); + g_key_file_load_from_file(keyfile, value, G_KEY_FILE_NONE, NULL); priv->desktop = g_strdup(value); @@ -356,10 +350,10 @@ desktop_cb (IndicateListener * listener, IndicateListenerServer * server, const /* Check for the over ride key and see if we should be using that icon. If we can't get it, then go back to the app info */ - if (g_key_file_has_key(priv->keyfile, G_KEY_FILE_DESKTOP_GROUP, ICON_KEY, NULL) && iconstr == NULL) { + if (g_key_file_has_key(keyfile, G_KEY_FILE_DESKTOP_GROUP, ICON_KEY, NULL) && iconstr == NULL) { GError * error = NULL; - iconstr = g_key_file_get_string(priv->keyfile, G_KEY_FILE_DESKTOP_GROUP, ICON_KEY, &error); + iconstr = g_key_file_get_string(keyfile, G_KEY_FILE_DESKTOP_GROUP, ICON_KEY, &error); if (error != NULL) { /* Can't figure out why this would happen, but sure, let's print something */ @@ -379,6 +373,7 @@ desktop_cb (IndicateListener * listener, IndicateListenerServer * server, const g_signal_emit(G_OBJECT(self), signals[NAME_CHANGED], 0, app_menu_item_get_name(self), TRUE); + g_object_unref(keyfile); return; } -- cgit v1.2.3 From 7b62b8125992d22a9216bd3f113ae3c9ed3b42cf Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Tue, 22 May 2012 13:24:31 +0200 Subject: app-menu-item: remove another unneeded priv variable --- src/app-menu-item.c | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/src/app-menu-item.c b/src/app-menu-item.c index 629a619..8530b3f 100644 --- a/src/app-menu-item.c +++ b/src/app-menu-item.c @@ -49,8 +49,7 @@ struct _AppMenuItemPrivate IndicateListenerServer * server; gchar * type; - GAppInfo * appinfo; - gchar * desktop; + GDesktopAppInfo * appinfo; guint unreadcount; DbusmenuClient * client; @@ -127,7 +126,6 @@ app_menu_item_init (AppMenuItem *self) priv->server = NULL; priv->type = NULL; priv->appinfo = NULL; - priv->desktop = NULL; priv->unreadcount = 0; priv->client = NULL; @@ -198,11 +196,6 @@ app_menu_item_finalize (GObject *object) priv->type = NULL; } - if (priv->desktop != NULL) { - g_free(priv->desktop); - priv->desktop = NULL; - } - G_OBJECT_CLASS (app_menu_item_parent_class)->finalize (object); return; @@ -324,23 +317,16 @@ desktop_cb (IndicateListener * listener, IndicateListenerServer * server, const priv->appinfo = NULL; } - if (priv->desktop != NULL) { - g_free(priv->desktop); - priv->desktop = NULL; - } - if (value == NULL || value[0] == '\0') { return; } - priv->appinfo = G_APP_INFO(g_desktop_app_info_new_from_filename(value)); + priv->appinfo = g_desktop_app_info_new_from_filename(value); g_return_if_fail(priv->appinfo != NULL); keyfile = g_key_file_new(); g_key_file_load_from_file(keyfile, value, G_KEY_FILE_NONE, NULL); - priv->desktop = g_strdup(value); - dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE); dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(self), APPLICATION_MENUITEM_PROP_RUNNING, TRUE); @@ -364,7 +350,7 @@ desktop_cb (IndicateListener * listener, IndicateListenerServer * server, const /* For some reason that didn't work, let's try the app info */ if (iconstr == NULL) { - GIcon * icon = g_app_info_get_icon(priv->appinfo); + GIcon * icon = g_app_info_get_icon(G_APP_INFO(priv->appinfo)); iconstr = g_icon_to_string(icon); } @@ -555,7 +541,7 @@ app_menu_item_get_name (AppMenuItem * appitem) if (priv->appinfo == NULL) { return INDICATE_LISTENER_SERVER_DBUS_NAME(priv->server); } else { - return g_app_info_get_name(priv->appinfo); + return g_app_info_get_name(G_APP_INFO(priv->appinfo)); } } @@ -564,7 +550,7 @@ app_menu_item_get_desktop (AppMenuItem * appitem) { g_return_val_if_fail(IS_APP_MENU_ITEM(appitem), NULL); AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(appitem); - return priv->desktop; + return g_desktop_app_info_get_filename (priv->appinfo); } /* Get the dynamic items added onto the end of -- cgit v1.2.3 From 92e361e3ab3dbf3025875842ff0cfca843015f4d Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Wed, 23 May 2012 11:24:41 +0200 Subject: Allow creating an app menu item without associated indicate server --- src/app-menu-item.c | 120 +++++++++++++++++++++++++++++----------------------- src/app-menu-item.h | 2 +- 2 files changed, 68 insertions(+), 54 deletions(-) diff --git a/src/app-menu-item.c b/src/app-menu-item.c index 8530b3f..6ed00a2 100644 --- a/src/app-menu-item.c +++ b/src/app-menu-item.c @@ -201,10 +201,62 @@ app_menu_item_finalize (GObject *object) return; } +static void +app_menu_item_set_appinfo (AppMenuItem *self, + GDesktopAppInfo *appinfo) +{ + AppMenuItemPrivate *priv = APP_MENU_ITEM_GET_PRIVATE (self); + GKeyFile *keyfile; + gchar *iconstr = NULL; + + g_return_if_fail (appinfo != NULL); + + g_clear_object (&priv->appinfo); + priv->appinfo = g_object_ref (appinfo); + + dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE); + dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(self), APPLICATION_MENUITEM_PROP_RUNNING, TRUE); + + update_label(self); + + keyfile = g_key_file_new(); + g_key_file_load_from_file(keyfile, g_desktop_app_info_get_filename (appinfo), G_KEY_FILE_NONE, NULL); + + /* Check for the over ride key and see if we should be using that + icon. If we can't get it, then go back to the app info */ + if (g_key_file_has_key(keyfile, G_KEY_FILE_DESKTOP_GROUP, ICON_KEY, NULL)) { + GError * error = NULL; + + iconstr = g_key_file_get_string(keyfile, G_KEY_FILE_DESKTOP_GROUP, ICON_KEY, &error); + + if (error != NULL) { + /* Can't figure out why this would happen, but sure, let's print something */ + g_warning("Error getting '" ICON_KEY "' from desktop file: %s", error->message); + g_error_free(error); + } + } + + /* For some reason that didn't work, let's try the app info */ + if (iconstr == NULL) { + GIcon * icon = g_app_info_get_icon(G_APP_INFO(priv->appinfo)); + iconstr = g_icon_to_string(icon); + } + + dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), APPLICATION_MENUITEM_PROP_ICON, iconstr); + g_free(iconstr); + + g_signal_emit(G_OBJECT(self), signals[NAME_CHANGED], 0, app_menu_item_get_name(self), TRUE); + + g_key_file_unref(keyfile); +} + AppMenuItem * -app_menu_item_new () +app_menu_item_new (GDesktopAppInfo *appinfo) { - return g_object_new(APP_MENU_ITEM_TYPE, NULL); + AppMenuItem *self = g_object_new(APP_MENU_ITEM_TYPE, NULL); + if (appinfo) + app_menu_item_set_appinfo (self, appinfo); + return self; } AppMenuItem * @@ -309,58 +361,15 @@ desktop_cb (IndicateListener * listener, IndicateListenerServer * server, const { g_return_if_fail(IS_APP_MENU_ITEM(data)); AppMenuItem * self = APP_MENU_ITEM(data); - AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self); - GKeyFile *keyfile; - - if (priv->appinfo != NULL) { - g_object_unref(G_OBJECT(priv->appinfo)); - priv->appinfo = NULL; - } + GDesktopAppInfo *appinfo; if (value == NULL || value[0] == '\0') { return; } - priv->appinfo = g_desktop_app_info_new_from_filename(value); - g_return_if_fail(priv->appinfo != NULL); - - keyfile = g_key_file_new(); - g_key_file_load_from_file(keyfile, value, G_KEY_FILE_NONE, NULL); - - dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE); - dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(self), APPLICATION_MENUITEM_PROP_RUNNING, TRUE); - - update_label(self); - - gchar * iconstr = NULL; - - /* Check for the over ride key and see if we should be using that - icon. If we can't get it, then go back to the app info */ - if (g_key_file_has_key(keyfile, G_KEY_FILE_DESKTOP_GROUP, ICON_KEY, NULL) && iconstr == NULL) { - GError * error = NULL; - - iconstr = g_key_file_get_string(keyfile, G_KEY_FILE_DESKTOP_GROUP, ICON_KEY, &error); - - if (error != NULL) { - /* Can't figure out why this would happen, but sure, let's print something */ - g_warning("Error getting '" ICON_KEY "' from desktop file: %s", error->message); - g_error_free(error); - } - } - - /* For some reason that didn't work, let's try the app info */ - if (iconstr == NULL) { - GIcon * icon = g_app_info_get_icon(G_APP_INFO(priv->appinfo)); - iconstr = g_icon_to_string(icon); - } - - dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), APPLICATION_MENUITEM_PROP_ICON, iconstr); - g_free(iconstr); - - g_signal_emit(G_OBJECT(self), signals[NAME_CHANGED], 0, app_menu_item_get_name(self), TRUE); - - g_object_unref(keyfile); - return; + appinfo = g_desktop_app_info_new_from_filename(value); + app_menu_item_set_appinfo (self, appinfo); + g_object_unref (appinfo); } /* Relay this signal into causing a rebuild of the shortcuts @@ -538,11 +547,13 @@ app_menu_item_get_name (AppMenuItem * appitem) g_return_val_if_fail(IS_APP_MENU_ITEM(appitem), NULL); AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(appitem); - if (priv->appinfo == NULL) { - return INDICATE_LISTENER_SERVER_DBUS_NAME(priv->server); - } else { + if (priv->appinfo) { return g_app_info_get_name(G_APP_INFO(priv->appinfo)); } + else if (priv->server) { + return INDICATE_LISTENER_SERVER_DBUS_NAME(priv->server); + } + return NULL; } const gchar * @@ -550,7 +561,10 @@ app_menu_item_get_desktop (AppMenuItem * appitem) { g_return_val_if_fail(IS_APP_MENU_ITEM(appitem), NULL); AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(appitem); - return g_desktop_app_info_get_filename (priv->appinfo); + if (priv->appinfo) + return g_desktop_app_info_get_filename (priv->appinfo); + else + return NULL; } /* Get the dynamic items added onto the end of diff --git a/src/app-menu-item.h b/src/app-menu-item.h index a474de0..74efb6a 100644 --- a/src/app-menu-item.h +++ b/src/app-menu-item.h @@ -59,7 +59,7 @@ struct _AppMenuItem { }; GType app_menu_item_get_type (void); -AppMenuItem * app_menu_item_new (); +AppMenuItem * app_menu_item_new (GDesktopAppInfo *appinfo); AppMenuItem * app_menu_item_new_with_server (IndicateListener * listener, IndicateListenerServer * server); void app_menu_item_set_server (AppMenuItem *self, IndicateListener *listener, IndicateListenerServer *server); guint app_menu_item_get_count (AppMenuItem * appitem); -- cgit v1.2.3 From 8960bbafb9805c1e787e70bb2289cb8bc95a5f30 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Wed, 23 May 2012 21:30:00 +0200 Subject: Merge launcher- and appmenuitems --- src/Makefile.am | 2 - src/app-menu-item.c | 59 ++++++- src/launcher-menu-item.c | 362 ----------------------------------------- src/launcher-menu-item.h | 68 -------- src/messages-service.c | 415 +++++++++++++---------------------------------- test/Makefile.am | 2 - 6 files changed, 175 insertions(+), 733 deletions(-) delete mode 100644 src/launcher-menu-item.c delete mode 100644 src/launcher-menu-item.h diff --git a/src/Makefile.am b/src/Makefile.am index fa8c7a5..4fdc8a9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -46,8 +46,6 @@ indicator_messages_service_SOURCES = \ im-menu-item.h \ app-menu-item.c \ app-menu-item.h \ - launcher-menu-item.c \ - launcher-menu-item.h \ dbus-data.h \ \ status-items.c \ diff --git a/src/app-menu-item.c b/src/app-menu-item.c index 6ed00a2..48aef3e 100644 --- a/src/app-menu-item.c +++ b/src/app-menu-item.c @@ -28,6 +28,7 @@ with this program. If not, see . #include #include #include +#include #include "app-menu-item.h" #include "dbus-data.h" @@ -55,6 +56,8 @@ struct _AppMenuItemPrivate DbusmenuClient * client; DbusmenuMenuitem * root; GList * shortcuts; + GList * static_shortcuts; + IndicatorDesktopShortcuts * ids; }; #define APP_MENU_ITEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), APP_MENU_ITEM_TYPE, AppMenuItemPrivate)) @@ -131,6 +134,7 @@ app_menu_item_init (AppMenuItem *self) priv->client = NULL; priv->root = NULL; priv->shortcuts = NULL; + priv->static_shortcuts = NULL; dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE); @@ -165,6 +169,17 @@ app_menu_item_dispose (GObject *object) priv->shortcuts = NULL; } + if (priv->static_shortcuts != NULL) { + g_list_foreach(priv->static_shortcuts, func_unref, object); + g_list_free(priv->static_shortcuts); + priv->static_shortcuts = NULL; + } + + if (priv->ids != NULL) { + g_object_unref(priv->ids); + priv->ids = NULL; + } + if (priv->root != NULL) { g_object_unref(priv->root); priv->root = NULL; @@ -201,6 +216,29 @@ app_menu_item_finalize (GObject *object) return; } +/* Respond to one of the shortcuts getting clicked on. */ +static void +nick_activate_cb (DbusmenuMenuitem * self, guint timestamp, gpointer data) +{ + gchar * nick = g_object_get_data(G_OBJECT(self), "ids-nick-data"); + AppMenuItem * mi = APP_MENU_ITEM(data); + + g_return_if_fail(nick != NULL); + g_return_if_fail(mi != NULL); + + AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(mi); + + g_return_if_fail(priv->ids != NULL); + + if (!indicator_desktop_shortcuts_nick_exec(priv->ids, nick)) { + g_warning("Unable to execute nick '%s' for desktop file '%s'", + nick, g_desktop_app_info_get_filename (priv->appinfo)); + } + + return; +} + + static void app_menu_item_set_appinfo (AppMenuItem *self, GDesktopAppInfo *appinfo) @@ -247,6 +285,24 @@ app_menu_item_set_appinfo (AppMenuItem *self, g_signal_emit(G_OBJECT(self), signals[NAME_CHANGED], 0, app_menu_item_get_name(self), TRUE); + /* Start to build static shortcuts */ + priv->ids = indicator_desktop_shortcuts_new(g_desktop_app_info_get_filename (priv->appinfo), "Messaging Menu"); + const gchar ** nicks = indicator_desktop_shortcuts_get_nicks(priv->ids); + gint i; + for (i = 0; nicks[i] != NULL; i++) { + DbusmenuMenuitem * mi = dbusmenu_menuitem_new(); + dbusmenu_menuitem_property_set(mi, DBUSMENU_MENUITEM_PROP_TYPE, APPLICATION_MENUITEM_TYPE); + g_object_set_data(G_OBJECT(mi), "ids-nick-data", (gpointer)nicks[i]); + + gchar *name = indicator_desktop_shortcuts_nick_get_name(priv->ids, nicks[i]); + dbusmenu_menuitem_property_set(mi, DBUSMENU_MENUITEM_PROP_LABEL, name); + g_free(name); + + g_signal_connect(G_OBJECT(mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(nick_activate_cb), self); + + priv->static_shortcuts = g_list_append(priv->static_shortcuts, mi); + } + g_key_file_unref(keyfile); } @@ -574,5 +630,6 @@ app_menu_item_get_items (AppMenuItem * appitem) { g_return_val_if_fail(IS_APP_MENU_ITEM(appitem), NULL); AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(appitem); - return priv->shortcuts; + return g_list_concat (g_list_copy (priv->shortcuts), + g_list_copy (priv->static_shortcuts)); } diff --git a/src/launcher-menu-item.c b/src/launcher-menu-item.c deleted file mode 100644 index fd04f52..0000000 --- a/src/launcher-menu-item.c +++ /dev/null @@ -1,362 +0,0 @@ -/* -An indicator to show information that is in messaging applications -that the user is using. - -Copyright 2009 Canonical Ltd. - -Authors: - Ted Gould - -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 . -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include "launcher-menu-item.h" -#include "dbus-data.h" - -enum { - NAME_CHANGED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -typedef struct _LauncherMenuItemPrivate LauncherMenuItemPrivate; -struct _LauncherMenuItemPrivate -{ - GAppInfo * appinfo; - GKeyFile * keyfile; - gchar * desktop; - IndicatorDesktopShortcuts * ids; - GList * shortcuts; -}; - -#define LAUNCHER_MENU_ITEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), LAUNCHER_MENU_ITEM_TYPE, LauncherMenuItemPrivate)) - -#define NICK_DATA "ids-nick-data" - -/* Prototypes */ -static void launcher_menu_item_class_init (LauncherMenuItemClass *klass); -static void launcher_menu_item_init (LauncherMenuItem *self); -static void launcher_menu_item_dispose (GObject *object); -static void launcher_menu_item_finalize (GObject *object); -static void activate_cb (LauncherMenuItem * self, guint timestamp, gpointer data); -static void nick_activate_cb (LauncherMenuItem * self, guint timestamp, gpointer data); - - -G_DEFINE_TYPE (LauncherMenuItem, launcher_menu_item, DBUSMENU_TYPE_MENUITEM); - -static void -launcher_menu_item_class_init (LauncherMenuItemClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (LauncherMenuItemPrivate)); - - object_class->dispose = launcher_menu_item_dispose; - object_class->finalize = launcher_menu_item_finalize; - - signals[NAME_CHANGED] = g_signal_new(LAUNCHER_MENU_ITEM_SIGNAL_NAME_CHANGED, - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (LauncherMenuItemClass, name_changed), - NULL, NULL, - g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, 1, G_TYPE_STRING); - - return; -} - -static void -launcher_menu_item_init (LauncherMenuItem *self) -{ - g_debug("Building new Launcher Menu Item"); - LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(self); - - priv->appinfo = NULL; - priv->desktop = NULL; - priv->keyfile = NULL; - - priv->ids = NULL; - priv->shortcuts = NULL; - - dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_TYPE, APPLICATION_MENUITEM_TYPE); - - return; -} - -static void -func_unref (gpointer data, gpointer user_data) -{ - g_object_unref(G_OBJECT(data)); - return; -} - -static void -launcher_menu_item_dispose (GObject *object) -{ - LauncherMenuItem * self = LAUNCHER_MENU_ITEM(object); - LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(self); - - if (priv->appinfo != NULL) { - g_object_unref(priv->appinfo); - priv->appinfo = NULL; - } - - if (priv->keyfile != NULL) { - g_object_unref(priv->keyfile); - priv->keyfile = NULL; - } - - if (priv->ids != NULL) { - g_object_unref(priv->ids); - priv->ids = NULL; - } - - if (priv->shortcuts != NULL) { - g_list_foreach(priv->shortcuts, func_unref, NULL); - g_list_free(priv->shortcuts); - priv->shortcuts = NULL; - } - - G_OBJECT_CLASS (launcher_menu_item_parent_class)->dispose (object); -} - -static void -launcher_menu_item_finalize (GObject *object) -{ - LauncherMenuItem * self = LAUNCHER_MENU_ITEM(object); - LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(self); - - if (priv->desktop != NULL) { - g_free(priv->desktop); - priv->desktop = NULL; - } - - G_OBJECT_CLASS (launcher_menu_item_parent_class)->finalize (object); - - return; -} - -LauncherMenuItem * -launcher_menu_item_new (const gchar * desktop_file) -{ - LauncherMenuItem * self = g_object_new(LAUNCHER_MENU_ITEM_TYPE, NULL); - g_debug("\tDesktop file: %s", desktop_file); - - LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(self); - - /* Parse the desktop file we've been given. */ - priv->appinfo = G_APP_INFO(g_desktop_app_info_new_from_filename(desktop_file)); - priv->keyfile = g_key_file_new(); - g_key_file_load_from_file(priv->keyfile, desktop_file, G_KEY_FILE_NONE, NULL); - priv->desktop = g_strdup(desktop_file); - - /* Set the appropriate values on this menu item based on the - app info that we've parsed */ - g_debug("\tName: %s", launcher_menu_item_get_name(self)); - - dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_LABEL, launcher_menu_item_get_name(self)); - - gchar * iconstr = launcher_menu_item_get_icon(self); - dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_ICON_NAME, iconstr); - g_free(iconstr); - dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE); - - g_signal_connect(G_OBJECT(self), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(activate_cb), NULL); - - /* Start to build static shortcuts */ - priv->ids = indicator_desktop_shortcuts_new(priv->desktop, "Messaging Menu"); - const gchar ** nicks = indicator_desktop_shortcuts_get_nicks(priv->ids); - gint i; - for (i = 0; nicks[i] != NULL; i++) { - DbusmenuMenuitem * mi = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set(mi, DBUSMENU_MENUITEM_PROP_TYPE, APPLICATION_MENUITEM_TYPE); - g_object_set_data(G_OBJECT(mi), NICK_DATA, (gpointer)nicks[i]); - - gchar *name = indicator_desktop_shortcuts_nick_get_name(priv->ids, nicks[i]); - dbusmenu_menuitem_property_set(mi, DBUSMENU_MENUITEM_PROP_LABEL, name); - g_free(name); - - g_signal_connect(G_OBJECT(mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(nick_activate_cb), self); - - priv->shortcuts = g_list_append(priv->shortcuts, mi); - } - - /* Check to see if we should be eclipsed */ - if (priv->appinfo == NULL) { - launcher_menu_item_set_eclipsed(self, TRUE); - } - - return self; -} - -const gchar * -launcher_menu_item_get_name (LauncherMenuItem * appitem) -{ - LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(appitem); - - if (priv->appinfo == NULL) { - return NULL; - } else { - return g_app_info_get_name(priv->appinfo); - } -} - -/* Respond to one of the shortcuts getting clicked on. */ -static void -nick_activate_cb (LauncherMenuItem * self, guint timestamp, gpointer data) -{ - gchar * nick = (gchar *)g_object_get_data(G_OBJECT(self), NICK_DATA); - LauncherMenuItem * lmi = LAUNCHER_MENU_ITEM(data); - - g_return_if_fail(nick != NULL); - g_return_if_fail(lmi != NULL); - - LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(lmi); - - g_return_if_fail(priv->ids != NULL); - - if (!indicator_desktop_shortcuts_nick_exec(priv->ids, nick)) { - g_warning("Unable to execute nick '%s' for desktop file '%s'", nick, priv->desktop); - } - - return; -} - -/* Figure out the appropriate icon for this launcher */ -gchar * -launcher_menu_item_get_icon (LauncherMenuItem * appitem) -{ - LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(appitem); - gchar * retval = NULL; - - /* Check to see if there is a specific icon for the messaging - menu first. */ - if (g_key_file_has_key(priv->keyfile, G_KEY_FILE_DESKTOP_GROUP, ICON_KEY, NULL) && retval == NULL) { - GError * error = NULL; - - retval = g_key_file_get_string(priv->keyfile, G_KEY_FILE_DESKTOP_GROUP, ICON_KEY, &error); - - if (error != NULL) { - /* Can't figure out why this would happen, but sure, let's print something */ - g_warning("Error getting '" ICON_KEY "' from desktop file: %s", error->message); - g_error_free(error); - } - } - - /* If there's not, or there is an error, we'll use the one - from the application info */ - if (priv->appinfo != NULL && retval == NULL) { - GIcon * icon = g_app_info_get_icon(priv->appinfo); - retval = g_icon_to_string(icon); - } - - return retval; -} - -/* When the menu item is clicked on it tries to launch - the application that is represented by the desktop file */ -static void -activate_cb (LauncherMenuItem * self, guint timestamp, gpointer data) -{ - LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(self); - g_return_if_fail(priv->appinfo != NULL); - - GError * error = NULL; - if (!g_app_info_launch(priv->appinfo, NULL, NULL, &error)) { - g_warning("Application failed to launch '%s' because: %s", launcher_menu_item_get_name(self), error->message); - g_error_free(error); - } - - return; -} - -const gchar * -launcher_menu_item_get_desktop (LauncherMenuItem * launchitem) -{ - g_return_val_if_fail(IS_LAUNCHER_MENU_ITEM(launchitem), NULL); - LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(launchitem); - return priv->desktop; -} - -/* Gets the decription for the item that should - go in the messaging menu */ -const gchar * -launcher_menu_item_get_description (LauncherMenuItem * li) -{ - g_return_val_if_fail(IS_LAUNCHER_MENU_ITEM(li), NULL); - LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(li); - return g_app_info_get_description(priv->appinfo); -} - -/* Apply the eclipse value to all the shortcuts */ -static void -eclipse_shortcuts_cb (gpointer data, gpointer user_data) -{ - DbusmenuMenuitem * mi = DBUSMENU_MENUITEM(data); - g_return_if_fail(mi != NULL); - - gboolean eclipsed = GPOINTER_TO_UINT(user_data); - - dbusmenu_menuitem_property_set_bool(mi, DBUSMENU_MENUITEM_PROP_VISIBLE, !eclipsed); - return; -} - -/* Hides the menu item based on whether it is eclipsed - or not. */ -void -launcher_menu_item_set_eclipsed (LauncherMenuItem * li, gboolean eclipsed) -{ - g_return_if_fail(IS_LAUNCHER_MENU_ITEM(li)); - LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(li); - - g_debug("Laucher '%s' is %s", launcher_menu_item_get_name(li), eclipsed ? "now eclipsed" : "shown again"); - dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(li), DBUSMENU_MENUITEM_PROP_VISIBLE, !eclipsed); - - g_list_foreach(priv->shortcuts, eclipse_shortcuts_cb, GINT_TO_POINTER(eclipsed)); - - /* If we're being reshown let's re-evaluate how we should be - showing the label */ - if (!eclipsed) { - dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(li), DBUSMENU_MENUITEM_PROP_LABEL, launcher_menu_item_get_name(li)); - } - - return; -} - -/* Check to see if this item is eclipsed */ -gboolean -launcher_menu_item_get_eclipsed (LauncherMenuItem * li) -{ - gboolean show = dbusmenu_menuitem_property_get_bool(DBUSMENU_MENUITEM(li), DBUSMENU_MENUITEM_PROP_VISIBLE); - g_debug("Launcher check eclipse: %s", show ? "false" : "true"); - return !show; -} - -/* Gets the shortcuts that are associated with this - launcher. They're a list of DbusmenuMenuitems */ -GList * -launcher_menu_item_get_items (LauncherMenuItem * li) -{ - g_return_val_if_fail(IS_LAUNCHER_MENU_ITEM(li), NULL); - LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(li); - return priv->shortcuts; -} diff --git a/src/launcher-menu-item.h b/src/launcher-menu-item.h deleted file mode 100644 index ace1f85..0000000 --- a/src/launcher-menu-item.h +++ /dev/null @@ -1,68 +0,0 @@ -/* -An indicator to show information that is in messaging applications -that the user is using. - -Copyright 2009 Canonical Ltd. - -Authors: - Ted Gould - -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 . -*/ - -#ifndef __LAUNCHER_MENU_ITEM_H__ -#define __LAUNCHER_MENU_ITEM_H__ - -#include -#include - -#include - -G_BEGIN_DECLS - -#define LAUNCHER_MENU_ITEM_TYPE (launcher_menu_item_get_type ()) -#define LAUNCHER_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), LAUNCHER_MENU_ITEM_TYPE, LauncherMenuItem)) -#define LAUNCHER_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), LAUNCHER_MENU_ITEM_TYPE, LauncherMenuItemClass)) -#define IS_LAUNCHER_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LAUNCHER_MENU_ITEM_TYPE)) -#define IS_LAUNCHER_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), LAUNCHER_MENU_ITEM_TYPE)) -#define LAUNCHER_MENU_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), LAUNCHER_MENU_ITEM_TYPE, LauncherMenuItemClass)) - -#define LAUNCHER_MENU_ITEM_SIGNAL_NAME_CHANGED "name-changed" - -typedef struct _LauncherMenuItem LauncherMenuItem; -typedef struct _LauncherMenuItemClass LauncherMenuItemClass; - -struct _LauncherMenuItemClass { - DbusmenuMenuitemClass parent_class; - - void (* name_changed) (gchar * name); -}; - -struct _LauncherMenuItem { - DbusmenuMenuitem parent; -}; - -GType launcher_menu_item_get_type (void); -LauncherMenuItem * launcher_menu_item_new (const gchar * desktop_file); -const gchar * launcher_menu_item_get_name (LauncherMenuItem * appitem); -const gchar * launcher_menu_item_get_desktop (LauncherMenuItem * launchitem); -const gchar * launcher_menu_item_get_description (LauncherMenuItem * li); -gchar * launcher_menu_item_get_icon (LauncherMenuItem * appitem); -void launcher_menu_item_set_eclipsed (LauncherMenuItem * li, gboolean eclipsed); -gboolean launcher_menu_item_get_eclipsed (LauncherMenuItem * li); -GList * launcher_menu_item_get_items (LauncherMenuItem * li); - -G_END_DECLS - -#endif /* __LAUNCHER_MENU_ITEM_H__ */ - diff --git a/src/messages-service.c b/src/messages-service.c index 1b01e4b..0934b9c 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -36,7 +36,6 @@ with this program. If not, see . #include "im-menu-item.h" #include "app-menu-item.h" -#include "launcher-menu-item.h" #include "dbus-data.h" #include "messages-service-dbus.h" #include "status-items.h" @@ -44,7 +43,6 @@ with this program. If not, see . static IndicatorService * service = NULL; static IndicateListener * listener = NULL; static GList * serverList = NULL; -static GList * launcherList = NULL; static DbusmenuMenuitem * root_menuitem = NULL; static DbusmenuMenuitem * status_separator = NULL; @@ -64,11 +62,8 @@ static void server_name_changed (AppMenuItem * appitem, gchar * name, gpointer d static void im_time_changed (ImMenuItem * imitem, glong seconds, gpointer data); static void resort_menu (DbusmenuMenuitem * menushell); static void indicator_removed (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gpointer data); -static void check_eclipses (AppMenuItem * ai); -static void remove_eclipses (AppMenuItem * ai); static gboolean build_launcher (gpointer data); static gboolean build_launchers (gpointer data); -static void check_hidden (void); /* @@ -161,56 +156,6 @@ imList_sort (gconstpointer a, gconstpointer b) return (gint)(im_menu_item_get_seconds(IM_MENU_ITEM(pb->menuitem)) - im_menu_item_get_seconds(IM_MENU_ITEM(pa->menuitem))); } -/* - * Launcher List - */ - -typedef struct _launcherList_t launcherList_t; -struct _launcherList_t { - LauncherMenuItem * menuitem; - DbusmenuMenuitem * separator; -}; - -static gint -launcherList_sort (gconstpointer a, gconstpointer b) -{ - launcherList_t * pa, * pb; - - pa = (launcherList_t *)a; - pb = (launcherList_t *)b; - - const gchar * pan = launcher_menu_item_get_name(pa->menuitem); - const gchar * pbn = launcher_menu_item_get_name(pb->menuitem); - - return g_strcmp0(pan, pbn); -} - -static void -launcherList_count_helper (gpointer data, gpointer user_data) -{ - guint * count = (guint *)user_data; - launcherList_t * li = (launcherList_t *)data; - - if (!launcher_menu_item_get_eclipsed(li->menuitem)) { - *count = *count + 1; - } - - return; -} - -static guint -launcherList_count (void) -{ - guint count = 0; - - g_list_foreach(launcherList, launcherList_count_helper, &count); - - return count; -} - -/* - * More code - */ /* Goes through all the servers and sees if any of them want attention. If they do, then well we'll give it @@ -259,6 +204,84 @@ server_attention (serverList_t * slt) return; } +static void +desktop_cb (IndicateListener *listener, + IndicateListenerServer *server, + const gchar *value, + gpointer data) +{ + DbusmenuMenuitem * menushell = DBUSMENU_MENUITEM(data); + GList *listitem; + serverList_t * sl_item = NULL; + + /* Check to see if we already have a launcher for this app */ + for (listitem = serverList; listitem != NULL; listitem = listitem->next) { + serverList_t * slt = listitem->data; + if (!g_strcmp0(app_menu_item_get_desktop(slt->menuitem), value)) { + sl_item = slt; + break; + } + } + + if (!sl_item) { + /* Build the Menu item */ + AppMenuItem * menuitem = app_menu_item_new_with_server (listener, server); + + /* Build a possible server structure */ + sl_item = g_new0(serverList_t, 1); + sl_item->server = server; + sl_item->menuitem = menuitem; + sl_item->imList = NULL; + sl_item->attention = FALSE; + sl_item->count = 0; + + /* Build a separator */ + sl_item->separator = dbusmenu_menuitem_new(); + dbusmenu_menuitem_property_set(sl_item->separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR); + + /* Connect the signals up to the menu item */ + g_signal_connect(G_OBJECT(menuitem), APP_MENU_ITEM_SIGNAL_COUNT_CHANGED, G_CALLBACK(server_count_changed), sl_item); + g_signal_connect(G_OBJECT(menuitem), APP_MENU_ITEM_SIGNAL_NAME_CHANGED, G_CALLBACK(server_name_changed), menushell); + g_signal_connect(G_OBJECT(menuitem), APP_MENU_ITEM_SIGNAL_SHORTCUT_ADDED, G_CALLBACK(server_shortcut_added), menushell); + g_signal_connect(G_OBJECT(menuitem), APP_MENU_ITEM_SIGNAL_SHORTCUT_REMOVED, G_CALLBACK(server_shortcut_removed), menushell); + + /* Put our new menu item in, with the separator behind it. + resort_menu will take care of whether it should be hidden + or not. */ + dbusmenu_menuitem_child_append(menushell, DBUSMENU_MENUITEM(menuitem)); + + /* Incase we got an indicator first */ + GList * alreadythere = g_list_find_custom(serverList, sl_item, serverList_equal); + if (alreadythere != NULL) { + /* Use the one we already had */ + g_free(sl_item); + sl_item = (serverList_t *)alreadythere->data; + sl_item->menuitem = menuitem; + serverList = g_list_sort(serverList, serverList_sort); + } else { + /* Insert the new one in the list */ + serverList = g_list_insert_sorted(serverList, sl_item, serverList_sort); + } + + dbusmenu_menuitem_child_append(menushell, DBUSMENU_MENUITEM(sl_item->separator)); + } + else { + app_menu_item_set_server (sl_item->menuitem, listener, server); + } + + GList * shortcuts = app_menu_item_get_items(sl_item->menuitem); + GList * shortcut = shortcuts; + while (shortcut != NULL) { + DbusmenuMenuitem * mi = DBUSMENU_MENUITEM(shortcut->data); + g_debug("\tAdding shortcut: %s", dbusmenu_menuitem_property_get(mi, DBUSMENU_MENUITEM_PROP_LABEL)); + dbusmenu_menuitem_child_append(menushell, mi); + shortcut = g_list_next(shortcut); + } + g_list_free (shortcuts); + + resort_menu(menushell); +} + /* A new server has been created on the indicate bus. We need to check to see if we like it. And build structures for it if so. */ @@ -279,65 +302,9 @@ server_added (IndicateListener * listener, IndicateListenerServer * server, gcha return; } - DbusmenuMenuitem * menushell = DBUSMENU_MENUITEM(data); - if (menushell == NULL) { - g_error("\tData in callback is not a menushell"); - return; - } - - /* Build the Menu item */ - AppMenuItem * menuitem = app_menu_item_new_with_server (listener, server); - - /* Build a possible server structure */ - serverList_t * sl_item = g_new0(serverList_t, 1); - sl_item->server = server; - sl_item->menuitem = menuitem; - sl_item->imList = NULL; - sl_item->attention = FALSE; - sl_item->count = 0; - - /* Incase we got an indicator first */ - GList * alreadythere = g_list_find_custom(serverList, sl_item, serverList_equal); - if (alreadythere != NULL) { - /* Use the one we already had */ - g_free(sl_item); - sl_item = (serverList_t *)alreadythere->data; - sl_item->menuitem = menuitem; - serverList = g_list_sort(serverList, serverList_sort); - } else { - /* Insert the new one in the list */ - serverList = g_list_insert_sorted(serverList, sl_item, serverList_sort); - } - - /* Build a separator */ - sl_item->separator = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set(sl_item->separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR); - - /* Connect the signals up to the menu item */ - g_signal_connect(G_OBJECT(menuitem), APP_MENU_ITEM_SIGNAL_COUNT_CHANGED, G_CALLBACK(server_count_changed), sl_item); - g_signal_connect(G_OBJECT(menuitem), APP_MENU_ITEM_SIGNAL_NAME_CHANGED, G_CALLBACK(server_name_changed), menushell); - g_signal_connect(G_OBJECT(menuitem), APP_MENU_ITEM_SIGNAL_SHORTCUT_ADDED, G_CALLBACK(server_shortcut_added), menushell); - g_signal_connect(G_OBJECT(menuitem), APP_MENU_ITEM_SIGNAL_SHORTCUT_REMOVED, G_CALLBACK(server_shortcut_removed), menushell); - - /* Put our new menu item in, with the separator behind it. - resort_menu will take care of whether it should be hidden - or not. */ - dbusmenu_menuitem_child_append(menushell, DBUSMENU_MENUITEM(menuitem)); - - GList * shortcuts = app_menu_item_get_items(sl_item->menuitem); - while (shortcuts != NULL) { - DbusmenuMenuitem * mi = DBUSMENU_MENUITEM(shortcuts->data); - g_debug("\tAdding shortcut: %s", dbusmenu_menuitem_property_get(mi, DBUSMENU_MENUITEM_PROP_LABEL)); - dbusmenu_menuitem_child_append(menushell, mi); - shortcuts = g_list_next(shortcuts); - } - - dbusmenu_menuitem_child_append(menushell, DBUSMENU_MENUITEM(sl_item->separator)); - - resort_menu(menushell); - check_hidden(); - - return; + /* fetch the desktop file before creating the menu item, in case we + * already have a launcher for it */ + indicate_listener_server_get_desktop(listener, server, desktop_cb, data); } /* Server shortcut has been added */ @@ -372,7 +339,6 @@ static void server_name_changed (AppMenuItem * appitem, gchar * name, gpointer data) { serverList = g_list_sort(serverList, serverList_sort); - check_eclipses(appitem); resort_menu(DBUSMENU_MENUITEM(data)); return; } @@ -466,19 +432,18 @@ server_removed (IndicateListener * listener, IndicateListenerServer * server, gc /* Remove from the server list */ serverList = g_list_remove(serverList, sltp); - /* Remove launchers this could be eclipsing */ - remove_eclipses(sltp->menuitem); - /* If there is a menu item, let's get rid of it. */ if (sltp->menuitem != NULL) { /* If there are shortcuts remove them */ GList * shortcuts = app_menu_item_get_items(sltp->menuitem); - while (shortcuts != NULL) { - g_debug("\tRemoving shortcut: %s", dbusmenu_menuitem_property_get(DBUSMENU_MENUITEM(shortcuts->data), DBUSMENU_MENUITEM_PROP_LABEL)); - dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(shortcuts->data), DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE); - dbusmenu_menuitem_child_delete(DBUSMENU_MENUITEM(data), DBUSMENU_MENUITEM(shortcuts->data)); - shortcuts = g_list_next(shortcuts); + GList * shortcut = shortcuts; + while (shortcut != NULL) { + g_debug("\tRemoving shortcut: %s", dbusmenu_menuitem_property_get(DBUSMENU_MENUITEM(shortcut->data), DBUSMENU_MENUITEM_PROP_LABEL)); + dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(shortcut->data), DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE); + dbusmenu_menuitem_child_delete(DBUSMENU_MENUITEM(data), DBUSMENU_MENUITEM(shortcut->data)); + shortcut = g_list_next(shortcut); } + g_list_free (shortcuts); g_debug("\tRemoving item"); dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(sltp->menuitem), DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE); @@ -506,8 +471,6 @@ server_removed (IndicateListener * listener, IndicateListenerServer * server, gc g_free(sltp); - check_hidden(); - return; } @@ -531,9 +494,12 @@ menushell_foreach_cb (DbusmenuMenuitem * data_mi, gpointer data_ms) { AppMenuItem * appmenu = APP_MENU_ITEM(data_mi); if (!g_strcmp0(INDICATE_LISTENER_SERVER_DBUS_NAME((IndicateListenerServer*)msl->server), INDICATE_LISTENER_SERVER_DBUS_NAME(app_menu_item_get_server(appmenu)))) { + GList *shortcuts = app_menu_item_get_items(appmenu); msl->found = TRUE; /* Return a position at the end of our shortcuts */ - msl->position += g_list_length(app_menu_item_get_items(appmenu)); + msl->position += g_list_length(shortcuts); + g_list_free (shortcuts); + } else { msl->position++; } @@ -541,24 +507,6 @@ menushell_foreach_cb (DbusmenuMenuitem * data_mi, gpointer data_ms) { return; } -static void -check_hidden (void) -{ - g_debug("Checking Hidden..."); - gboolean hide = FALSE; - if (launcherList_count() == 0) { - g_debug("\tZero Launchers"); - /* If we don't have visible launchers we need to look more */ - if (g_list_length(serverList) == 0) { - g_debug("\tZero Applications"); - hide = TRUE; - } - } - - message_service_dbus_set_icon(dbus_interface, hide); - return; -} - /* This function takes care of putting the menu in the right order. It basically it rebuilds the order by looking through all the applications and launchers and puts them in the right place. The @@ -569,7 +517,6 @@ resort_menu (DbusmenuMenuitem * menushell) { guint position = 0; GList * serverentry; - GList * launcherentry = launcherList; g_debug("Reordering Menu:"); @@ -581,41 +528,6 @@ resort_menu (DbusmenuMenuitem * menushell) for (serverentry = serverList; serverentry != NULL; serverentry = serverentry->next) { serverList_t * si = (serverList_t *)serverentry->data; - /* Looking to see if there are any launchers we need to insert - into the menu structure. We put as many as we need to. */ - if (launcherentry != NULL) { - launcherList_t * li = (launcherList_t *)launcherentry->data; - while (launcherentry != NULL && g_strcmp0(launcher_menu_item_get_name(li->menuitem), app_menu_item_get_name(si->menuitem)) < 0) { - /* Putting the launcher item in */ - g_debug("\tMoving launcher '%s' to position %d", launcher_menu_item_get_name(li->menuitem), position); - dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(li->menuitem), position); - position++; - - /* Inserting the shortcuts from the launcher */ - GList * shortcuts = launcher_menu_item_get_items(li->menuitem); - while (shortcuts != NULL) { - g_debug("\t\tMoving shortcut to position %d", position); - dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(shortcuts->data), position); - position++; - shortcuts = g_list_next(shortcuts); - } - - /* Putting the launcher separator in */ - g_debug("\tMoving launcher separator to position %d", position); - dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(li->separator), position); - if (!launcher_menu_item_get_eclipsed(li->menuitem)) { - /* Only clear the visiblity if we're not eclipsed */ - dbusmenu_menuitem_property_set_bool(li->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE); - } - position++; - - launcherentry = launcherentry->next; - if (launcherentry != NULL) { - li = (launcherList_t *)launcherentry->data; - } - } - } - /* Putting the app menu item in */ if (si->menuitem != NULL) { g_debug("\tMoving app %s to position %d", INDICATE_LISTENER_SERVER_DBUS_NAME(si->server), position); @@ -624,12 +536,14 @@ resort_menu (DbusmenuMenuitem * menushell) /* Inserting the shortcuts from the launcher */ GList * shortcuts = app_menu_item_get_items(si->menuitem); - while (shortcuts != NULL) { + GList * shortcut = shortcuts; + while (shortcut != NULL) { g_debug("\t\tMoving shortcut to position %d", position); - dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(shortcuts->data), position); + dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(shortcut->data), position); position++; - shortcuts = g_list_next(shortcuts); + shortcut = g_list_next(shortcut); } + g_list_free (shortcuts); } /* Putting all the indicators that are related to this application @@ -668,36 +582,6 @@ resort_menu (DbusmenuMenuitem * menushell) } } - /* Put any leftover launchers in at the end of the list. */ - while (launcherentry != NULL) { - launcherList_t * li = (launcherList_t *)launcherentry->data; - - /* Putting the launcher in */ - g_debug("\tMoving launcher '%s' to position %d", launcher_menu_item_get_name(li->menuitem), position); - dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(li->menuitem), position); - position++; - - /* Inserting the shortcuts from the launcher */ - GList * shortcuts = launcher_menu_item_get_items(li->menuitem); - while (shortcuts != NULL) { - g_debug("\t\tMoving shortcut to position %d", position); - dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(shortcuts->data), position); - position++; - shortcuts = g_list_next(shortcuts); - } - - /* Putting the launcher separator in */ - g_debug("\tMoving launcher separator to position %d", position); - dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(li->separator), position); - if (!launcher_menu_item_get_eclipsed(li->menuitem)) { - /* Only clear the visiblity if we're not eclipsed */ - dbusmenu_menuitem_property_set_bool(li->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE); - } - position++; - - launcherentry = launcherentry->next; - } - if (clear_attention != NULL) { dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), clear_attention, position); position++; /* Not needed, but reduce bugs on code tacked on here, compiler will remove */ @@ -870,73 +754,22 @@ indicator_removed (IndicateListener * listener, IndicateListenerServer * server, return; } -/* Check to see if a new desktop file causes - any of the launchers to be eclipsed by a running - process */ -static void -check_eclipses (AppMenuItem * ai) -{ - g_debug("Checking eclipsing"); - const gchar * aidesktop = app_menu_item_get_desktop(ai); - if (aidesktop == NULL) return; - g_debug("\tApp desktop: %s", aidesktop); - - GList * llitem; - for (llitem = launcherList; llitem != NULL; llitem = llitem->next) { - launcherList_t * ll = (launcherList_t *)llitem->data; - const gchar * lidesktop = launcher_menu_item_get_desktop(ll->menuitem); - g_debug("\tLauncher desktop: %s", lidesktop); - - if (!g_strcmp0(aidesktop, lidesktop)) { - launcher_menu_item_set_eclipsed(ll->menuitem, TRUE); - dbusmenu_menuitem_property_set_bool(ll->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE); - break; - } - } - - return; -} - -/* Remove any eclipses that might have been caused - by this app item that is now retiring */ -static void -remove_eclipses (AppMenuItem * ai) -{ - const gchar * aidesktop = app_menu_item_get_desktop(ai); - if (aidesktop == NULL) return; - - GList * llitem; - for (llitem = launcherList; llitem != NULL; llitem = llitem->next) { - launcherList_t * ll = (launcherList_t *)llitem->data; - const gchar * lidesktop = launcher_menu_item_get_desktop(ll->menuitem); - - if (!g_strcmp0(aidesktop, lidesktop)) { - launcher_menu_item_set_eclipsed(ll->menuitem, FALSE); - dbusmenu_menuitem_property_set_bool(ll->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE); - break; - } - } - - return; -} - /* This function turns a specific file into a menu item and registers it appropriately with everyone */ static gboolean build_launcher (gpointer data) { gchar *desktop_id = data; - const gchar *desktop = data; GDesktopAppInfo *appinfo; + GList *listitem; appinfo = g_desktop_app_info_new (desktop_id); - desktop = g_desktop_app_info_get_filename (appinfo); /* Check to see if we already have a launcher */ - GList * listitem; - for (listitem = launcherList; listitem != NULL; listitem = listitem->next) { - launcherList_t * li = (launcherList_t *)listitem->data; - if (!g_strcmp0(launcher_menu_item_get_desktop(li->menuitem), desktop)) { + for (listitem = serverList; listitem != NULL; listitem = listitem->next) { + serverList_t * slt = listitem->data; + if (!g_strcmp0(app_menu_item_get_desktop(slt->menuitem), + g_desktop_app_info_get_filename (appinfo))) { break; } } @@ -944,43 +777,29 @@ build_launcher (gpointer data) if (listitem == NULL) { /* If not */ /* Build the item */ - launcherList_t * ll = g_new0(launcherList_t, 1); - ll->menuitem = launcher_menu_item_new(desktop); + serverList_t * sl_item = g_new0(serverList_t, 1); + sl_item->menuitem = app_menu_item_new(appinfo); /* Build a separator */ - ll->separator = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set(ll->separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR); + sl_item->separator = dbusmenu_menuitem_new(); + dbusmenu_menuitem_property_set(sl_item->separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR); /* Add it to the list */ - launcherList = g_list_insert_sorted(launcherList, ll, launcherList_sort); + serverList = g_list_insert_sorted (serverList, sl_item, serverList_sort); /* Add it to the menu */ - dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(ll->menuitem), DBUSMENU_MENUITEM_PROP_TYPE, APPLICATION_MENUITEM_TYPE); - dbusmenu_menuitem_child_append(root_menuitem, DBUSMENU_MENUITEM(ll->menuitem)); - GList * shortcuts = launcher_menu_item_get_items(ll->menuitem); - while (shortcuts != NULL) { - dbusmenu_menuitem_child_append(root_menuitem, DBUSMENU_MENUITEM(shortcuts->data)); - shortcuts = g_list_next(shortcuts); - } - dbusmenu_menuitem_child_append(root_menuitem, DBUSMENU_MENUITEM(ll->separator)); - - /* If we've gotten eclipsed by something else, hide the item - * and the separator. */ - if (launcher_menu_item_get_eclipsed(ll->menuitem)) { - launcher_menu_item_set_eclipsed(ll->menuitem, TRUE); - dbusmenu_menuitem_property_set_bool(ll->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE); - } - - /* Check to see if any of the current applications should - be eclipsing us. */ - GList * server; - for (server = serverList; server != NULL; server = g_list_next(server)) { - serverList_t * slt = (serverList_t *)server->data; - check_eclipses(slt->menuitem); + dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(sl_item->menuitem), DBUSMENU_MENUITEM_PROP_TYPE, APPLICATION_MENUITEM_TYPE); + dbusmenu_menuitem_child_append(root_menuitem, DBUSMENU_MENUITEM(sl_item->menuitem)); + GList * shortcuts = app_menu_item_get_items(sl_item->menuitem); + GList * shortcut = shortcuts; + while (shortcut != NULL) { + dbusmenu_menuitem_child_append(root_menuitem, DBUSMENU_MENUITEM(shortcut->data)); + shortcut = g_list_next(shortcut); } + g_list_free (shortcuts); + dbusmenu_menuitem_child_append(root_menuitem, DBUSMENU_MENUITEM(sl_item->separator)); resort_menu(root_menuitem); - check_hidden(); } g_object_unref (appinfo); @@ -1005,7 +824,7 @@ build_launchers (gpointer data) g_idle_add(build_launcher, g_strdup (*app)); } - launcherList = g_list_sort(launcherList, launcherList_sort); + serverList = g_list_sort(serverList, serverList_sort); g_strfreev (applications); return FALSE; diff --git a/test/Makefile.am b/test/Makefile.am index 9206036..bb58ab2 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -42,7 +42,6 @@ libindicator_messages_service_la_HEADERS = \ $(top_srcdir)/src/gen-messages-service.xml.h \ $(top_srcdir)/src/im-menu-item.h \ $(top_srcdir)/src/app-menu-item.h \ - $(top_srcdir)/src/launcher-menu-item.h \ $(top_srcdir)/src/dbus-data.h \ $(top_srcdir)/src/status-items.h @@ -52,7 +51,6 @@ libindicator_messages_service_la_SOURCES = \ $(top_srcdir)/src/gen-messages-service.xml.c \ $(top_srcdir)/src/im-menu-item.c \ $(top_srcdir)/src/app-menu-item.c \ - $(top_srcdir)/src/launcher-menu-item.c \ $(top_srcdir)/src/status-items.c libindicator_messages_service_ladir = \ -- cgit v1.2.3 From e1c600ba95e4520caf471ebf2eb9f41e2580fa98 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Thu, 24 May 2012 22:28:40 +0200 Subject: Port to gmenu, act I Work-in-progress of the gmenu port for the service. The bulk of this patch removes everything related to libindicate from the service. Only the static app launchers and their configured shortcut actions are exported for now. --- configure.ac | 2 - src/Makefile.am | 2 - src/app-menu-item.c | 474 ++++------------------------- src/app-menu-item.h | 17 +- src/dbus-data.h | 4 + src/im-menu-item.c | 586 ----------------------------------- src/im-menu-item.h | 67 ---- src/messages-service.c | 807 ++++--------------------------------------------- src/status-items.c | 89 +++--- src/status-items.h | 4 +- test/Makefile.am | 2 - 11 files changed, 175 insertions(+), 1879 deletions(-) delete mode 100644 src/im-menu-item.c delete mode 100644 src/im-menu-item.h diff --git a/configure.ac b/configure.ac index 148259d..b7602a3 100644 --- a/configure.ac +++ b/configure.ac @@ -41,7 +41,6 @@ AC_PROG_CXX GTK_REQUIRED_VERSION=3.0 GIO_UNIX_REQUIRED_VERSION=2.18 PANEL_REQUIRED_VERSION=2.0.0 -INDICATE_REQUIRED_VERSION=0.6.90 INDICATOR_REQUIRED_VERSION=0.3.19 DBUSMENUGTK_REQUIRED_VERSION=0.5.90 GLIB_REQUIRED_VERSION=2.31.20 @@ -49,7 +48,6 @@ GLIB_REQUIRED_VERSION=2.31.20 PKG_CHECK_MODULES(APPLET, gtk+-3.0 >= $GTK_REQUIRED_VERSION gio-unix-2.0 >= $GIO_UNIX_REQUIRED_VERSION indicator3-0.4 >= $INDICATOR_REQUIRED_VERSION - indicate-0.7 >= $INDICATE_REQUIRED_VERSION dbusmenu-gtk3-0.4 >= $DBUSMENUGTK_REQUIRED_VERSION glib-2.0 >= $GLIB_REQUIRED_VERSION gmodule-2.0 >= $GLIB_REQUIRED_VERSION) diff --git a/src/Makefile.am b/src/Makefile.am index 4fdc8a9..2527878 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -42,8 +42,6 @@ indicator_messages_service_SOURCES = \ messages-service-dbus.h \ gen-messages-service.xml.h \ gen-messages-service.xml.c \ - im-menu-item.c \ - im-menu-item.h \ app-menu-item.c \ app-menu-item.h \ dbus-data.h \ diff --git a/src/app-menu-item.c b/src/app-menu-item.c index 48aef3e..b5d4994 100644 --- a/src/app-menu-item.c +++ b/src/app-menu-item.c @@ -26,17 +26,13 @@ with this program. If not, see . #include #include -#include -#include +#include #include #include "app-menu-item.h" #include "dbus-data.h" enum { - COUNT_CHANGED, NAME_CHANGED, - SHORTCUT_ADDED, - SHORTCUT_REMOVED, LAST_SIGNAL }; @@ -46,18 +42,13 @@ typedef struct _AppMenuItemPrivate AppMenuItemPrivate; struct _AppMenuItemPrivate { - IndicateListener * listener; - IndicateListenerServer * server; - - gchar * type; GDesktopAppInfo * appinfo; guint unreadcount; - DbusmenuClient * client; - DbusmenuMenuitem * root; - GList * shortcuts; - GList * static_shortcuts; IndicatorDesktopShortcuts * ids; + + GMenu *menu; + GSimpleActionGroup *static_shortcuts; }; #define APP_MENU_ITEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), APP_MENU_ITEM_TYPE, AppMenuItemPrivate)) @@ -66,16 +57,12 @@ struct _AppMenuItemPrivate static void app_menu_item_class_init (AppMenuItemClass *klass); static void app_menu_item_init (AppMenuItem *self); static void app_menu_item_dispose (GObject *object); -static void app_menu_item_finalize (GObject *object); -static void activate_cb (AppMenuItem * self, guint timestamp, gpointer data); -static void count_changed (IndicateListener * listener, IndicateListenerServer * server, guint count, gpointer data); -static void count_cb (IndicateListener * listener, IndicateListenerServer * server, guint value, gpointer data); -static void menu_cb (IndicateListener * listener, IndicateListenerServer * server, const gchar * menupath, gpointer data); -static void desktop_cb (IndicateListener * listener, IndicateListenerServer * server, const gchar * value, gpointer data); -static void update_label (AppMenuItem * self); +static void activate_cb (GSimpleAction *action, + GVariant *param, + gpointer userdata); /* GObject Boilerplate */ -G_DEFINE_TYPE (AppMenuItem, app_menu_item, DBUSMENU_TYPE_MENUITEM); +G_DEFINE_TYPE (AppMenuItem, app_menu_item, G_TYPE_OBJECT); static void app_menu_item_class_init (AppMenuItemClass *klass) @@ -85,15 +72,7 @@ app_menu_item_class_init (AppMenuItemClass *klass) g_type_class_add_private (klass, sizeof (AppMenuItemPrivate)); object_class->dispose = app_menu_item_dispose; - object_class->finalize = app_menu_item_finalize; - signals[COUNT_CHANGED] = g_signal_new(APP_MENU_ITEM_SIGNAL_COUNT_CHANGED, - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (AppMenuItemClass, count_changed), - NULL, NULL, - g_cclosure_marshal_VOID__UINT, - G_TYPE_NONE, 1, G_TYPE_UINT); signals[NAME_CHANGED] = g_signal_new(APP_MENU_ITEM_SIGNAL_NAME_CHANGED, G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, @@ -101,22 +80,6 @@ app_menu_item_class_init (AppMenuItemClass *klass) NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); - signals[SHORTCUT_ADDED] = g_signal_new(APP_MENU_ITEM_SIGNAL_SHORTCUT_ADDED, - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (AppMenuItemClass, shortcut_added), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_OBJECT); - signals[SHORTCUT_REMOVED] = g_signal_new(APP_MENU_ITEM_SIGNAL_SHORTCUT_REMOVED, - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (AppMenuItemClass, shortcut_removed), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_OBJECT); - - return; } static void @@ -125,71 +88,29 @@ app_menu_item_init (AppMenuItem *self) g_debug("Building new App Menu Item"); AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self); - priv->listener = NULL; - priv->server = NULL; - priv->type = NULL; priv->appinfo = NULL; priv->unreadcount = 0; - priv->client = NULL; - priv->root = NULL; - priv->shortcuts = NULL; - priv->static_shortcuts = NULL; - - dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE); + priv->menu = g_menu_new (); + priv->static_shortcuts = g_simple_action_group_new (); return; } -/* A wrapper to make the prototypes work for GFunc */ -static void -func_unref (gpointer data, gpointer user_data) -{ - g_signal_emit(user_data, signals[SHORTCUT_REMOVED], 0, data, TRUE); - g_object_unref(G_OBJECT(data)); - return; -} - -/* Disconnect the count_changed signal and unref the listener */ static void app_menu_item_dispose (GObject *object) { AppMenuItem * self = APP_MENU_ITEM(object); AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self); - if (priv->listener != NULL) { - g_signal_handlers_disconnect_by_func(G_OBJECT(priv->listener), count_changed, self); - g_object_unref(priv->listener); - priv->listener = NULL; - } - - if (priv->shortcuts != NULL) { - g_list_foreach(priv->shortcuts, func_unref, object); - g_list_free(priv->shortcuts); - priv->shortcuts = NULL; - } - - if (priv->static_shortcuts != NULL) { - g_list_foreach(priv->static_shortcuts, func_unref, object); - g_list_free(priv->static_shortcuts); - priv->static_shortcuts = NULL; - } + g_clear_object (&priv->menu); + g_clear_object (&priv->static_shortcuts); if (priv->ids != NULL) { g_object_unref(priv->ids); priv->ids = NULL; } - if (priv->root != NULL) { - g_object_unref(priv->root); - priv->root = NULL; - } - - if (priv->client != NULL) { - g_object_unref(priv->client); - priv->client = NULL; - } - if (priv->appinfo != NULL) { g_object_unref(priv->appinfo); priv->appinfo = NULL; @@ -198,34 +119,14 @@ app_menu_item_dispose (GObject *object) G_OBJECT_CLASS (app_menu_item_parent_class)->dispose (object); } -/* Free the memory used by our type, desktop file and application - info structures. */ -static void -app_menu_item_finalize (GObject *object) -{ - AppMenuItem * self = APP_MENU_ITEM(object); - AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self); - - if (priv->type != NULL) { - g_free(priv->type); - priv->type = NULL; - } - - G_OBJECT_CLASS (app_menu_item_parent_class)->finalize (object); - - return; -} - /* Respond to one of the shortcuts getting clicked on. */ static void -nick_activate_cb (DbusmenuMenuitem * self, guint timestamp, gpointer data) +nick_activate_cb (GSimpleAction *action, + GVariant *param, + gpointer userdata) { - gchar * nick = g_object_get_data(G_OBJECT(self), "ids-nick-data"); - AppMenuItem * mi = APP_MENU_ITEM(data); - - g_return_if_fail(nick != NULL); - g_return_if_fail(mi != NULL); - + const gchar * nick = g_action_get_name (G_ACTION (action)); + AppMenuItem * mi = APP_MENU_ITEM (userdata); AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(mi); g_return_if_fail(priv->ids != NULL); @@ -234,29 +135,24 @@ nick_activate_cb (DbusmenuMenuitem * self, guint timestamp, gpointer data) g_warning("Unable to execute nick '%s' for desktop file '%s'", nick, g_desktop_app_info_get_filename (priv->appinfo)); } - - return; } - static void app_menu_item_set_appinfo (AppMenuItem *self, GDesktopAppInfo *appinfo) { AppMenuItemPrivate *priv = APP_MENU_ITEM_GET_PRIVATE (self); + GSimpleAction *launch; + GMenuItem *menuitem; GKeyFile *keyfile; gchar *iconstr = NULL; + gchar *label; g_return_if_fail (appinfo != NULL); g_clear_object (&priv->appinfo); priv->appinfo = g_object_ref (appinfo); - dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE); - dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(self), APPLICATION_MENUITEM_PROP_RUNNING, TRUE); - - update_label(self); - keyfile = g_key_file_new(); g_key_file_load_from_file(keyfile, g_desktop_app_info_get_filename (appinfo), G_KEY_FILE_NONE, NULL); @@ -280,29 +176,47 @@ app_menu_item_set_appinfo (AppMenuItem *self, iconstr = g_icon_to_string(icon); } - dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), APPLICATION_MENUITEM_PROP_ICON, iconstr); - g_free(iconstr); + launch = g_simple_action_new ("launch", NULL); + g_signal_connect (launch, "activate", G_CALLBACK (activate_cb), self); + g_simple_action_group_insert (priv->static_shortcuts, G_ACTION (launch)); - g_signal_emit(G_OBJECT(self), signals[NAME_CHANGED], 0, app_menu_item_get_name(self), TRUE); + if (priv->unreadcount > 0) + label = g_strdup_printf("%s (%d)", app_menu_item_get_name (self), priv->unreadcount); + else + label = g_strdup(app_menu_item_get_name (self)); + + menuitem = g_menu_item_new (label, "launch"); + g_menu_item_set_attribute (menuitem, INDICATOR_MENU_ATTRIBUTE_ICON_NAME, "s", iconstr); + g_menu_append_item (priv->menu, menuitem); /* Start to build static shortcuts */ priv->ids = indicator_desktop_shortcuts_new(g_desktop_app_info_get_filename (priv->appinfo), "Messaging Menu"); const gchar ** nicks = indicator_desktop_shortcuts_get_nicks(priv->ids); gint i; for (i = 0; nicks[i] != NULL; i++) { - DbusmenuMenuitem * mi = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set(mi, DBUSMENU_MENUITEM_PROP_TYPE, APPLICATION_MENUITEM_TYPE); - g_object_set_data(G_OBJECT(mi), "ids-nick-data", (gpointer)nicks[i]); + gchar *name; + GSimpleAction *action; + GMenuItem *item; - gchar *name = indicator_desktop_shortcuts_nick_get_name(priv->ids, nicks[i]); - dbusmenu_menuitem_property_set(mi, DBUSMENU_MENUITEM_PROP_LABEL, name); - g_free(name); + name = indicator_desktop_shortcuts_nick_get_name(priv->ids, nicks[i]); + + action = g_simple_action_new (name, NULL); + g_signal_connect(action, "activate", G_CALLBACK (nick_activate_cb), self); + g_simple_action_group_insert (priv->static_shortcuts, G_ACTION (action)); - g_signal_connect(G_OBJECT(mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(nick_activate_cb), self); + item = g_menu_item_new (name, name); + g_menu_append_item (priv->menu, item); - priv->static_shortcuts = g_list_append(priv->static_shortcuts, mi); + g_object_unref (item); + g_free(name); } + g_signal_emit(G_OBJECT(self), signals[NAME_CHANGED], 0, app_menu_item_get_name(self), TRUE); + + g_free(label); + g_free(iconstr); + g_object_unref (launch); + g_object_unref (menuitem); g_key_file_unref(keyfile); } @@ -315,269 +229,19 @@ app_menu_item_new (GDesktopAppInfo *appinfo) return self; } -AppMenuItem * -app_menu_item_new_with_server (IndicateListener * listener, IndicateListenerServer * server) -{ - AppMenuItem * self = g_object_new(APP_MENU_ITEM_TYPE, NULL); - app_menu_item_set_server (self, listener, server); - return self; -} - -void -app_menu_item_set_server (AppMenuItem *self, - IndicateListener *listener, - IndicateListenerServer *server) -{ - AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self); - - /* only allow setting this once */ - g_return_if_fail (priv->listener == NULL && priv->server == NULL); - - /* Copy the listener so we can use it later */ - priv->listener = listener; - g_object_ref(G_OBJECT(listener)); - - /* Can not ref as not real GObject */ - priv->server = server; - - dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_TYPE, APPLICATION_MENUITEM_TYPE); - - /* Set up listener signals */ - g_signal_connect(G_OBJECT(listener), INDICATE_LISTENER_SIGNAL_SERVER_COUNT_CHANGED, G_CALLBACK(count_changed), self); - - /* Get the values we care about from the server */ - indicate_listener_server_get_desktop(listener, server, desktop_cb, self); - indicate_listener_server_get_count(listener, server, count_cb, self); - indicate_listener_server_get_menu(listener, server, menu_cb, self); - - g_signal_connect(G_OBJECT(self), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(activate_cb), NULL); - - indicate_listener_server_show_interest(listener, server, INDICATE_INTEREST_SERVER_DISPLAY); - indicate_listener_server_show_interest(listener, server, INDICATE_INTEREST_SERVER_SIGNAL); - indicate_listener_server_show_interest(listener, server, INDICATE_INTEREST_INDICATOR_COUNT); - indicate_listener_server_show_interest(listener, server, INDICATE_INTEREST_INDICATOR_DISPLAY); - indicate_listener_server_show_interest(listener, server, INDICATE_INTEREST_INDICATOR_SIGNAL); - indicate_listener_set_server_max_indicators(listener, server, MAX_NUMBER_OF_INDICATORS); -} - static void -update_label (AppMenuItem * self) +activate_cb (GSimpleAction *action, + GVariant *param, + gpointer userdata) { - AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self); - const gchar * name = app_menu_item_get_name(self); - - if (priv->unreadcount > 0) { - /* TRANSLATORS: This is the name of the program and the number of indicators. So it - would read something like "Mail Client (5)" */ - gchar * label = g_strdup_printf(_("%s (%d)"), _(name), priv->unreadcount); - dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), APPLICATION_MENUITEM_PROP_NAME, label); - g_free(label); - } else { - dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), APPLICATION_MENUITEM_PROP_NAME, _(name)); - } - - return; -} - -/* Callback to the signal that the server count - has changed to a new value. This checks to see if - it's actually changed and if so signals everyone and - updates the label. */ -static void -count_changed (IndicateListener * listener, IndicateListenerServer * server, guint count, gpointer data) -{ - g_return_if_fail(IS_APP_MENU_ITEM(data)); - AppMenuItem * self = APP_MENU_ITEM(data); - AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self); - - if (priv->unreadcount != count) { - priv->unreadcount = count; - update_label(self); - g_signal_emit(G_OBJECT(self), signals[COUNT_CHANGED], 0, priv->unreadcount, TRUE); - } - - return; -} - -/* Callback for getting the count property off - of the server. */ -static void -count_cb (IndicateListener * listener, IndicateListenerServer * server, guint value, gpointer data) -{ - count_changed(listener, server, value, data); - return; -} - -/* Callback for when we ask the server for the path - to it's desktop file. We then turn it into an - app structure and start sucking data out of it. - Mostly the name. And the icon. */ -static void -desktop_cb (IndicateListener * listener, IndicateListenerServer * server, const gchar * value, gpointer data) -{ - g_return_if_fail(IS_APP_MENU_ITEM(data)); - AppMenuItem * self = APP_MENU_ITEM(data); - GDesktopAppInfo *appinfo; - - if (value == NULL || value[0] == '\0') { - return; - } - - appinfo = g_desktop_app_info_new_from_filename(value); - app_menu_item_set_appinfo (self, appinfo); - g_object_unref (appinfo); -} - -/* Relay this signal into causing a rebuild of the shortcuts - from those above us. */ -static void -child_added_cb (DbusmenuMenuitem * root, DbusmenuMenuitem * child, guint position, gpointer data) -{ - g_return_if_fail(IS_APP_MENU_ITEM(data)); - AppMenuItem * self = APP_MENU_ITEM(data); - AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self); - DbusmenuMenuitemProxy * mip = dbusmenu_menuitem_proxy_new(child); - - priv->shortcuts = g_list_insert(priv->shortcuts, mip, position); - - g_signal_emit(G_OBJECT(data), signals[SHORTCUT_ADDED], 0, mip, TRUE); - return; -} - -/* Relay this signal into causing a rebuild of the shortcuts - from those above us. */ -static void -child_removed_cb (DbusmenuMenuitem * root, DbusmenuMenuitem * child, gpointer data) -{ - g_return_if_fail(IS_APP_MENU_ITEM(data)); - AppMenuItem * self = APP_MENU_ITEM(data); - AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self); - - GList * pitems = priv->shortcuts; - while (pitems != NULL) { - DbusmenuMenuitemProxy * mip = DBUSMENU_MENUITEM_PROXY(pitems->data); - - if (dbusmenu_menuitem_proxy_get_wrapped(mip) == child) { - break; - } - - pitems = g_list_next(pitems); - } - - if (pitems != NULL) { - DbusmenuMenuitemProxy * mip = DBUSMENU_MENUITEM_PROXY(pitems->data); - priv->shortcuts = g_list_remove(priv->shortcuts, mip); - - g_signal_emit(G_OBJECT(data), signals[SHORTCUT_REMOVED], 0, mip, TRUE); - g_object_unref(mip); - } - - return; -} - -/* Relay this signal into causing a rebuild of the shortcuts - from those above us. */ -static void -child_moved_cb (DbusmenuMenuitem * root, DbusmenuMenuitem * child, guint newpos, guint oldpos, gpointer data) -{ - g_return_if_fail(IS_APP_MENU_ITEM(data)); - AppMenuItem * self = APP_MENU_ITEM(data); - AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self); - - DbusmenuMenuitemProxy * mip = DBUSMENU_MENUITEM_PROXY(g_list_nth_data(priv->shortcuts, oldpos)); - - if (mip != NULL) { - if (dbusmenu_menuitem_proxy_get_wrapped(mip) != child) { - mip = NULL; - } - } - - if (mip != NULL) { - priv->shortcuts = g_list_remove(priv->shortcuts, mip); - priv->shortcuts = g_list_insert(priv->shortcuts, mip, newpos); - g_signal_emit(G_OBJECT(data), signals[SHORTCUT_ADDED], 0, NULL, TRUE); - } - - return; -} - -/* We've got a new root. We need to proxy it and handle it's children - if that's a relevant thing to do. */ -static void -root_changed (DbusmenuClient * client, DbusmenuMenuitem * newroot, gpointer data) -{ - g_debug("Root Changed"); - AppMenuItem * self = APP_MENU_ITEM(data); - AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self); - - if (priv->root != NULL) { - if (dbusmenu_menuitem_get_children(DBUSMENU_MENUITEM(priv->root)) != NULL) { - g_list_foreach(priv->shortcuts, func_unref, data); - g_list_free(priv->shortcuts); - priv->shortcuts = NULL; - } - g_object_unref(priv->root); - priv->root = NULL; - } - - /* We need to proxy the new root across to the old - world of indicator land. */ - priv->root = newroot; - - if (priv->root != NULL) { - g_object_ref(priv->root); - g_signal_connect(G_OBJECT(priv->root), DBUSMENU_MENUITEM_SIGNAL_CHILD_ADDED, G_CALLBACK(child_added_cb), self); - g_signal_connect(G_OBJECT(priv->root), DBUSMENU_MENUITEM_SIGNAL_CHILD_REMOVED, G_CALLBACK(child_removed_cb), self); - g_signal_connect(G_OBJECT(priv->root), DBUSMENU_MENUITEM_SIGNAL_CHILD_MOVED, G_CALLBACK(child_moved_cb), self); - - /* See if we have any menuitems to worry about, - otherwise we'll just move along. */ - GList * children = dbusmenu_menuitem_get_children(DBUSMENU_MENUITEM(priv->root)); - if (children != NULL) { - g_debug("\tProcessing %d children", g_list_length(children)); - while (children != NULL) { - DbusmenuMenuitemProxy * mip = dbusmenu_menuitem_proxy_new(DBUSMENU_MENUITEM(children->data)); - priv->shortcuts = g_list_append(priv->shortcuts, mip); - g_signal_emit(G_OBJECT(self), signals[SHORTCUT_ADDED], 0, mip, TRUE); - children = g_list_next(children); - } - } - } - - return; -} - -/* Gets the path to menuitems if there are some. Now we need to - make them special. */ -static void -menu_cb (IndicateListener * listener, IndicateListenerServer * server, const gchar * menupath, gpointer data) -{ - g_debug("Got Menu: %s", menupath); - g_return_if_fail(IS_APP_MENU_ITEM(data)); - AppMenuItem * self = APP_MENU_ITEM(data); - AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self); - - priv->client = dbusmenu_client_new(indicate_listener_server_get_dbusname(server), menupath); - g_signal_connect(G_OBJECT(priv->client), DBUSMENU_CLIENT_SIGNAL_ROOT_CHANGED, G_CALLBACK(root_changed), self); + AppMenuItem * mi = APP_MENU_ITEM (userdata); + AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(mi); + GError *error = NULL; - DbusmenuMenuitem * root = dbusmenu_client_get_root(priv->client); - if (root != NULL) { - root_changed(priv->client, root, self); + if (!g_app_info_launch (G_APP_INFO (priv->appinfo), NULL, NULL, &error)) { + g_warning("Unable to execute application for desktop file '%s'", + g_desktop_app_info_get_filename (priv->appinfo)); } - - return; -} - -static void -activate_cb (AppMenuItem * self, guint timestamp, gpointer data) -{ - AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self); - - g_return_if_fail (priv->listener != NULL && priv->server != NULL); - - indicate_listener_display(priv->listener, priv->server, NULL, timestamp); - - return; } guint @@ -589,14 +253,6 @@ app_menu_item_get_count (AppMenuItem * appitem) return priv->unreadcount; } -IndicateListenerServer * -app_menu_item_get_server (AppMenuItem * appitem) { - g_return_val_if_fail(IS_APP_MENU_ITEM(appitem), NULL); - AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(appitem); - - return priv->server; -} - const gchar * app_menu_item_get_name (AppMenuItem * appitem) { @@ -606,9 +262,6 @@ app_menu_item_get_name (AppMenuItem * appitem) if (priv->appinfo) { return g_app_info_get_name(G_APP_INFO(priv->appinfo)); } - else if (priv->server) { - return INDICATE_LISTENER_SERVER_DBUS_NAME(priv->server); - } return NULL; } @@ -623,13 +276,10 @@ app_menu_item_get_desktop (AppMenuItem * appitem) return NULL; } -/* Get the dynamic items added onto the end of - and app entry. */ -GList * -app_menu_item_get_items (AppMenuItem * appitem) +GMenuModel * +app_menu_item_get_menu (AppMenuItem *appitem) { - g_return_val_if_fail(IS_APP_MENU_ITEM(appitem), NULL); AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(appitem); - return g_list_concat (g_list_copy (priv->shortcuts), - g_list_copy (priv->static_shortcuts)); + return G_MENU_MODEL (priv->menu); } + diff --git a/src/app-menu-item.h b/src/app-menu-item.h index 74efb6a..785a997 100644 --- a/src/app-menu-item.h +++ b/src/app-menu-item.h @@ -22,11 +22,7 @@ with this program. If not, see . #ifndef __APP_MENU_ITEM_H__ #define __APP_MENU_ITEM_H__ -#include -#include - -#include -#include +#include G_BEGIN_DECLS @@ -46,27 +42,22 @@ typedef struct _AppMenuItem AppMenuItem; typedef struct _AppMenuItemClass AppMenuItemClass; struct _AppMenuItemClass { - DbusmenuMenuitemClass parent_class; + GObjectClass parent_class; void (* count_changed) (guint count); void (* name_changed) (gchar * name); - void (* shortcut_added) (DbusmenuMenuitem * mi); - void (* shortcut_removed) (DbusmenuMenuitem * mi); }; struct _AppMenuItem { - DbusmenuMenuitem parent; + GObject parent; }; GType app_menu_item_get_type (void); AppMenuItem * app_menu_item_new (GDesktopAppInfo *appinfo); -AppMenuItem * app_menu_item_new_with_server (IndicateListener * listener, IndicateListenerServer * server); -void app_menu_item_set_server (AppMenuItem *self, IndicateListener *listener, IndicateListenerServer *server); guint app_menu_item_get_count (AppMenuItem * appitem); -IndicateListenerServer * app_menu_item_get_server (AppMenuItem * appitem); const gchar * app_menu_item_get_name (AppMenuItem * appitem); const gchar * app_menu_item_get_desktop (AppMenuItem * appitem); -GList * app_menu_item_get_items (AppMenuItem * appitem); +GMenuModel * app_menu_item_get_menu (AppMenuItem *appitem); G_END_DECLS diff --git a/src/dbus-data.h b/src/dbus-data.h index 1e82ded..d7efd86 100644 --- a/src/dbus-data.h +++ b/src/dbus-data.h @@ -25,4 +25,8 @@ have a better place to put it. */ #define ICON_KEY "X-Ayatana-Messaging-Menu-Icon" +#define INDICATOR_MENU_ATTRIBUTE_VISIBLE "indicator-visible" +#define INDICATOR_MENU_ATTRIBUTE_ENABLED "indicator-enabled" +#define INDICATOR_MENU_ATTRIBUTE_ICON_NAME "indicator-icon-name" + #endif /* __DBUS_DATA_H__ */ diff --git a/src/im-menu-item.c b/src/im-menu-item.c deleted file mode 100644 index 7466d3e..0000000 --- a/src/im-menu-item.c +++ /dev/null @@ -1,586 +0,0 @@ -/* -An indicator to show information that is in messaging applications -that the user is using. - -Copyright 2009 Canonical Ltd. - -Authors: - Ted Gould - -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 . -*/ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include "im-menu-item.h" -#include "dbus-data.h" - -enum { - TIME_CHANGED, - ATTENTION_CHANGED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -typedef struct _ImMenuItemPrivate ImMenuItemPrivate; - -struct _ImMenuItemPrivate -{ - IndicateListener * listener; - IndicateListenerServer * server; - IndicateListenerIndicator * indicator; - - glong creation_seconds; - glong seconds; - gchar * count; - gulong indicator_changed; - gboolean attention; - gboolean show; - - guint time_update_min; -}; - -#define IM_MENU_ITEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), IM_MENU_ITEM_TYPE, ImMenuItemPrivate)) - -/* Prototypes */ -static void im_menu_item_class_init (ImMenuItemClass *klass); -static void im_menu_item_init (ImMenuItem *self); -static void im_menu_item_dispose (GObject *object); -static void im_menu_item_finalize (GObject *object); -static void sender_cb (IndicateListener * listener, - IndicateListenerServer * server, - IndicateListenerIndicator * indicator, - gchar * property, - const gchar * propertydata, - gpointer data); -static void time_cb (IndicateListener * listener, - IndicateListenerServer * server, - IndicateListenerIndicator * indicator, - gchar * property, - const GTimeVal * propertydata, - gpointer data); -static void icon_cb (IndicateListener * listener, - IndicateListenerServer * server, - IndicateListenerIndicator * indicator, - gchar * property, - const gchar * propertydata, - gpointer data); -static void activate_cb (ImMenuItem * self, - guint timestamp, - gpointer data); -static void indicator_modified_cb (IndicateListener * listener, - IndicateListenerServer * server, - IndicateListenerIndicator * indicator, - gchar * property, - ImMenuItem * self); - -G_DEFINE_TYPE (ImMenuItem, im_menu_item, DBUSMENU_TYPE_MENUITEM); - -static void -im_menu_item_class_init (ImMenuItemClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (ImMenuItemPrivate)); - - object_class->dispose = im_menu_item_dispose; - object_class->finalize = im_menu_item_finalize; - - signals[TIME_CHANGED] = g_signal_new(IM_MENU_ITEM_SIGNAL_TIME_CHANGED, - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (ImMenuItemClass, time_changed), - NULL, NULL, - g_cclosure_marshal_VOID__LONG, - G_TYPE_NONE, 1, G_TYPE_LONG); - signals[ATTENTION_CHANGED] = g_signal_new(IM_MENU_ITEM_SIGNAL_ATTENTION_CHANGED, - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (ImMenuItemClass, attention_changed), - NULL, NULL, - g_cclosure_marshal_VOID__BOOLEAN, - G_TYPE_NONE, 1, G_TYPE_BOOLEAN); - - return; -} - -static void -im_menu_item_init (ImMenuItem *self) -{ - g_debug("Building new IM Menu Item"); - ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(self); - - /* Set the variables to NULL, but they should be - configured further down the line. */ - priv->listener = NULL; - priv->server = NULL; - priv->indicator = NULL; - - /* A sane default, but look below */ - priv->creation_seconds = 0; - priv->seconds = 0; - - /* Set the seconds to be the time when the item was - created incase we're not given a better time. */ - GTimeVal current_time; - g_get_current_time(¤t_time); - priv->creation_seconds = current_time.tv_sec; - - return; -} - -static void -im_menu_item_dispose (GObject *object) -{ - G_OBJECT_CLASS (im_menu_item_parent_class)->dispose (object); - - ImMenuItem * self = IM_MENU_ITEM(object); - ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(self); - - if (priv->time_update_min != 0) { - g_source_remove(priv->time_update_min); - } - - g_signal_handler_disconnect(priv->listener, priv->indicator_changed); - priv->indicator_changed = 0; - - return; -} - -static void -im_menu_item_finalize (GObject *object) -{ - G_OBJECT_CLASS (im_menu_item_parent_class)->finalize (object); -} - -/* Call back for getting icon data. It just passes it along - to the indicator so that it can visualize it. Not our problem. */ -static void -icon_cb (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * property, const gchar * propertydata, gpointer data) -{ - gsize len; - guchar *icon; - icon = g_base64_decode (propertydata, &len); - dbusmenu_menuitem_property_set_byte_array(DBUSMENU_MENUITEM(data), INDICATOR_MENUITEM_PROP_ICON, icon, len); - g_free (icon); - return; -} - -/* This function takes the time and turns it into the appropriate - string to put on the right side of the menu item. Of course it - doesn't do that if there is a count set. If there's a count then - it gets that space. */ -static void -update_time (ImMenuItem * self) -{ - ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(self); - - /* Count has been set, so it takes priority. */ - if (priv->count != NULL) { - return; - } - - /* Seconds hasn't been set, so we just want to keep the time - area blank. */ - if (priv->seconds == 0) { - dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), INDICATOR_MENUITEM_PROP_RIGHT, ""); - return; - } - - gchar * timestring = NULL; - - GTimeVal current_time; - g_get_current_time(¤t_time); - - guint elapsed_seconds = current_time.tv_sec - priv->seconds; - guint elapsed_minutes = elapsed_seconds / 60; - - if (elapsed_seconds % 60 > 55) { - /* We're using fuzzy timers, so we need fuzzy comparisons */ - elapsed_minutes += 1; - } - - if (elapsed_minutes < 60) { - /* TRANSLATORS: This string is used to represent the number of minutes - since an IM has occured. It is in the right column - of a menu so being brief is desirable, but one character - is not a requirement. */ - timestring = g_strdup_printf(ngettext("%d m", "%d m", elapsed_minutes), elapsed_minutes); - } else { - guint elapsed_hours = elapsed_minutes / 60; - - if (elapsed_minutes % 60 > 55) { - /* We're using fuzzy timers, so we need fuzzy comparisons */ - elapsed_hours += 1; - } - - /* TRANSLATORS: This string is used to represent the number of hours - since an IM has occured. It is in the right column - of a menu so being brief is desirable, but one character - is not a requirement. */ - timestring = g_strdup_printf(ngettext("%d h", "%d h", elapsed_hours), elapsed_hours); - } - - if (timestring != NULL) { - dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), INDICATOR_MENUITEM_PROP_RIGHT, timestring); - g_free(timestring); - } - - return; -} - -/* This is a wrapper around update_time that matches the prototype - needed to make this a timer callback. Silly. */ -static gboolean -time_update_cb (gpointer data) -{ - ImMenuItem * self = IM_MENU_ITEM(data); - - update_time(self); - - return TRUE; -} - -/* Yet another time function. This one takes the time as formated as - we get it from libindicate and turns it into the seconds that we're - looking for. It should only be called once at the init with a new - indicator and again when the value changes. */ -static void -time_cb (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * property, const GTimeVal * propertydata, gpointer data) -{ - g_debug("Got Time info"); - ImMenuItem * self = IM_MENU_ITEM(data); - if (self == NULL) { - g_error("Menu Item callback called without a menu item"); - return; - } - - if (property == NULL || g_strcmp0(property, "time")) { - g_warning("Time callback called without being sent the time."); - return; - } - - ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(self); - - priv->seconds = propertydata->tv_sec; - - update_time(self); - - if (priv->time_update_min == 0) { - priv->time_update_min = g_timeout_add_seconds(60, time_update_cb, self); - } - - g_signal_emit(G_OBJECT(self), signals[TIME_CHANGED], 0, priv->seconds, TRUE); - - return; -} - -/* Returns a newly allocated string which is 'str' with all occurences of - * consecutive whitespace collapsed into single space character. */ -static gchar * -collapse_whitespace (const gchar *str) -{ - GString *result; - gboolean in_space = FALSE; - - if (!str) - return NULL; - - result = g_string_sized_new (strlen (str)); - - while (*str) { - gunichar c = g_utf8_get_char_validated (str, -1); - - if (c < 0) - break; - - if (!g_unichar_isspace (c)) { - g_string_append_unichar (result, c); - in_space = FALSE; - } - else if (!in_space) { - g_string_append_c (result, ' '); - in_space = TRUE; - } - - str = g_utf8_next_char (str); - } - - return g_string_free (result, FALSE); -} - -/* Callback from libindicate that is for getting the sender information - on a particular indicator. */ -static void -sender_cb (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * property, const gchar * propertydata, gpointer data) -{ - gchar *label; - - g_debug("Got Sender Information: %s", propertydata); - ImMenuItem * self = IM_MENU_ITEM(data); - - /* Our data should be right */ - g_return_if_fail(self != NULL); - /* We should have a property name */ - g_return_if_fail(property != NULL); - /* The Property should be sender or name */ - g_return_if_fail(!g_strcmp0(property, "sender") || !g_strcmp0(property, INDICATE_INDICATOR_MESSAGES_PROP_NAME)); - - /* We might get the sender variable returning a - null string as it doesn't exist on newer clients - but we don't want to listen to that. */ - if (!g_strcmp0(property, "sender") && propertydata[0] == '\0') { - return; - } - - label = collapse_whitespace (propertydata); - dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), INDICATOR_MENUITEM_PROP_LABEL, label); - g_free (label); - - return; -} - -/* Callback saying that the count is updated, we need to either put - that on the menu item or just remove it if the count is gone. If - that's the case we can update time. */ -static void -count_cb (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * property, const gchar * propertydata, gpointer data) -{ - g_debug("Got Count Information"); - ImMenuItem * self = IM_MENU_ITEM(data); - - /* Our data should be right */ - g_return_if_fail(self != NULL); - /* We should have a property name */ - g_return_if_fail(property != NULL); - /* The Property should be count */ - g_return_if_fail(!g_strcmp0(property, INDICATE_INDICATOR_MESSAGES_PROP_COUNT)); - - ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(self); - - if (propertydata == NULL || propertydata[0] == '\0') { - /* The count is either being unset or it was never - set in the first place. */ - if (priv->count != NULL) { - g_free(priv->count); - priv->count = NULL; - update_time(self); - dbusmenu_menuitem_property_set_bool (DBUSMENU_MENUITEM (self), - INDICATOR_MENUITEM_PROP_RIGHT_IS_LOZENGE, - FALSE); - } - return; - } - - if (priv->count != NULL) { - g_free(priv->count); - } - - priv->count = g_strdup_printf("%s", propertydata); - dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), INDICATOR_MENUITEM_PROP_RIGHT, priv->count); - dbusmenu_menuitem_property_set_bool (DBUSMENU_MENUITEM (self), - INDICATOR_MENUITEM_PROP_RIGHT_IS_LOZENGE, - TRUE); - - return; -} - -/* This is getting the attention variable that's looking at whether - this indicator should be calling for attention or not. If we are, - we need to signal that. */ -static void -attention_cb (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * property, GVariant * propertydata, gpointer data) -{ - g_debug("Got Attention Information"); - ImMenuItem * self = IM_MENU_ITEM(data); - - /* Our data should be right */ - g_return_if_fail(self != NULL); - /* We should have a property name */ - g_return_if_fail(property != NULL); - /* The Property should be count */ - g_return_if_fail(!g_strcmp0(property, INDICATE_INDICATOR_MESSAGES_PROP_ATTENTION)); - - ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(self); - - gboolean wantit; - if (g_variant_is_of_type(propertydata, G_VARIANT_TYPE_BOOLEAN)) { - wantit = g_variant_get_boolean(propertydata); - } else if (g_variant_is_of_type(propertydata, G_VARIANT_TYPE_STRING)) { - const gchar * propstring = g_variant_get_string(propertydata, NULL); - - if (propstring == NULL || propstring[0] == '\0' || !g_strcmp0(propstring, "false")) { - wantit = FALSE; - } else { - wantit = TRUE; - } - } else { - g_warning("Got property '%s' of an unknown type.", property); - return; - } - - if (priv->attention != wantit) { - priv->attention = wantit; - g_signal_emit(G_OBJECT(self), signals[ATTENTION_CHANGED], 0, wantit, TRUE); - } - - return; -} - -/* Callback when the item gets clicked on from the Messaging Menu */ -static void -activate_cb (ImMenuItem * self, guint timestamp, gpointer data) -{ - ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(self); - - indicate_listener_display(priv->listener, priv->server, priv->indicator, timestamp); -} - -/* Callback when a property gets modified. It figures out which one - got modified and notifies the appropriate person. */ -void -indicator_modified_cb (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * property, ImMenuItem * self) -{ - ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(self); - - /* Not meant for us */ - if (INDICATE_LISTENER_INDICATOR_ID(indicator) != INDICATE_LISTENER_INDICATOR_ID(priv->indicator)) return; - if (server != priv->server) return; - - /* Determine which property has been changed and request the - value go to the appropriate callback. */ - if (!g_strcmp0(property, INDICATE_INDICATOR_MESSAGES_PROP_NAME)) { - indicate_listener_get_property(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_NAME, sender_cb, self); - } else if (!g_strcmp0(property, INDICATE_INDICATOR_MESSAGES_PROP_TIME)) { - indicate_listener_get_property_time(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_TIME, time_cb, self); - } else if (!g_strcmp0(property, INDICATE_INDICATOR_MESSAGES_PROP_ICON)) { - indicate_listener_get_property(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_ICON, icon_cb, self); - } else if (!g_strcmp0(property, INDICATE_INDICATOR_MESSAGES_PROP_COUNT)) { - indicate_listener_get_property(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_COUNT, count_cb, self); - } else if (!g_strcmp0(property, INDICATE_INDICATOR_MESSAGES_PROP_ATTENTION)) { - indicate_listener_get_property_variant(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_ATTENTION, attention_cb, self); - } else if (!g_strcmp0(property, "sender")) { - /* This is a compatibility string with v1 and should be removed */ - g_debug("Indicator is using 'sender' property which is a v1 string."); - indicate_listener_get_property(listener, server, indicator, "sender", sender_cb, self); - } - - return; -} - -ImMenuItem * -im_menu_item_new (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator) -{ - ImMenuItem * self = g_object_new(IM_MENU_ITEM_TYPE, NULL); - - ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(self); - - priv->listener = listener; - priv->server = server; - priv->indicator = indicator; - priv->count = NULL; - priv->time_update_min = 0; - priv->attention = FALSE; - priv->show = TRUE; - - dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_TYPE, INDICATOR_MENUITEM_TYPE); - - indicate_listener_displayed(listener, server, indicator, TRUE); - - indicate_listener_get_property(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_NAME, sender_cb, self); - indicate_listener_get_property_time(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_TIME, time_cb, self); - indicate_listener_get_property(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_ICON, icon_cb, self); - indicate_listener_get_property(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_COUNT, count_cb, self); - indicate_listener_get_property_variant(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_ATTENTION, attention_cb, self); - indicate_listener_get_property(listener, server, indicator, "sender", sender_cb, self); - - g_signal_connect(G_OBJECT(self), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(activate_cb), NULL); - priv->indicator_changed = g_signal_connect(G_OBJECT(listener), INDICATE_LISTENER_SIGNAL_INDICATOR_MODIFIED, G_CALLBACK(indicator_modified_cb), self); - - return self; -} - -/* Gets the number of seconds for the creator - of this item. */ -glong -im_menu_item_get_seconds (ImMenuItem * menuitem) -{ - g_return_val_if_fail(IS_IM_MENU_ITEM(menuitem), 0); - - ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(menuitem); - - if (priv->seconds == 0) { - return priv->creation_seconds; - } else { - return priv->seconds; - } -} - -/* Gets whether or not this indicator item is - asking for attention or not. */ -gboolean -im_menu_item_get_attention (ImMenuItem * menuitem) -{ - g_return_val_if_fail(IS_IM_MENU_ITEM(menuitem), FALSE); - - ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(menuitem); - return priv->attention; -} - -/* This takes care of items that need to be hidden, this is - usually because they go over the count of allowed indicators. - Which is more than a little bit silly. We shouldn't do that. - But we need to enforce it to save users against bad apps. */ -void -im_menu_item_show (ImMenuItem * menuitem, gboolean show) -{ - g_return_if_fail(IS_IM_MENU_ITEM(menuitem)); - - ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(menuitem); - - if (priv->show == show) { - return; - } - - priv->show = show; - /* Tell the app what we're doing to it. If it's being - punished it needs to know about it. */ - indicate_listener_displayed(priv->listener, priv->server, priv->indicator, priv->show); - if (priv->attention) { - /* If we were asking for attention we can ask for it - again if we're being shown, otherwise no. */ - g_signal_emit(G_OBJECT(menuitem), signals[ATTENTION_CHANGED], 0, priv->show, TRUE); - } - dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(menuitem), DBUSMENU_MENUITEM_PROP_VISIBLE, priv->show ? "true" : "false"); - - return; -} - -/* Check to see if this item is shown. Accessor for the - internal variable. */ -gboolean -im_menu_item_shown (ImMenuItem * menuitem) -{ - g_return_val_if_fail(IS_IM_MENU_ITEM(menuitem), FALSE); - - ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(menuitem); - - return priv->show; -} diff --git a/src/im-menu-item.h b/src/im-menu-item.h deleted file mode 100644 index 4279c2e..0000000 --- a/src/im-menu-item.h +++ /dev/null @@ -1,67 +0,0 @@ -/* -An indicator to show information that is in messaging applications -that the user is using. - -Copyright 2009 Canonical Ltd. - -Authors: - Ted Gould - -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 . -*/ -#ifndef __IM_MENU_ITEM_H__ -#define __IM_MENU_ITEM_H__ - -#include -#include - -#include -#include - -G_BEGIN_DECLS - -#define IM_MENU_ITEM_TYPE (im_menu_item_get_type ()) -#define IM_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IM_MENU_ITEM_TYPE, ImMenuItem)) -#define IM_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), IM_MENU_ITEM_TYPE, ImMenuItemClass)) -#define IS_IM_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IM_MENU_ITEM_TYPE)) -#define IS_IM_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), IM_MENU_ITEM_TYPE)) -#define IM_MENU_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), IM_MENU_ITEM_TYPE, ImMenuItemClass)) - -#define IM_MENU_ITEM_SIGNAL_TIME_CHANGED "time-changed" -#define IM_MENU_ITEM_SIGNAL_ATTENTION_CHANGED "attention-changed" - -typedef struct _ImMenuItem ImMenuItem; -typedef struct _ImMenuItemClass ImMenuItemClass; - -struct _ImMenuItemClass { - DbusmenuMenuitemClass parent_class; - - void (*time_changed) (glong seconds); - void (*attention_changed) (gboolean requestit); -}; - -struct _ImMenuItem { - DbusmenuMenuitem parent; -}; - -GType im_menu_item_get_type (void); -ImMenuItem * im_menu_item_new (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator); -glong im_menu_item_get_seconds (ImMenuItem * menuitem); -gboolean im_menu_item_get_attention (ImMenuItem * menuitem); -void im_menu_item_show (ImMenuItem * menuitem, gboolean show); -gboolean im_menu_item_shown (ImMenuItem * menuitem); - -G_END_DECLS - -#endif - diff --git a/src/messages-service.c b/src/messages-service.c index 0934b9c..432846e 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -25,46 +25,27 @@ with this program. If not, see . #include #include #include -#include #include #include #include #include -#include -#include - -#include "im-menu-item.h" #include "app-menu-item.h" #include "dbus-data.h" #include "messages-service-dbus.h" #include "status-items.h" static IndicatorService * service = NULL; -static IndicateListener * listener = NULL; static GList * serverList = NULL; -static DbusmenuMenuitem * root_menuitem = NULL; -static DbusmenuMenuitem * status_separator = NULL; -static DbusmenuMenuitem * clear_attention = NULL; +static GDBusConnection *bus; +static GSimpleActionGroup *actions; +static GMenu *menu; static GSettings *settings; static GMainLoop * mainloop = NULL; static MessageServiceDbus * dbus_interface = NULL; -#define DESKTOP_FILE_GROUP "Messaging Menu" -#define DESKTOP_FILE_KEY_DESKTOP "DesktopFile" - -static void server_shortcut_added (AppMenuItem * appitem, DbusmenuMenuitem * mi, gpointer data); -static void server_shortcut_removed (AppMenuItem * appitem, DbusmenuMenuitem * mi, gpointer data); -static void server_count_changed (AppMenuItem * appitem, guint count, gpointer data); -static void server_name_changed (AppMenuItem * appitem, gchar * name, gpointer data); -static void im_time_changed (ImMenuItem * imitem, glong seconds, gpointer data); -static void resort_menu (DbusmenuMenuitem * menushell); -static void indicator_removed (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gpointer data); -static gboolean build_launcher (gpointer data); -static gboolean build_launchers (gpointer data); - /* * Server List @@ -72,33 +53,12 @@ static gboolean build_launchers (gpointer data); typedef struct _serverList_t serverList_t; struct _serverList_t { - IndicateListenerServer * server; AppMenuItem * menuitem; - DbusmenuMenuitem * separator; gboolean attention; guint count; GList * imList; }; -static gint -serverList_equal (gconstpointer a, gconstpointer b) -{ - serverList_t * pa, * pb; - - pa = (serverList_t *)a; - pb = (serverList_t *)b; - - const gchar * pan = INDICATE_LISTENER_SERVER_DBUS_NAME(pa->server); - const gchar * pbn = INDICATE_LISTENER_SERVER_DBUS_NAME(pb->server); - const gchar * pap = indicate_listener_server_get_dbuspath(pa->server); - const gchar * pbp = indicate_listener_server_get_dbuspath(pb->server); - - if (g_strcmp0(pan, pbn) == 0) - return g_strcmp0(pap, pbp); - else - return 1; -} - static gint serverList_sort (gconstpointer a, gconstpointer b) { @@ -113,648 +73,7 @@ serverList_sort (gconstpointer a, gconstpointer b) return g_strcmp0(pan, pbn); } -/* - * Item List - */ - -typedef struct _imList_t imList_t; -struct _imList_t { - IndicateListenerServer * server; - IndicateListenerIndicator * indicator; - DbusmenuMenuitem * menuitem; - gulong timechange_cb; - gulong attentionchange_cb; -}; - -static gboolean -imList_equal (gconstpointer a, gconstpointer b) -{ - imList_t * pa, * pb; - - pa = (imList_t *)a; - pb = (imList_t *)b; - - const gchar * pas = INDICATE_LISTENER_SERVER_DBUS_NAME(pa->server); - const gchar * pbs = INDICATE_LISTENER_SERVER_DBUS_NAME(pb->server); - - guint pai = INDICATE_LISTENER_INDICATOR_ID(pa->indicator); - guint pbi = INDICATE_LISTENER_INDICATOR_ID(pb->indicator); - - g_debug("\tComparing (%s %d) to (%s %d)", pas, pai, pbs, pbi); - - return !((!g_strcmp0(pas, pbs)) && (pai == pbi)); -} - -static gint -imList_sort (gconstpointer a, gconstpointer b) -{ - imList_t * pa, * pb; - - pa = (imList_t *)a; - pb = (imList_t *)b; - - return (gint)(im_menu_item_get_seconds(IM_MENU_ITEM(pb->menuitem)) - im_menu_item_get_seconds(IM_MENU_ITEM(pa->menuitem))); -} - - -/* Goes through all the servers and sees if any of them - want attention. If they do, then well we'll give it - to them. If they don't, let's not bother the user - any, shall we? */ -static void -check_attention (void) -{ - GList * pointer; - for (pointer = serverList; pointer != NULL; pointer = g_list_next(pointer)) { - serverList_t * slt = (serverList_t *)pointer->data; - if (slt->attention) { - message_service_dbus_set_attention(dbus_interface, TRUE); - return; - } - } - message_service_dbus_set_attention(dbus_interface, FALSE); - return; -} - -/* This checks a server listing to see if it should - have attention. It can get attention through it's - count or by having an indicator that is requestion - attention. */ -static void -server_attention (serverList_t * slt) -{ - /* Count, easy yes and out. */ - if (slt->count > 0) { - slt->attention = TRUE; - return; - } - - /* Check to see if any of the indicators want attention */ - GList * pointer; - for (pointer = slt->imList; pointer != NULL; pointer = g_list_next(pointer)) { - imList_t * ilt = (imList_t *)pointer->data; - if (im_menu_item_get_attention(IM_MENU_ITEM(ilt->menuitem))) { - slt->attention = TRUE; - return; - } - } - - /* Nope, no one */ - slt->attention = FALSE; - return; -} - -static void -desktop_cb (IndicateListener *listener, - IndicateListenerServer *server, - const gchar *value, - gpointer data) -{ - DbusmenuMenuitem * menushell = DBUSMENU_MENUITEM(data); - GList *listitem; - serverList_t * sl_item = NULL; - - /* Check to see if we already have a launcher for this app */ - for (listitem = serverList; listitem != NULL; listitem = listitem->next) { - serverList_t * slt = listitem->data; - if (!g_strcmp0(app_menu_item_get_desktop(slt->menuitem), value)) { - sl_item = slt; - break; - } - } - - if (!sl_item) { - /* Build the Menu item */ - AppMenuItem * menuitem = app_menu_item_new_with_server (listener, server); - - /* Build a possible server structure */ - sl_item = g_new0(serverList_t, 1); - sl_item->server = server; - sl_item->menuitem = menuitem; - sl_item->imList = NULL; - sl_item->attention = FALSE; - sl_item->count = 0; - - /* Build a separator */ - sl_item->separator = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set(sl_item->separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR); - - /* Connect the signals up to the menu item */ - g_signal_connect(G_OBJECT(menuitem), APP_MENU_ITEM_SIGNAL_COUNT_CHANGED, G_CALLBACK(server_count_changed), sl_item); - g_signal_connect(G_OBJECT(menuitem), APP_MENU_ITEM_SIGNAL_NAME_CHANGED, G_CALLBACK(server_name_changed), menushell); - g_signal_connect(G_OBJECT(menuitem), APP_MENU_ITEM_SIGNAL_SHORTCUT_ADDED, G_CALLBACK(server_shortcut_added), menushell); - g_signal_connect(G_OBJECT(menuitem), APP_MENU_ITEM_SIGNAL_SHORTCUT_REMOVED, G_CALLBACK(server_shortcut_removed), menushell); - - /* Put our new menu item in, with the separator behind it. - resort_menu will take care of whether it should be hidden - or not. */ - dbusmenu_menuitem_child_append(menushell, DBUSMENU_MENUITEM(menuitem)); - - /* Incase we got an indicator first */ - GList * alreadythere = g_list_find_custom(serverList, sl_item, serverList_equal); - if (alreadythere != NULL) { - /* Use the one we already had */ - g_free(sl_item); - sl_item = (serverList_t *)alreadythere->data; - sl_item->menuitem = menuitem; - serverList = g_list_sort(serverList, serverList_sort); - } else { - /* Insert the new one in the list */ - serverList = g_list_insert_sorted(serverList, sl_item, serverList_sort); - } - - dbusmenu_menuitem_child_append(menushell, DBUSMENU_MENUITEM(sl_item->separator)); - } - else { - app_menu_item_set_server (sl_item->menuitem, listener, server); - } - - GList * shortcuts = app_menu_item_get_items(sl_item->menuitem); - GList * shortcut = shortcuts; - while (shortcut != NULL) { - DbusmenuMenuitem * mi = DBUSMENU_MENUITEM(shortcut->data); - g_debug("\tAdding shortcut: %s", dbusmenu_menuitem_property_get(mi, DBUSMENU_MENUITEM_PROP_LABEL)); - dbusmenu_menuitem_child_append(menushell, mi); - shortcut = g_list_next(shortcut); - } - g_list_free (shortcuts); - - resort_menu(menushell); -} - -/* A new server has been created on the indicate bus. - We need to check to see if we like it. And build - structures for it if so. */ -static void -server_added (IndicateListener * listener, IndicateListenerServer * server, gchar * type, gpointer data) -{ - g_debug("Server Added '%s' of type '%s'.", INDICATE_LISTENER_SERVER_DBUS_NAME(server), type); - if (type == NULL) { - return; - } - - if (type[0] == '\0') { - return; - } - - if (strncmp(type, "message", strlen("message"))) { - g_debug("\tServer type '%s' is not a message based type.", type); - return; - } - - /* fetch the desktop file before creating the menu item, in case we - * already have a launcher for it */ - indicate_listener_server_get_desktop(listener, server, desktop_cb, data); -} - -/* Server shortcut has been added */ -static void -server_shortcut_added (AppMenuItem * appitem, DbusmenuMenuitem * mi, gpointer data) -{ - g_debug("Application Shortcut added: %s", mi != NULL ? dbusmenu_menuitem_property_get(mi, DBUSMENU_MENUITEM_PROP_LABEL) : "none"); - DbusmenuMenuitem * shell = DBUSMENU_MENUITEM(data); - if (mi != NULL) { - dbusmenu_menuitem_property_set (mi, DBUSMENU_MENUITEM_PROP_ICON_NAME, DBUSMENU_MENUITEM_ICON_NAME_BLANK); - dbusmenu_menuitem_child_append(shell, mi); - } - resort_menu(shell); - return; -} - -/* Server shortcut has been removed */ -static void -server_shortcut_removed (AppMenuItem * appitem, DbusmenuMenuitem * mi, gpointer data) -{ - g_debug("Application Shortcut removed: %s", mi != NULL ? dbusmenu_menuitem_property_get(mi, DBUSMENU_MENUITEM_PROP_LABEL) : "none"); - DbusmenuMenuitem * shell = DBUSMENU_MENUITEM(data); - dbusmenu_menuitem_child_delete(shell, mi); - return; -} - -/* The name of a server has changed, we probably - need to reorder the menu to keep it in alphabetical - order. This happens often after we read the destkop - file from disk. */ -static void -server_name_changed (AppMenuItem * appitem, gchar * name, gpointer data) -{ - serverList = g_list_sort(serverList, serverList_sort); - resort_menu(DBUSMENU_MENUITEM(data)); - return; -} - -/* If the count on the server changes, we need to know - whether that should be grabbing attention or not. If - it is, we need to reevaluate whether the whole thing - should be grabbing attention or not. */ -static void -server_count_changed (AppMenuItem * appitem, guint count, gpointer data) -{ - serverList_t * slt = (serverList_t *)data; - slt->count = count; - - if (count == 0 && slt->attention) { - /* Regen based on indicators if the count isn't going to cause it. */ - server_attention(slt); - /* If we're dropping let's see if we're the last. */ - if (!slt->attention) { - check_attention(); - } - } - - if (count != 0 && !slt->attention) { - slt->attention = TRUE; - /* Let's tell everyone about us! */ - message_service_dbus_set_attention(dbus_interface, TRUE); - } - - return; -} - -/* Respond to the IM entrie's time changing - which results in it needing to resort the list - and rebuild the menu to match. */ -static void -im_time_changed (ImMenuItem * imitem, glong seconds, gpointer data) -{ - serverList_t * sl = (serverList_t *)data; - sl->imList = g_list_sort(sl->imList, imList_sort); - resort_menu(root_menuitem); - return; -} - -/* The IM entrie's request for attention has changed - so we need to pass that up the stack. */ -static void -im_attention_changed (ImMenuItem * imitem, gboolean requestit, gpointer data) -{ - serverList_t * sl = (serverList_t *)data; - - if (requestit) { - sl->attention = TRUE; - message_service_dbus_set_attention(dbus_interface, TRUE); - } else { - server_attention(sl); - if (!sl->attention) { - check_attention(); - } - } - - return; -} - -/* Run when a server is removed from the indicator bus. It figures - out if we have it somewhere, and if so then we dump it out and - clean up all of it's entries. */ -static void -server_removed (IndicateListener * listener, IndicateListenerServer * server, gchar * type, gpointer data) -{ - /* Look for the server */ - g_debug("Removing server: %s", INDICATE_LISTENER_SERVER_DBUS_NAME(server)); - serverList_t slt = {0}; - slt.server = server; - GList * lookup = g_list_find_custom(serverList, &slt, serverList_equal); - - /* If we don't have it, exit */ - if (lookup == NULL) { - g_debug("\tUnable to find server: %s", INDICATE_LISTENER_SERVER_DBUS_NAME(server)); - return; - } - - serverList_t * sltp = (serverList_t *)lookup->data; - - /* Removing indicators from this server */ - while (sltp->imList) { - imList_t * imitem = (imList_t *)sltp->imList->data; - indicator_removed(listener, server, imitem->indicator, data); - } - - /* Remove from the server list */ - serverList = g_list_remove(serverList, sltp); - - /* If there is a menu item, let's get rid of it. */ - if (sltp->menuitem != NULL) { - /* If there are shortcuts remove them */ - GList * shortcuts = app_menu_item_get_items(sltp->menuitem); - GList * shortcut = shortcuts; - while (shortcut != NULL) { - g_debug("\tRemoving shortcut: %s", dbusmenu_menuitem_property_get(DBUSMENU_MENUITEM(shortcut->data), DBUSMENU_MENUITEM_PROP_LABEL)); - dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(shortcut->data), DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE); - dbusmenu_menuitem_child_delete(DBUSMENU_MENUITEM(data), DBUSMENU_MENUITEM(shortcut->data)); - shortcut = g_list_next(shortcut); - } - g_list_free (shortcuts); - - g_debug("\tRemoving item"); - dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(sltp->menuitem), DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE); - dbusmenu_menuitem_child_delete(DBUSMENU_MENUITEM(data), DBUSMENU_MENUITEM(sltp->menuitem)); - g_object_unref(G_OBJECT(sltp->menuitem)); - } else { - g_debug("\tNo menuitem"); - } - - /* If there is a separator, let's get rid of it. */ - if (sltp->separator != NULL) { - g_debug("\tRemoving separator"); - dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(sltp->separator), DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE); - dbusmenu_menuitem_child_delete(DBUSMENU_MENUITEM(data), DBUSMENU_MENUITEM(sltp->separator)); - g_object_unref(G_OBJECT(sltp->separator)); - } else { - g_debug("\tNo separator"); - } - - if (sltp->attention) { - /* Check to see if this was the server causing the menu item to - be lit up. */ - check_attention(); - } - - g_free(sltp); - - return; -} - -typedef struct _menushell_location menushell_location_t; -struct _menushell_location { - const IndicateListenerServer * server; - gint position; - gboolean found; -}; - -static void -menushell_foreach_cb (DbusmenuMenuitem * data_mi, gpointer data_ms) { - menushell_location_t * msl = (menushell_location_t *)data_ms; - - if (msl->found) return; - - if (!IS_APP_MENU_ITEM(data_mi)) { - msl->position++; - return; - } - - AppMenuItem * appmenu = APP_MENU_ITEM(data_mi); - if (!g_strcmp0(INDICATE_LISTENER_SERVER_DBUS_NAME((IndicateListenerServer*)msl->server), INDICATE_LISTENER_SERVER_DBUS_NAME(app_menu_item_get_server(appmenu)))) { - GList *shortcuts = app_menu_item_get_items(appmenu); - msl->found = TRUE; - /* Return a position at the end of our shortcuts */ - msl->position += g_list_length(shortcuts); - g_list_free (shortcuts); - - } else { - msl->position++; - } - - return; -} - -/* This function takes care of putting the menu in the right order. - It basically it rebuilds the order by looking through all the - applications and launchers and puts them in the right place. The - menu functions will handle the cases where they don't move so this - is a good way to ensure everything is right. */ -static void -resort_menu (DbusmenuMenuitem * menushell) -{ - guint position = 0; - GList * serverentry; - - 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; - - /* Putting the app menu item in */ - if (si->menuitem != NULL) { - g_debug("\tMoving app %s to position %d", INDICATE_LISTENER_SERVER_DBUS_NAME(si->server), position); - dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(si->menuitem), position); - position++; - - /* Inserting the shortcuts from the launcher */ - GList * shortcuts = app_menu_item_get_items(si->menuitem); - GList * shortcut = shortcuts; - while (shortcut != NULL) { - g_debug("\t\tMoving shortcut to position %d", position); - dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(shortcut->data), position); - position++; - shortcut = g_list_next(shortcut); - } - g_list_free (shortcuts); - } - - /* Putting all the indicators that are related to this application - after it. */ - GList * imentry; - for (imentry = si->imList; imentry != NULL; imentry = imentry->next) { - imList_t * imi = (imList_t *)imentry->data; - - if (imi->menuitem != NULL) { - g_debug("\tMoving indicator on %s id %d to position %d", INDICATE_LISTENER_SERVER_DBUS_NAME(imi->server), INDICATE_LISTENER_INDICATOR_ID(imi->indicator), position); - - if (si->menuitem == NULL || !dbusmenu_menuitem_property_get_bool(DBUSMENU_MENUITEM(si->menuitem), DBUSMENU_MENUITEM_PROP_VISIBLE)) { - dbusmenu_menuitem_property_set_bool(imi->menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE); - } else { - dbusmenu_menuitem_property_set_bool(imi->menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE); - } - - dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(imi->menuitem), position); - position++; - } - } - - /* Lastly putting the separator in */ - if (si->separator != NULL) { - g_debug("\tMoving app %s separator to position %d", INDICATE_LISTENER_SERVER_DBUS_NAME(si->server), position); - - if (si->menuitem == NULL || !dbusmenu_menuitem_property_get_bool(DBUSMENU_MENUITEM(si->menuitem), DBUSMENU_MENUITEM_PROP_VISIBLE)) { - dbusmenu_menuitem_property_set_bool(si->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE); - /* Note, this isn't the last if we can't see it */ - } else { - dbusmenu_menuitem_property_set_bool(si->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE); - } - - dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(si->separator), position); - position++; - } - } - - if (clear_attention != NULL) { - dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), clear_attention, position); - position++; /* Not needed, but reduce bugs on code tacked on here, compiler will remove */ - } - - return; -} - -/* Responding to a new indicator showing up on the bus. We - need to create a menuitem for it and start populating the - internal structures to track it. */ -static void -indicator_added (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gpointer data) -{ - DbusmenuMenuitem * menushell = DBUSMENU_MENUITEM(data); - if (menushell == NULL) { - g_error("Data in callback is not a menushell"); - return; - } - - imList_t * listItem = g_new0(imList_t, 1); - listItem->server = server; - listItem->indicator = indicator; - - /* Building the IM Menu Item which is a subclass - of DBus Menuitem */ - ImMenuItem * menuitem = im_menu_item_new(listener, server, indicator); - listItem->menuitem = DBUSMENU_MENUITEM(menuitem); - - /* Looking for a server entry to attach this indicator - to. If we can't find one then we have to build one - and attach the indicator to it. */ - serverList_t sl_item_local = {0}; - serverList_t * sl_item = NULL; - sl_item_local.server = server; - GList * serverentry = g_list_find_custom(serverList, &sl_item_local, serverList_equal); - - if (serverentry == NULL) { - /* This sucks, we got an indicator before the server. I guess - that's the joy of being asynchronous */ - sl_item = g_new0(serverList_t, 1); - sl_item->server = server; - sl_item->menuitem = NULL; - sl_item->imList = NULL; - sl_item->attention = FALSE; - sl_item->count = 0; - sl_item->separator = NULL; - - serverList = g_list_insert_sorted(serverList, sl_item, serverList_sort); - } else { - sl_item = (serverList_t *)serverentry->data; - } - - /* Added a this entry into the IM list */ - sl_item->imList = g_list_insert_sorted(sl_item->imList, listItem, imList_sort); - listItem->timechange_cb = g_signal_connect(G_OBJECT(menuitem), IM_MENU_ITEM_SIGNAL_TIME_CHANGED, G_CALLBACK(im_time_changed), sl_item); - listItem->attentionchange_cb = g_signal_connect(G_OBJECT(menuitem), IM_MENU_ITEM_SIGNAL_ATTENTION_CHANGED, G_CALLBACK(im_attention_changed), sl_item); - - /* Check the length of the list. If we've got more inidactors - than we allow. Well. Someone's gotta pay. Sorry. I didn't - want to do this, but you did it to yourself. */ - if (g_list_length(sl_item->imList) > MAX_NUMBER_OF_INDICATORS) { - GList * indicatoritem; - gint count; - for (indicatoritem = sl_item->imList, count = 0; indicatoritem != NULL; indicatoritem = g_list_next(indicatoritem), count++) { - imList_t * im = (imList_t *)indicatoritem->data; - im_menu_item_show(IM_MENU_ITEM(im->menuitem), count < MAX_NUMBER_OF_INDICATORS); - } - } - - /* Placing the item into the shell. Look to see if - we can find our server and slip in there. Otherwise - we'll just append. */ - menushell_location_t msl; - msl.found = FALSE; - msl.position = 0; - msl.server = server; - - dbusmenu_menuitem_foreach(DBUSMENU_MENUITEM(menushell), menushell_foreach_cb, &msl); - if (msl.found) { - dbusmenu_menuitem_child_add_position(menushell, DBUSMENU_MENUITEM(menuitem), msl.position); - } else { - g_warning("Unable to find server menu item"); - dbusmenu_menuitem_child_append(menushell, DBUSMENU_MENUITEM(menuitem)); - resort_menu (root_menuitem); - } - - return; -} - -/* Process and indicator getting removed from the system. We - first need to ensure that it's one of ours and figure out - where we put it. When we find all that out we can go through - the process of removing the effect it had on the system. */ -static void -indicator_removed (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gpointer data) -{ - g_debug("Removing %s %d", INDICATE_LISTENER_SERVER_DBUS_NAME(server), INDICATE_LISTENER_INDICATOR_ID(indicator)); - - gboolean removed = FALSE; - - /* Find the server that was related to this item */ - serverList_t sl_item_local = {0}; - serverList_t * sl_item = NULL; - sl_item_local.server = server; - GList * serverentry = g_list_find_custom(serverList, &sl_item_local, serverList_equal); - if (serverentry == NULL) { - /* We didn't care about that server */ - return; - } - sl_item = (serverList_t *)serverentry->data; - - /* Look in the IM Hash Table */ - imList_t listData = {0}; - listData.server = server; - listData.indicator = indicator; - - GList * listItem = g_list_find_custom(sl_item->imList, &listData, imList_equal); - DbusmenuMenuitem * menuitem = NULL; - imList_t * ilt = NULL; - if (listItem != NULL) { - ilt = (imList_t *)listItem->data; - menuitem = ilt->menuitem; - } - - /* If we found a menu item and an imList_t item then - we can go ahead and remove it. Otherwise we can - skip this and exit. */ - if (!removed && menuitem != NULL) { - sl_item->imList = g_list_remove(sl_item->imList, ilt); - g_signal_handler_disconnect(menuitem, ilt->timechange_cb); - g_signal_handler_disconnect(menuitem, ilt->attentionchange_cb); - g_free(ilt); - - if (im_menu_item_get_attention(IM_MENU_ITEM(menuitem)) && im_menu_item_shown(IM_MENU_ITEM(menuitem))) { - /* If the removed indicator menu item was asking for - attention we need to see if this server should still - be asking for attention. */ - server_attention(sl_item); - /* If the server is no longer asking for attention then - we need to check if the whole system should be. */ - if (!sl_item->attention) { - check_attention(); - } - } - - if (im_menu_item_shown(IM_MENU_ITEM(menuitem)) && g_list_length(sl_item->imList) >= MAX_NUMBER_OF_INDICATORS) { - /* In this case we need to show a different indicator - becasue a shown one has left. But we're going to be - easy and set all the values. */ - GList * indicatoritem; - gint count; - for (indicatoritem = sl_item->imList, count = 0; indicatoritem != NULL; indicatoritem = g_list_next(indicatoritem), count++) { - imList_t * im = (imList_t *)indicatoritem->data; - im_menu_item_show(IM_MENU_ITEM(im->menuitem), count < MAX_NUMBER_OF_INDICATORS); - } - } - - /* Hide the item immediately, and then remove it - which might take a little longer. */ - dbusmenu_menuitem_property_set_bool(menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE); - dbusmenu_menuitem_child_delete(DBUSMENU_MENUITEM(data), menuitem); - removed = TRUE; - } - - if (!removed) { - g_warning("We were asked to remove %s %d but we didn't.", INDICATE_LISTENER_SERVER_DBUS_NAME(server), INDICATE_LISTENER_INDICATOR_ID(indicator)); - } - - return; -} - -/* This function turns a specific file into a menu +/* This function turns a specific desktop id into a menu item and registers it appropriately with everyone */ static gboolean build_launcher (gpointer data) @@ -780,26 +99,12 @@ build_launcher (gpointer data) serverList_t * sl_item = g_new0(serverList_t, 1); sl_item->menuitem = app_menu_item_new(appinfo); - /* Build a separator */ - sl_item->separator = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set(sl_item->separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR); - - /* Add it to the list */ serverList = g_list_insert_sorted (serverList, sl_item, serverList_sort); - /* Add it to the menu */ - dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(sl_item->menuitem), DBUSMENU_MENUITEM_PROP_TYPE, APPLICATION_MENUITEM_TYPE); - dbusmenu_menuitem_child_append(root_menuitem, DBUSMENU_MENUITEM(sl_item->menuitem)); - GList * shortcuts = app_menu_item_get_items(sl_item->menuitem); - GList * shortcut = shortcuts; - while (shortcut != NULL) { - dbusmenu_menuitem_child_append(root_menuitem, DBUSMENU_MENUITEM(shortcut->data)); - shortcut = g_list_next(shortcut); - } - g_list_free (shortcuts); - dbusmenu_menuitem_child_append(root_menuitem, DBUSMENU_MENUITEM(sl_item->separator)); - - resort_menu(root_menuitem); + /* TODO insert it at the right position (alphabetically by application name) */ + g_menu_insert_section (menu, 2, + app_menu_item_get_name (sl_item->menuitem), + app_menu_item_get_menu (sl_item->menuitem)); } g_object_unref (appinfo); @@ -838,36 +143,34 @@ service_shutdown (IndicatorService * service, gpointer user_data) return; } -/* Respond to changing status by updating the icon that - is on the panel */ static void -status_update_callback (void) +clear_action_activate (GSimpleAction *simple, + GVariant *param, + gpointer user_data) { - return; + MessageServiceDbus *msg_service = user_data; + message_service_dbus_set_attention(msg_service, FALSE); } -/* The clear attention item has been clicked on, what to do? */ static void -clear_attention_activate (DbusmenuMenuitem * mi, guint timestamp, MessageServiceDbus * dbus) +clear_action_handler (MessageServiceDbus *msd, + gboolean attention, + gpointer user_data) { - message_service_dbus_set_attention(dbus, FALSE); - return; + GSimpleAction *action = user_data; + g_simple_action_set_enabled (action, attention); } -/* Handle an update of the active state to ensure that we're - only enabled when we could do something. */ -static void -clear_attention_handler (MessageServiceDbus * msd, gboolean attention, DbusmenuMenuitem * clearitem) -{ - dbusmenu_menuitem_property_set_bool(clearitem, DBUSMENU_MENUITEM_PROP_ENABLED, attention); - return; -} - -/* Oh, if you don't know what main() is for - we really shouldn't be talking. */ int main (int argc, char ** argv) { + GError *error = NULL; + GActionEntry entries[] = { + { "status", NULL, "s", "'offline'", NULL }, + { "clear", clear_action_activate } + }; + GMenuModel *status_items; + /* Glib init */ g_type_init(); @@ -884,36 +187,40 @@ main (int argc, char ** argv) /* Bring up the service DBus interface */ dbus_interface = message_service_dbus_new(); - /* 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); + bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); + if (!bus) { + g_warning ("unable to connect to the session bus: %s", error->message); + g_error_free (error); + return 1; + } + + actions = g_simple_action_group_new (); + g_simple_action_group_add_entries (actions, entries, G_N_ELEMENTS (entries), NULL); + g_dbus_connection_export_action_group (bus, INDICATOR_MESSAGES_DBUS_OBJECT, + G_ACTION_GROUP (actions), &error); + if (error) { + g_warning ("unable to export action group on dbus: %s", error->message); + g_error_free (error); + return 1; + } + + g_signal_connect (dbus_interface, MESSAGE_SERVICE_DBUS_SIGNAL_ATTENTION_CHANGED, + G_CALLBACK(clear_action_handler), + g_action_map_lookup_action (G_ACTION_MAP (actions), "clear")); + + status_items = status_items_build (g_action_map_lookup_action (G_ACTION_MAP (actions), "status")); + + menu = g_menu_new (); + g_menu_append_section (menu, _("Status"), status_items); + g_menu_append (menu, _("Clear"), "clear"); - /* 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); + g_dbus_connection_export_menu_model (bus, INDICATOR_MESSAGES_DBUS_OBJECT, + G_MENU_MODEL (menu), &error); + if (error) { + g_warning ("unable to export menu on dbus: %s", error->message); + g_error_free (error); + return 1; } - 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); - - /* Add in the clear attention item */ - clear_attention = dbusmenu_menuitem_new(); - dbusmenu_menuitem_property_set(clear_attention, DBUSMENU_MENUITEM_PROP_LABEL, _("Clear")); - dbusmenu_menuitem_child_append(root_menuitem, clear_attention); - g_signal_connect(G_OBJECT(dbus_interface), MESSAGE_SERVICE_DBUS_SIGNAL_ATTENTION_CHANGED, G_CALLBACK(clear_attention_handler), clear_attention); - g_signal_connect(G_OBJECT(clear_attention), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(clear_attention_activate), dbus_interface); - - /* 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); settings = g_settings_new ("com.canonical.indicator.messages"); diff --git a/src/status-items.c b/src/status-items.c index 70a2ad9..a2e3a02 100644 --- a/src/status-items.c +++ b/src/status-items.c @@ -22,10 +22,19 @@ with this program. If not, see . #include #include #include -#include #include "status-items.h" #include "status-provider.h" +#include "dbus-data.h" + +static const gchar * status_ids [STATUS_PROVIDER_STATUS_LAST] = { + /* STATUS_PROVIDER_STATUS_ONLINE, */ "available", + /* STATUS_PROVIDER_STATUS_AWAY, */ "away", + /* STATUS_PROVIDER_STATUS_DND */ "busy", + /* STATUS_PROVIDER_STATUS_INVISIBLE */ "invisible", + /* STATUS_PROVIDER_STATUS_OFFLINE, */ "offline", + /* STATUS_PROVIDER_STATUS_DISCONNECTED*/ "offline" +}; static const gchar * status_strings [STATUS_PROVIDER_STATUS_LAST] = { /* STATUS_PROVIDER_STATUS_ONLINE, */ N_("Available"), @@ -66,39 +75,40 @@ static const gchar * panel_active_icons[STATUS_PROVIDER_STATUS_LAST] = { /* 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); +static void user_status_change (GSimpleAction *action, + GVariant *value, + gpointer user_data); /* Globals */ static StatusProviderStatus current_status = STATUS_PROVIDER_STATUS_DISCONNECTED; -static GList * menuitems = NULL; +static GMenu * menu; +static GAction *status_action; 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) +GMenuModel * +status_items_build (GAction *action) { int i; - for (i = STATUS_PROVIDER_STATUS_ONLINE; i < STATUS_PROVIDER_STATUS_DISCONNECTED; i++) { - DbusmenuMenuitem * item = dbusmenu_menuitem_new(); + menu = g_menu_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]); + status_action = action; + g_signal_connect (action, "change-state", G_CALLBACK (user_status_change), NULL); - dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE); - dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_ENABLED, FALSE); + for (i = STATUS_PROVIDER_STATUS_ONLINE; i < STATUS_PROVIDER_STATUS_DISCONNECTED; i++) { + GMenuItem *item = g_menu_item_new (_(status_strings[i]), NULL); - 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_menu_item_set_action_and_target (item, g_action_get_name (action), "s", status_ids[i]); - g_signal_connect(G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(user_status_change), GINT_TO_POINTER(i)); + g_menu_item_set_attribute (item, INDICATOR_MENU_ATTRIBUTE_ICON_NAME, "s", status_icons[i]); + g_menu_item_set_attribute (item, INDICATOR_MENU_ATTRIBUTE_VISIBLE, "b", TRUE); + g_menu_item_set_attribute (item, INDICATOR_MENU_ATTRIBUTE_ENABLED, "b", FALSE); - menuitems = g_list_append(menuitems, item); + g_menu_append_item (menu, item); + g_object_unref (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); @@ -106,7 +116,7 @@ status_items_build (StatusUpdateFunc status_update_func) g_idle_add(provider_directory_parse, (gpointer)status_providers_env); } - return menuitems; + return G_MENU_MODEL (menu); } /* Clean up our globals and stop with all this allocation @@ -155,38 +165,33 @@ update_status (void) 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); - } - } + g_action_change_state (status_action, g_variant_new_string (status_ids[current_status])); return; } /* Handle the user requesting a status change */ static void -user_status_change (DbusmenuMenuitem * item, guint timestamp, gpointer pstatus) +user_status_change (GSimpleAction *action, + GVariant *value, + gpointer user_data) { - StatusProviderStatus status = GPOINTER_TO_INT(pstatus); + const gchar *status_id; + int i; + StatusProviderStatus status = STATUS_PROVIDER_STATUS_DISCONNECTED; GList * provider; + g_return_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING)); + + status_id = g_variant_get_string (value, NULL); + + for (i = STATUS_PROVIDER_STATUS_ONLINE; i < STATUS_PROVIDER_STATUS_DISCONNECTED; i++) { + if (!strcmp (status_id, status_ids [i])) { + status = i; + break; + } + } + /* 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); diff --git a/src/status-items.h b/src/status-items.h index fe7900c..ff35dfc 100644 --- a/src/status-items.h +++ b/src/status-items.h @@ -26,9 +26,7 @@ with this program. If not, see . G_BEGIN_DECLS -typedef void (*StatusUpdateFunc) (void); - -GList * status_items_build (StatusUpdateFunc update_func); +GMenuModel * status_items_build (GAction *action); const gchar * status_current_panel_icon (gboolean alert); void status_items_cleanup (void); diff --git a/test/Makefile.am b/test/Makefile.am index bb58ab2..847d857 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -40,7 +40,6 @@ lib_LTLIBRARIES = \ libindicator_messages_service_la_HEADERS = \ $(top_srcdir)/src/gen-messages-service.xml.h \ - $(top_srcdir)/src/im-menu-item.h \ $(top_srcdir)/src/app-menu-item.h \ $(top_srcdir)/src/dbus-data.h \ $(top_srcdir)/src/status-items.h @@ -49,7 +48,6 @@ libindicator_messages_service_la_SOURCES = \ $(top_srcdir)/src/messages-service.c \ $(top_srcdir)/src/messages-service-dbus.c \ $(top_srcdir)/src/gen-messages-service.xml.c \ - $(top_srcdir)/src/im-menu-item.c \ $(top_srcdir)/src/app-menu-item.c \ $(top_srcdir)/src/status-items.c -- cgit v1.2.3 From e3c0e7048e032a5a8678c25341fc61b9c191a5db Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Thu, 24 May 2012 22:36:29 +0200 Subject: Don't support X-Ayatana-Messaging-Menu-Icon anymore It was used to override icons for the default apps (Mail, Chat, Broadcast). Since all apps are now shown with their real name and icon, the override is not needed anymore. --- src/app-menu-item.c | 27 +++------------------------ src/dbus-data.h | 4 ---- 2 files changed, 3 insertions(+), 28 deletions(-) diff --git a/src/app-menu-item.c b/src/app-menu-item.c index b5d4994..5badfee 100644 --- a/src/app-menu-item.c +++ b/src/app-menu-item.c @@ -144,7 +144,7 @@ app_menu_item_set_appinfo (AppMenuItem *self, AppMenuItemPrivate *priv = APP_MENU_ITEM_GET_PRIVATE (self); GSimpleAction *launch; GMenuItem *menuitem; - GKeyFile *keyfile; + GIcon *icon; gchar *iconstr = NULL; gchar *label; @@ -153,28 +153,8 @@ app_menu_item_set_appinfo (AppMenuItem *self, g_clear_object (&priv->appinfo); priv->appinfo = g_object_ref (appinfo); - keyfile = g_key_file_new(); - g_key_file_load_from_file(keyfile, g_desktop_app_info_get_filename (appinfo), G_KEY_FILE_NONE, NULL); - - /* Check for the over ride key and see if we should be using that - icon. If we can't get it, then go back to the app info */ - if (g_key_file_has_key(keyfile, G_KEY_FILE_DESKTOP_GROUP, ICON_KEY, NULL)) { - GError * error = NULL; - - iconstr = g_key_file_get_string(keyfile, G_KEY_FILE_DESKTOP_GROUP, ICON_KEY, &error); - - if (error != NULL) { - /* Can't figure out why this would happen, but sure, let's print something */ - g_warning("Error getting '" ICON_KEY "' from desktop file: %s", error->message); - g_error_free(error); - } - } - - /* For some reason that didn't work, let's try the app info */ - if (iconstr == NULL) { - GIcon * icon = g_app_info_get_icon(G_APP_INFO(priv->appinfo)); - iconstr = g_icon_to_string(icon); - } + icon = g_app_info_get_icon (G_APP_INFO(priv->appinfo)); + iconstr = g_icon_to_string (icon); launch = g_simple_action_new ("launch", NULL); g_signal_connect (launch, "activate", G_CALLBACK (activate_cb), self); @@ -217,7 +197,6 @@ app_menu_item_set_appinfo (AppMenuItem *self, g_free(iconstr); g_object_unref (launch); g_object_unref (menuitem); - g_key_file_unref(keyfile); } AppMenuItem * diff --git a/src/dbus-data.h b/src/dbus-data.h index d7efd86..bf82cf0 100644 --- a/src/dbus-data.h +++ b/src/dbus-data.h @@ -21,10 +21,6 @@ #define MAX_NUMBER_OF_INDICATORS 7 -/* Used for override icons in the normal case, but didn't - have a better place to put it. */ -#define ICON_KEY "X-Ayatana-Messaging-Menu-Icon" - #define INDICATOR_MENU_ATTRIBUTE_VISIBLE "indicator-visible" #define INDICATOR_MENU_ATTRIBUTE_ENABLED "indicator-enabled" #define INDICATOR_MENU_ATTRIBUTE_ICON_NAME "indicator-icon-name" -- cgit v1.2.3 From 9763d347aabc9050e4f17133bcf287ed1cbc190d Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Thu, 24 May 2012 22:50:22 +0200 Subject: message-service: replace the server list with a hash table of appmenuitems --- src/messages-service.c | 61 ++++++++++---------------------------------------- 1 file changed, 12 insertions(+), 49 deletions(-) diff --git a/src/messages-service.c b/src/messages-service.c index 432846e..fbbfb9d 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -36,7 +36,7 @@ with this program. If not, see . #include "status-items.h" static IndicatorService * service = NULL; -static GList * serverList = NULL; +static GHashTable *applications; static GDBusConnection *bus; static GSimpleActionGroup *actions; @@ -47,32 +47,6 @@ static GMainLoop * mainloop = NULL; static MessageServiceDbus * dbus_interface = NULL; -/* - * Server List - */ - -typedef struct _serverList_t serverList_t; -struct _serverList_t { - AppMenuItem * menuitem; - gboolean attention; - guint count; - GList * imList; -}; - -static gint -serverList_sort (gconstpointer a, gconstpointer b) -{ - serverList_t * pa, * pb; - - pa = (serverList_t *)a; - pb = (serverList_t *)b; - - const gchar * pan = app_menu_item_get_name(pa->menuitem); - const gchar * pbn = app_menu_item_get_name(pb->menuitem); - - return g_strcmp0(pan, pbn); -} - /* This function turns a specific desktop id into a menu item and registers it appropriately with everyone */ static gboolean @@ -80,31 +54,20 @@ build_launcher (gpointer data) { gchar *desktop_id = data; GDesktopAppInfo *appinfo; - GList *listitem; + const gchar *desktop_file; appinfo = g_desktop_app_info_new (desktop_id); + desktop_file = g_desktop_app_info_get_filename (appinfo); - /* Check to see if we already have a launcher */ - for (listitem = serverList; listitem != NULL; listitem = listitem->next) { - serverList_t * slt = listitem->data; - if (!g_strcmp0(app_menu_item_get_desktop(slt->menuitem), - g_desktop_app_info_get_filename (appinfo))) { - break; - } - } - - if (listitem == NULL) { - /* If not */ - /* Build the item */ - serverList_t * sl_item = g_new0(serverList_t, 1); - sl_item->menuitem = app_menu_item_new(appinfo); - - serverList = g_list_insert_sorted (serverList, sl_item, serverList_sort); + if (!g_hash_table_lookup (applications, desktop_file)) { + AppMenuItem *menuitem = app_menu_item_new(appinfo); /* TODO insert it at the right position (alphabetically by application name) */ g_menu_insert_section (menu, 2, - app_menu_item_get_name (sl_item->menuitem), - app_menu_item_get_menu (sl_item->menuitem)); + app_menu_item_get_name (menuitem), + app_menu_item_get_menu (menuitem)); + + g_hash_table_insert (applications, g_strdup (desktop_file), menuitem); } g_object_unref (appinfo); @@ -129,8 +92,6 @@ build_launchers (gpointer data) g_idle_add(build_launcher, g_strdup (*app)); } - serverList = g_list_sort(serverList, serverList_sort); - g_strfreev (applications); return FALSE; } @@ -224,6 +185,8 @@ main (int argc, char ** argv) settings = g_settings_new ("com.canonical.indicator.messages"); + applications = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); + g_idle_add(build_launchers, NULL); /* Let's run a mainloop */ @@ -233,6 +196,6 @@ main (int argc, char ** argv) /* Clean up */ status_items_cleanup(); g_object_unref (settings); - + g_hash_table_unref (applications); return 0; } -- cgit v1.2.3 From 54621a3d3ece6ddf0bdd9868b8d0405c396c59b2 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Thu, 24 May 2012 22:53:00 +0200 Subject: Check whether supplied desktop files exist --- src/messages-service.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/messages-service.c b/src/messages-service.c index fbbfb9d..cfc07fc 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -57,6 +57,12 @@ build_launcher (gpointer data) const gchar *desktop_file; appinfo = g_desktop_app_info_new (desktop_id); + if (!appinfo) { + g_warning ("could not find a desktop file with id '%s'\n", desktop_id); + g_free (desktop_id); + return FALSE; + } + desktop_file = g_desktop_app_info_get_filename (appinfo); if (!g_hash_table_lookup (applications, desktop_file)) { -- cgit v1.2.3 From 2c113b49296184a057bd64e89d2e3240c8262f44 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Fri, 25 May 2012 10:58:30 +0200 Subject: appmenuitem: remove name-changed signal --- src/app-menu-item.c | 17 ----------------- src/app-menu-item.h | 8 -------- 2 files changed, 25 deletions(-) diff --git a/src/app-menu-item.c b/src/app-menu-item.c index 5badfee..b18b7c9 100644 --- a/src/app-menu-item.c +++ b/src/app-menu-item.c @@ -31,13 +31,6 @@ with this program. If not, see . #include "app-menu-item.h" #include "dbus-data.h" -enum { - NAME_CHANGED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - typedef struct _AppMenuItemPrivate AppMenuItemPrivate; struct _AppMenuItemPrivate @@ -72,14 +65,6 @@ app_menu_item_class_init (AppMenuItemClass *klass) g_type_class_add_private (klass, sizeof (AppMenuItemPrivate)); object_class->dispose = app_menu_item_dispose; - - signals[NAME_CHANGED] = g_signal_new(APP_MENU_ITEM_SIGNAL_NAME_CHANGED, - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (AppMenuItemClass, name_changed), - NULL, NULL, - g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, 1, G_TYPE_STRING); } static void @@ -191,8 +176,6 @@ app_menu_item_set_appinfo (AppMenuItem *self, g_free(name); } - g_signal_emit(G_OBJECT(self), signals[NAME_CHANGED], 0, app_menu_item_get_name(self), TRUE); - g_free(label); g_free(iconstr); g_object_unref (launch); diff --git a/src/app-menu-item.h b/src/app-menu-item.h index 785a997..cec5bb0 100644 --- a/src/app-menu-item.h +++ b/src/app-menu-item.h @@ -33,19 +33,11 @@ G_BEGIN_DECLS #define IS_APP_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), APP_MENU_ITEM_TYPE)) #define APP_MENU_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), APP_MENU_ITEM_TYPE, AppMenuItemClass)) -#define APP_MENU_ITEM_SIGNAL_COUNT_CHANGED "count-changed" -#define APP_MENU_ITEM_SIGNAL_NAME_CHANGED "name-changed" -#define APP_MENU_ITEM_SIGNAL_SHORTCUT_ADDED "shortcut-added" -#define APP_MENU_ITEM_SIGNAL_SHORTCUT_REMOVED "shortcut-removed" - typedef struct _AppMenuItem AppMenuItem; typedef struct _AppMenuItemClass AppMenuItemClass; struct _AppMenuItemClass { GObjectClass parent_class; - - void (* count_changed) (guint count); - void (* name_changed) (gchar * name); }; struct _AppMenuItem { -- cgit v1.2.3 From 982bf2ed9cec576b599f0f87f3201675757eda05 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Fri, 25 May 2012 11:25:37 +0200 Subject: appmenuitem: make app-info a construct-only property --- src/app-menu-item.c | 103 +++++++++++++++++++++++++++++++++++++++++++++------- src/app-menu-item.h | 1 + 2 files changed, 90 insertions(+), 14 deletions(-) diff --git a/src/app-menu-item.c b/src/app-menu-item.c index b18b7c9..7638eb5 100644 --- a/src/app-menu-item.c +++ b/src/app-menu-item.c @@ -46,13 +46,31 @@ struct _AppMenuItemPrivate #define APP_MENU_ITEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), APP_MENU_ITEM_TYPE, AppMenuItemPrivate)) +enum { + PROP_0, + PROP_APPINFO, + NUM_PROPERTIES +}; + +static GParamSpec *properties[NUM_PROPERTIES]; + /* Prototypes */ -static void app_menu_item_class_init (AppMenuItemClass *klass); -static void app_menu_item_init (AppMenuItem *self); -static void app_menu_item_dispose (GObject *object); -static void activate_cb (GSimpleAction *action, - GVariant *param, - gpointer userdata); +static void app_menu_item_class_init (AppMenuItemClass *klass); +static void app_menu_item_init (AppMenuItem *self); +static void app_menu_item_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void app_menu_item_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); +static void app_menu_item_dispose (GObject *object); +static void activate_cb (GSimpleAction *action, + GVariant *param, + gpointer userdata); +static void app_menu_item_set_app_info (AppMenuItem *self, + GDesktopAppInfo *appinfo); /* GObject Boilerplate */ G_DEFINE_TYPE (AppMenuItem, app_menu_item, G_TYPE_OBJECT); @@ -64,7 +82,17 @@ app_menu_item_class_init (AppMenuItemClass *klass) g_type_class_add_private (klass, sizeof (AppMenuItemPrivate)); + object_class->get_property = app_menu_item_get_property; + object_class->set_property = app_menu_item_set_property; object_class->dispose = app_menu_item_dispose; + + properties[PROP_APPINFO] = g_param_spec_object ("app-info", + "AppInfo", + "The GAppInfo for the app that this menu represents", + G_TYPE_APP_INFO, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + + g_object_class_install_properties (object_class, NUM_PROPERTIES, properties); } static void @@ -82,6 +110,43 @@ app_menu_item_init (AppMenuItem *self) return; } +static void +app_menu_item_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + AppMenuItem *self = APP_MENU_ITEM (object); + + switch (property_id) + { + case PROP_APPINFO: + g_value_set_object (value, app_menu_item_get_app_info (self)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +app_menu_item_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + AppMenuItem *self = APP_MENU_ITEM (object); + + switch (property_id) + { + case PROP_APPINFO: + app_menu_item_set_app_info (self, g_value_get_object (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} static void app_menu_item_dispose (GObject *object) { @@ -123,8 +188,8 @@ nick_activate_cb (GSimpleAction *action, } static void -app_menu_item_set_appinfo (AppMenuItem *self, - GDesktopAppInfo *appinfo) +app_menu_item_set_app_info (AppMenuItem *self, + GDesktopAppInfo *appinfo) { AppMenuItemPrivate *priv = APP_MENU_ITEM_GET_PRIVATE (self); GSimpleAction *launch; @@ -133,9 +198,13 @@ app_menu_item_set_appinfo (AppMenuItem *self, gchar *iconstr = NULL; gchar *label; - g_return_if_fail (appinfo != NULL); + g_return_if_fail (priv->appinfo == NULL); + + if (appinfo == NULL) { + g_warning ("appinfo must not be NULL"); + return; + } - g_clear_object (&priv->appinfo); priv->appinfo = g_object_ref (appinfo); icon = g_app_info_get_icon (G_APP_INFO(priv->appinfo)); @@ -185,10 +254,9 @@ app_menu_item_set_appinfo (AppMenuItem *self, AppMenuItem * app_menu_item_new (GDesktopAppInfo *appinfo) { - AppMenuItem *self = g_object_new(APP_MENU_ITEM_TYPE, NULL); - if (appinfo) - app_menu_item_set_appinfo (self, appinfo); - return self; + return g_object_new (APP_MENU_ITEM_TYPE, + "app-info", appinfo, + NULL); } static void @@ -245,3 +313,10 @@ app_menu_item_get_menu (AppMenuItem *appitem) return G_MENU_MODEL (priv->menu); } +GAppInfo * +app_menu_item_get_app_info (AppMenuItem *appitem) +{ + AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(appitem); + return G_APP_INFO (priv->appinfo); +} + diff --git a/src/app-menu-item.h b/src/app-menu-item.h index cec5bb0..1fb2762 100644 --- a/src/app-menu-item.h +++ b/src/app-menu-item.h @@ -50,6 +50,7 @@ guint app_menu_item_get_count (AppMenuItem * appitem); const gchar * app_menu_item_get_name (AppMenuItem * appitem); const gchar * app_menu_item_get_desktop (AppMenuItem * appitem); GMenuModel * app_menu_item_get_menu (AppMenuItem *appitem); +GAppInfo * app_menu_item_get_app_info (AppMenuItem *appitem); G_END_DECLS -- cgit v1.2.3 From 9601275fe6382e09d94172c9ae7953d38ce92d1e Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Fri, 25 May 2012 15:28:50 +0200 Subject: Update .bzrignore --- .bzrignore | 89 ++++++++++++++++++++++++++++---------------------------------- 1 file changed, 40 insertions(+), 49 deletions(-) diff --git a/.bzrignore b/.bzrignore index 3ba685c..ea0968a 100644 --- a/.bzrignore +++ b/.bzrignore @@ -1,49 +1,40 @@ -compile -m4 -po -src/libmessaging.la -src/libmessaging_la-indicator-messages.lo -config.guess.cdbs-orig -config.sub.cdbs-orig -debian/compat -debian/files -debian/indicator-messages -debian/indicator-messages.debhelper.log -debian/indicator-messages.postinst.debhelper -debian/indicator-messages.postrm.debhelper -debian/indicator-messages.substvars -debian/stamp-autotools-files -debian/stamp-makefile-build -libmessaging_la-im-menu-item.lo -src/libmessaging_la-app-menu-item.lo -data/indicator-messages.service -indicator-messages-service -indicator-messages-service-activate -src/messages-service-client.h -src/messages-service-server.h -po/indicator-messages.pot -src/libmessaging_la-app-gtk-menu-item.lo -src/gen-messages-service.xml.c -src/gen-messages-service.xml.h -src/libemesene.la -src/libemesene_la-status-provider-emesene.lo -src/libmc5.la -src/libmc5_la-status-provider-mc5-marshal.lo -src/libmc5_la-status-provider-mc5.lo -src/libmessaging_la-gen-messages-service.xml.lo -src/libpidgin.la -src/libpidgin_la-status-provider-pidgin-marshal.lo -src/libpidgin_la-status-provider-pidgin.lo -src/libtelepathy.la -src/libtelepathy_la-status-provider-telepathy-marshal.lo -src/libtelepathy_la-status-provider-telepathy.lo -src/status-provider-mc5-marshal.c -src/status-provider-mc5-marshal.h -src/status-provider-pidgin-marshal.c -src/status-provider-pidgin-marshal.h -src/status-provider-telepathy-marshal.c -src/status-provider-telepathy-marshal.h -src/libindicator-messages-status-provider.la -src/libindicator_messages_status_provider_la-status-provider.lo -indicator-messages-status-provider-0.5.pc -indicator-messages-status-provider-0.5.pc.in +Makefile +Makefile.in +Makefile.in.in +*.o +*.lo +*.la +*.pot +.deps +.libs +*.valid +stamp-* + +/COPYING +/INSTALL +/compile +/libtool +/config.* +/configure +/aclocal.m4 +/ltmain.sh +/install-sh +/missing +/autom4te.cache +/depcomp +/mkinstalldirs + +/m4/* +/po/POTFILES +/data/indicator-messages.service +/src/indicator-messages-service +/src/gen-messages-service.xml.c +/src/gen-messages-service.xml.h +/src/status-provider-mc5-marshal.c +/src/status-provider-mc5-marshal.h +/src/status-provider-pidgin-marshal.c +/src/status-provider-pidgin-marshal.h +/src/status-provider-telepathy-marshal.c +/src/status-provider-telepathy-marshal.h +/src/indicator-messages-status-provider-0.5.pc +/src/indicator-messages-status-provider-0.5.pc.in -- cgit v1.2.3 From cd6da41abeb0ad5dd9bf15158efcb5fda1ee8870 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Fri, 25 May 2012 18:17:46 +0200 Subject: Port to gmenu, act II - the indicator object Ports the indicator object itself to listen to exported gactions and gmenumodels. The menu creation itself is outsourced to a new dependency: menu-factory-gtk. --- configure.ac | 4 +- src/indicator-messages.c | 385 ++++------------------------------------------- 2 files changed, 34 insertions(+), 355 deletions(-) diff --git a/configure.ac b/configure.ac index b7602a3..2886046 100644 --- a/configure.ac +++ b/configure.ac @@ -44,13 +44,15 @@ PANEL_REQUIRED_VERSION=2.0.0 INDICATOR_REQUIRED_VERSION=0.3.19 DBUSMENUGTK_REQUIRED_VERSION=0.5.90 GLIB_REQUIRED_VERSION=2.31.20 +MENU_FACTORY_REQUIRED_VERSION=0.0 PKG_CHECK_MODULES(APPLET, gtk+-3.0 >= $GTK_REQUIRED_VERSION gio-unix-2.0 >= $GIO_UNIX_REQUIRED_VERSION indicator3-0.4 >= $INDICATOR_REQUIRED_VERSION dbusmenu-gtk3-0.4 >= $DBUSMENUGTK_REQUIRED_VERSION glib-2.0 >= $GLIB_REQUIRED_VERSION - gmodule-2.0 >= $GLIB_REQUIRED_VERSION) + gmodule-2.0 >= $GLIB_REQUIRED_VERSION + menu-factory-gtk >= $MENU_FACTORY_REQUIRED_VERSION) AC_SUBST(APPLET_CFLAGS) AC_SUBST(APPLET_LIBS) diff --git a/src/indicator-messages.c b/src/indicator-messages.c index 32f97f7..b6707f5 100644 --- a/src/indicator-messages.c +++ b/src/indicator-messages.c @@ -29,14 +29,13 @@ with this program. If not, see . #include #include -#include -#include - #include #include #include #include +#include + #include "dbus-data.h" #include "gen-messages-service.xml.h" @@ -58,6 +57,8 @@ struct _IndicatorMessagesClass { struct _IndicatorMessages { IndicatorObject parent; IndicatorServiceManager * service; + GActionGroup *actions; + GMenuModel *menu; }; GType indicator_messages_get_type (void); @@ -155,6 +156,9 @@ indicator_messages_class_init (IndicatorMessagesClass *klass) static void indicator_messages_init (IndicatorMessages *self) { + GDBusConnection *bus; + GError *error = NULL; + /* Default values */ self->service = NULL; @@ -162,9 +166,24 @@ indicator_messages_init (IndicatorMessages *self) self->service = indicator_service_manager_new_version(INDICATOR_MESSAGES_DBUS_NAME, 1); g_signal_connect(self->service, INDICATOR_SERVICE_MANAGER_SIGNAL_CONNECTION_CHANGE, G_CALLBACK(connection_change), self); + bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); + if (!bus) { + g_warning ("error connecting to the session bus: %s", error->message); + g_error_free (error); + return; + } + + self->actions = G_ACTION_GROUP (g_dbus_action_group_get (bus, + INDICATOR_MESSAGES_DBUS_NAME, + INDICATOR_MESSAGES_DBUS_OBJECT)); + + self->menu = G_MENU_MODEL (g_dbus_menu_model_get (bus, + INDICATOR_MESSAGES_DBUS_NAME, + INDICATOR_MESSAGES_DBUS_OBJECT)); + indicator = INDICATOR_OBJECT(self); - return; + g_object_unref (bus); } /* Unref stuff */ @@ -179,6 +198,9 @@ indicator_messages_dispose (GObject *object) self->service = NULL; } + g_clear_object (&self->actions); + g_clear_object (&self->menu); + G_OBJECT_CLASS (indicator_messages_parent_class)->dispose (object); return; } @@ -376,206 +398,6 @@ connection_change (IndicatorServiceManager * sm, gboolean connected, gpointer us return; } -/* Sets the icon when it changes. */ -static void -application_icon_change_cb (DbusmenuMenuitem * mi, gchar * prop, GVariant * value, gpointer user_data) -{ - if (!g_strcmp0(prop, APPLICATION_MENUITEM_PROP_ICON)) { - /* Set the main icon */ - if (GTK_IS_IMAGE(user_data)) { - gtk_image_set_from_icon_name(GTK_IMAGE(user_data), g_variant_get_string(value, NULL), GTK_ICON_SIZE_MENU); - } - } - - return; -} - -/* Sets the label when it changes. */ -static void -application_prop_change_cb (DbusmenuMenuitem * mi, gchar * prop, GVariant * value, gpointer user_data) -{ - if (!g_strcmp0(prop, APPLICATION_MENUITEM_PROP_NAME)) { - /* Set the main label */ - if (GTK_IS_LABEL(user_data)) { - gtk_label_set_text(GTK_LABEL(user_data), g_variant_get_string(value, NULL)); - } - } - - if (!g_strcmp0(prop, APPLICATION_MENUITEM_PROP_RUNNING)) { - /* TODO: should hide/show the triangle live if the menu was open. - In practice, this is rarely needed. */ - } - - return; -} - -/* Draws a triangle on the left, using fg[STATE_TYPE] color. */ -static gboolean -application_triangle_draw_cb (GtkWidget *widget, cairo_t *cr, gpointer data) -{ - GtkAllocation allocation; - GtkStyle *style; - int x, y, arrow_width, arrow_height; - - if (!GTK_IS_WIDGET (widget)) return FALSE; - if (!DBUSMENU_IS_MENUITEM (data)) return FALSE; - - /* render the triangle indicator only if the application is running */ - if (! dbusmenu_menuitem_property_get_bool (DBUSMENU_MENUITEM(data), APPLICATION_MENUITEM_PROP_RUNNING)) - return FALSE;; - - /* get style */ - style = gtk_widget_get_style (widget); - - /* set arrow position / dimensions */ - arrow_width = 5; /* the pixel-based reference triangle is 5x9 */ - arrow_height = 9; - gtk_widget_get_allocation (widget, &allocation); - x = 0; - y = allocation.height/2.0 - (double)arrow_height/2.0; - - cairo_save (cr); - - /* set line width */ - cairo_set_line_width (cr, 1.0); - - /* cairo drawing code */ - cairo_move_to (cr, x, y); - cairo_line_to (cr, x, y + arrow_height); - cairo_line_to (cr, x + arrow_width, y + (double)arrow_height/2.0); - cairo_close_path (cr); - cairo_set_source_rgb (cr, style->fg[gtk_widget_get_state(widget)].red/65535.0, - style->fg[gtk_widget_get_state(widget)].green/65535.0, - style->fg[gtk_widget_get_state(widget)].blue/65535.0); - cairo_fill (cr); - - cairo_restore (cr); - - return FALSE; -} - -static gint -gtk_widget_get_font_size (GtkWidget *widget) -{ - const PangoFontDescription *font; - - font = gtk_style_context_get_font (gtk_widget_get_style_context (widget), - gtk_widget_get_state_flags (widget)); - - return pango_font_description_get_size (font) / PANGO_SCALE; -} - -/* Custom function to draw rounded rectangle with max radius */ -static void -custom_cairo_rounded_rectangle (cairo_t *cr, - double x, double y, double w, double h) -{ - double radius = h / 2.0; - - cairo_move_to (cr, x+radius, y); - cairo_arc (cr, x+w-radius, y+radius, radius, M_PI*1.5, M_PI*2); - cairo_arc (cr, x+w-radius, y+h-radius, radius, 0, M_PI*0.5); - cairo_arc (cr, x+radius, y+h-radius, radius, M_PI*0.5, M_PI); - cairo_arc (cr, x+radius, y+radius, radius, M_PI, M_PI*1.5); -} - -/* Draws a rounded rectangle with text inside. */ -static gboolean -numbers_draw_cb (GtkWidget *widget, cairo_t *cr, gpointer data) -{ - GtkAllocation allocation; - GtkStyle *style; - double x, y, w, h; - PangoLayout * layout; - PangoRectangle layout_extents; - gint font_size = gtk_widget_get_font_size (widget); - gboolean is_lozenge = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "is-lozenge")); - - if (!GTK_IS_WIDGET (widget)) return FALSE; - - /* let the label handle the drawing if it's not a lozenge */ - if (!is_lozenge) - return FALSE; - - /* get style */ - style = gtk_widget_get_style (widget); - - /* set arrow position / dimensions */ - gtk_widget_get_allocation (widget, &allocation); - x = 0; - y = 0; - w = allocation.width; - h = allocation.height; - - layout = gtk_label_get_layout (GTK_LABEL(widget)); - pango_layout_get_extents (layout, NULL, &layout_extents); - pango_extents_to_pixels (&layout_extents, NULL); - - if (layout_extents.width == 0) - return TRUE; - - cairo_save (cr); - - /* set line width */ - cairo_set_line_width (cr, 1.0); - - cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); - - /* cairo drawing code */ - custom_cairo_rounded_rectangle (cr, x - font_size/2.0, y, w + font_size, h); - - cairo_set_source_rgba (cr, style->fg[gtk_widget_get_state(widget)].red/65535.0, - style->fg[gtk_widget_get_state(widget)].green/65535.0, - style->fg[gtk_widget_get_state(widget)].blue/65535.0, 0.5); - - x += (allocation.width - layout_extents.width) / 2.0; - y += (allocation.height - layout_extents.height) / 2.0; - cairo_move_to (cr, floor (x), floor (y)); - pango_cairo_layout_path (cr, layout); - cairo_fill (cr); - - cairo_restore (cr); - - return TRUE; -} - -/* Builds a menu item representing a running application in the - messaging menu */ -static gboolean -new_application_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client, gpointer user_data) -{ - g_debug ("%s (\"%s\")", __func__, dbusmenu_menuitem_property_get(newitem, APPLICATION_MENUITEM_PROP_NAME)); - - GtkMenuItem * gmi = GTK_MENU_ITEM(gtk_menu_item_new()); - - gint padding = 4; - gtk_widget_style_get(GTK_WIDGET(gmi), "toggle-spacing", &padding, NULL); - - GtkWidget * hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, padding); - - GtkWidget * icon = gtk_image_new_from_icon_name(dbusmenu_menuitem_property_get(newitem, APPLICATION_MENUITEM_PROP_ICON), GTK_ICON_SIZE_MENU); - gtk_misc_set_alignment(GTK_MISC(icon), 1.0 /* right aligned */, 0.5); - gtk_box_pack_start (GTK_BOX (hbox), icon, FALSE, FALSE, 0); - - /* Application name in a label */ - GtkWidget * label = gtk_label_new(dbusmenu_menuitem_property_get(newitem, APPLICATION_MENUITEM_PROP_NAME)); - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); - gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0); - - gtk_container_add(GTK_CONTAINER(gmi), hbox); - gtk_widget_show_all (GTK_WIDGET (gmi)); - - /* Attach some of the standard GTK stuff */ - dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, gmi, parent); - - /* Make sure we can handle the label changing */ - g_signal_connect(G_OBJECT(newitem), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(application_prop_change_cb), label); - g_signal_connect(G_OBJECT(newitem), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(application_icon_change_cb), icon); - g_signal_connect_after(G_OBJECT (gmi), "draw", G_CALLBACK (application_triangle_draw_cb), newitem); - - return TRUE; -} - typedef struct _indicator_item_t indicator_item_t; struct _indicator_item_t { GtkWidget * icon; @@ -583,151 +405,6 @@ struct _indicator_item_t { GtkWidget * right; }; -/* Whenever we have a property change on a DbusmenuMenuitem - we need to be responsive to that. */ -static void -indicator_prop_change_cb (DbusmenuMenuitem * mi, gchar * prop, GVariant * value, indicator_item_t * mi_data) -{ - if (!g_strcmp0(prop, INDICATOR_MENUITEM_PROP_LABEL)) { - /* Set the main label */ - gtk_label_set_text(GTK_LABEL(mi_data->label), g_variant_get_string(value, NULL)); - } else if (!g_strcmp0(prop, INDICATOR_MENUITEM_PROP_RIGHT)) { - /* Set the right label */ - gtk_label_set_text(GTK_LABEL(mi_data->right), g_variant_get_string(value, NULL)); - } else if (!g_strcmp0(prop, INDICATOR_MENUITEM_PROP_RIGHT_IS_LOZENGE)) { - g_object_set_data (G_OBJECT (mi_data->right), "is-lozenge", GINT_TO_POINTER (TRUE)); - gtk_widget_queue_draw (mi_data->right); - } else if (!g_strcmp0(prop, INDICATOR_MENUITEM_PROP_ICON)) { - /* We don't use the value here, which is probably less efficient, - but it's easier to use the easy function. And since th value - is already cached, shouldn't be a big deal really. */ - GdkPixbuf * pixbuf = dbusmenu_menuitem_property_get_image(mi, INDICATOR_MENUITEM_PROP_ICON); - if (pixbuf != NULL) { - /* If we've got a pixbuf we need to make sure it's of a reasonable - size to fit in the menu. If not, rescale it. */ - GdkPixbuf * resized_pixbuf; - gint width, height; - gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height); - if (gdk_pixbuf_get_width(pixbuf) > width || - gdk_pixbuf_get_height(pixbuf) > height) { - g_debug("Resizing icon from %dx%d to %dx%d", gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf), width, height); - resized_pixbuf = gdk_pixbuf_scale_simple(pixbuf, - width, - height, - GDK_INTERP_BILINEAR); - g_object_unref(pixbuf); - } else { - g_debug("Happy with icon sized %dx%d", gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf)); - resized_pixbuf = pixbuf; - } - - gtk_image_set_from_pixbuf(GTK_IMAGE(mi_data->icon), resized_pixbuf); - - g_object_unref(resized_pixbuf); - - gtk_widget_show(mi_data->icon); - } else { - gtk_widget_hide(mi_data->icon); - } - } - - return; -} - -/* We have a small little menuitem type that handles all - of the fun stuff for indicators. Mostly this is the - shifting over and putting the icon in with some right - side text that'll be determined by the service. */ -static gboolean -new_indicator_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client, gpointer user_data) -{ - g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE); - g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE); - /* Note: not checking parent, it's reasonable for it to be NULL */ - - indicator_item_t * mi_data = g_new0(indicator_item_t, 1); - - GtkMenuItem * gmi = GTK_MENU_ITEM(gtk_menu_item_new()); - - gint padding = 4; - gint font_size = gtk_widget_get_font_size (GTK_WIDGET (gmi)); - gtk_widget_style_get(GTK_WIDGET(gmi), "toggle-spacing", &padding, NULL); - - GtkWidget * hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, padding); - - /* Icon, probably someone's face or avatar on an IM */ - mi_data->icon = gtk_image_new(); - - /* Set the minimum size, we always want it to take space */ - gint width, height; - gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height); - gtk_widget_set_size_request(GTK_WIDGET (gmi), -1, height + 4); - - gtk_widget_set_margin_left (hbox, width + padding); - - GdkPixbuf * pixbuf = dbusmenu_menuitem_property_get_image(newitem, INDICATOR_MENUITEM_PROP_ICON); - if (pixbuf != NULL) { - /* If we've got a pixbuf we need to make sure it's of a reasonable - size to fit in the menu. If not, rescale it. */ - GdkPixbuf * resized_pixbuf; - if (gdk_pixbuf_get_width(pixbuf) > width || - gdk_pixbuf_get_height(pixbuf) > height) { - g_debug("Resizing icon from %dx%d to %dx%d", gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf), width, height); - resized_pixbuf = gdk_pixbuf_scale_simple(pixbuf, - width, - height, - GDK_INTERP_BILINEAR); - g_object_unref(pixbuf); - } else { - g_debug("Happy with icon sized %dx%d", gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf)); - resized_pixbuf = pixbuf; - } - - gtk_image_set_from_pixbuf(GTK_IMAGE(mi_data->icon), resized_pixbuf); - - g_object_unref(resized_pixbuf); - } - gtk_misc_set_alignment(GTK_MISC(mi_data->icon), 0.0, 0.5); - gtk_box_pack_start(GTK_BOX(hbox), mi_data->icon, FALSE, FALSE, 0); - - if (pixbuf != NULL) { - gtk_widget_show(mi_data->icon); - } - - /* Label, probably a username, chat room or mailbox name */ - mi_data->label = gtk_label_new(dbusmenu_menuitem_property_get(newitem, INDICATOR_MENUITEM_PROP_LABEL)); - gtk_misc_set_alignment(GTK_MISC(mi_data->label), 0.0, 0.5); - gtk_box_pack_start(GTK_BOX(hbox), mi_data->label, TRUE, TRUE, 0); - gtk_widget_show(mi_data->label); - - /* Usually either the time or the count on the individual - item. */ - mi_data->right = gtk_label_new(dbusmenu_menuitem_property_get(newitem, INDICATOR_MENUITEM_PROP_RIGHT)); - g_object_set_data (G_OBJECT (mi_data->right), - "is-lozenge", - GINT_TO_POINTER (dbusmenu_menuitem_property_get_bool (newitem, INDICATOR_MENUITEM_PROP_RIGHT_IS_LOZENGE))); - /* install extra decoration overlay */ - g_signal_connect (G_OBJECT (mi_data->right), "draw", - G_CALLBACK (numbers_draw_cb), NULL); - - gtk_misc_set_alignment(GTK_MISC(mi_data->right), 1.0, 0.5); - gtk_box_pack_start(GTK_BOX(hbox), mi_data->right, FALSE, FALSE, padding + font_size/2.0); - gtk_label_set_width_chars (GTK_LABEL (mi_data->right), 2); - gtk_style_context_add_class (gtk_widget_get_style_context (mi_data->right), - "accelerator"); - gtk_widget_show(mi_data->right); - - gtk_container_add(GTK_CONTAINER(gmi), hbox); - gtk_widget_show(hbox); - - dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, gmi, parent); - - g_signal_connect(G_OBJECT(newitem), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(indicator_prop_change_cb), mi_data); - g_object_weak_ref(G_OBJECT(newitem), (GWeakNotify)g_free, mi_data); - - return TRUE; -} - /* Builds the main image icon using the libindicator helper. */ static GtkImage * get_icon (IndicatorObject * io) @@ -742,13 +419,13 @@ get_icon (IndicatorObject * io) static GtkMenu * get_menu (IndicatorObject * io) { - DbusmenuGtkMenu * menu = dbusmenu_gtkmenu_new(INDICATOR_MESSAGES_DBUS_NAME, INDICATOR_MESSAGES_DBUS_OBJECT); - DbusmenuGtkClient * client = dbusmenu_gtkmenu_get_client(menu); + IndicatorMessages *self = INDICATOR_MESSAGES (io); + GtkMenu *menu; - dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), INDICATOR_MENUITEM_TYPE, new_indicator_item); - dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), APPLICATION_MENUITEM_TYPE, new_application_item); + menu = menu_factory_gtk_new_menu (self->menu, self->actions); + gtk_widget_show_all (GTK_WIDGET (menu)); - return GTK_MENU(menu); + return menu; } /* Returns the accessible description of the indicator */ -- cgit v1.2.3 From 83f04d7c7df43dc4672a5686ecc5810f32efe000 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Fri, 25 May 2012 18:23:11 +0200 Subject: Remove dbusmenu dependency --- configure.ac | 2 -- 1 file changed, 2 deletions(-) diff --git a/configure.ac b/configure.ac index 2886046..e3beaa2 100644 --- a/configure.ac +++ b/configure.ac @@ -42,14 +42,12 @@ GTK_REQUIRED_VERSION=3.0 GIO_UNIX_REQUIRED_VERSION=2.18 PANEL_REQUIRED_VERSION=2.0.0 INDICATOR_REQUIRED_VERSION=0.3.19 -DBUSMENUGTK_REQUIRED_VERSION=0.5.90 GLIB_REQUIRED_VERSION=2.31.20 MENU_FACTORY_REQUIRED_VERSION=0.0 PKG_CHECK_MODULES(APPLET, gtk+-3.0 >= $GTK_REQUIRED_VERSION gio-unix-2.0 >= $GIO_UNIX_REQUIRED_VERSION indicator3-0.4 >= $INDICATOR_REQUIRED_VERSION - dbusmenu-gtk3-0.4 >= $DBUSMENUGTK_REQUIRED_VERSION glib-2.0 >= $GLIB_REQUIRED_VERSION gmodule-2.0 >= $GLIB_REQUIRED_VERSION menu-factory-gtk >= $MENU_FACTORY_REQUIRED_VERSION) -- cgit v1.2.3 From cb34c1a8d430a21330edc0119a6b74642f77c274 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Wed, 30 May 2012 19:23:43 +0200 Subject: Allow applications to (un)register themselves from the messaging menu via d-bus --- src/messages-service-dbus.c | 28 ++++++++++++++++ src/messages-service-dbus.h | 6 ++-- src/messages-service.c | 79 +++++++++++++++++++++++++++++++++++++++++---- src/messages-service.xml | 7 ++++ 4 files changed, 111 insertions(+), 9 deletions(-) diff --git a/src/messages-service-dbus.c b/src/messages-service-dbus.c index 2b72f2e..fec15e9 100644 --- a/src/messages-service-dbus.c +++ b/src/messages-service-dbus.c @@ -32,6 +32,8 @@ with this program. If not, see . enum { ATTENTION_CHANGED, ICON_CHANGED, + REGISTER_APPLICATION, + UNREGISTER_APPLICATION, LAST_SIGNAL }; @@ -101,6 +103,22 @@ message_service_dbus_class_init (MessageServiceDbusClass *klass) g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); + signals[REGISTER_APPLICATION] = g_signal_new(MESSAGE_SERVICE_DBUS_SIGNAL_REGISTER_APPLICATION, + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_generic, + G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING); + + signals[UNREGISTER_APPLICATION] = g_signal_new(MESSAGE_SERVICE_DBUS_SIGNAL_UNREGISTER_APPLICATION, + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, G_TYPE_STRING); + if (bus_node_info == NULL) { GError * error = NULL; @@ -418,6 +436,16 @@ bus_method_call (GDBusConnection * connection, const gchar * sender, const gchar message_service_dbus_set_attention(ms, FALSE); g_dbus_method_invocation_return_value(invocation, NULL); return; + } else if (g_strcmp0("RegisterApplication", method) == 0) { + const gchar *desktop_id, *object_path; + g_variant_get(params, "(&s&o)", &desktop_id, &object_path); + g_signal_emit(ms, signals[REGISTER_APPLICATION], 0, desktop_id, object_path); + g_dbus_method_invocation_return_value(invocation, NULL); + } else if (g_strcmp0("UnregisterApplication", method) == 0) { + const gchar *desktop_id; + g_variant_get(params, "(&s)", &desktop_id); + g_signal_emit(ms, signals[UNREGISTER_APPLICATION], 0, desktop_id); + g_dbus_method_invocation_return_value(invocation, NULL); } else { g_warning("Unknown function call '%s'", method); } diff --git a/src/messages-service-dbus.h b/src/messages-service-dbus.h index 7a8574e..f95b61b 100644 --- a/src/messages-service-dbus.h +++ b/src/messages-service-dbus.h @@ -35,8 +35,10 @@ G_BEGIN_DECLS #define IS_MESSAGE_SERVICE_DBUS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MESSAGE_SERVICE_DBUS_TYPE)) #define MESSAGE_SERVICE_DBUS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MESSAGE_SERVICE_DBUS_TYPE, MessageServiceDbusClass)) -#define MESSAGE_SERVICE_DBUS_SIGNAL_ATTENTION_CHANGED "attention-changed" -#define MESSAGE_SERVICE_DBUS_SIGNAL_ICON_CHANGED "icon-changed" +#define MESSAGE_SERVICE_DBUS_SIGNAL_ATTENTION_CHANGED "attention-changed" +#define MESSAGE_SERVICE_DBUS_SIGNAL_ICON_CHANGED "icon-changed" +#define MESSAGE_SERVICE_DBUS_SIGNAL_REGISTER_APPLICATION "register-application" +#define MESSAGE_SERVICE_DBUS_SIGNAL_UNREGISTER_APPLICATION "unregister-application" typedef struct _MessageServiceDbus MessageServiceDbus; typedef struct _MessageServiceDbusClass MessageServiceDbusClass; diff --git a/src/messages-service.c b/src/messages-service.c index cfc07fc..7c1a2b5 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -47,20 +47,17 @@ static GMainLoop * mainloop = NULL; static MessageServiceDbus * dbus_interface = NULL; -/* This function turns a specific desktop id into a menu - item and registers it appropriately with everyone */ -static gboolean -build_launcher (gpointer data) +static void +add_application (const gchar *desktop_id, + const gchar *menu_path) { - gchar *desktop_id = data; GDesktopAppInfo *appinfo; const gchar *desktop_file; appinfo = g_desktop_app_info_new (desktop_id); if (!appinfo) { g_warning ("could not find a desktop file with id '%s'\n", desktop_id); - g_free (desktop_id); - return FALSE; + return; } desktop_file = g_desktop_app_info_get_filename (appinfo); @@ -77,6 +74,17 @@ build_launcher (gpointer data) } g_object_unref (appinfo); +} + +/* This function turns a specific desktop id into a menu + item and registers it appropriately with everyone */ +static gboolean +build_launcher (gpointer data) +{ + gchar *desktop_id = data; + + add_application (desktop_id, NULL); + g_free (desktop_id); return FALSE; } @@ -128,6 +136,58 @@ clear_action_handler (MessageServiceDbus *msd, g_simple_action_set_enabled (action, attention); } +static void +register_application (MessageServiceDbus *msd, + const gchar *desktop_id, + const gchar *menu_path, + gpointer user_data) +{ + gchar **applications = g_settings_get_strv (settings, "applications"); + gchar **app; + + for (app = applications; *app; app++) { + if (!g_strcmp0 (desktop_id, *app)) + break; + } + + if (*app == NULL) { + GVariantBuilder builder; + + g_variant_builder_init (&builder, (GVariantType *)"as"); + for (app = applications; *app; app++) + g_variant_builder_add (&builder, "s", *app); + g_variant_builder_add (&builder, "s", desktop_id); + + g_settings_set_value (settings, "applications", + g_variant_builder_end (&builder)); + + add_application (desktop_id, menu_path); + } + + g_strfreev (applications); +} + +static void +unregister_application (MessageServiceDbus *msd, + const gchar *desktop_id, + gpointer user_data) +{ + gchar **applications = g_settings_get_strv (settings, "applications"); + gchar **app; + GVariantBuilder builder; + + g_variant_builder_init (&builder, (GVariantType *)"as"); + for (app = applications; *app; app++) { + if (g_strcmp0 (desktop_id, *app)) + g_variant_builder_add (&builder, "s", *app); + } + + g_settings_set_value (settings, "applications", + g_variant_builder_end (&builder)); + + g_strfreev (applications); +} + int main (int argc, char ** argv) { @@ -175,6 +235,11 @@ main (int argc, char ** argv) G_CALLBACK(clear_action_handler), g_action_map_lookup_action (G_ACTION_MAP (actions), "clear")); + g_signal_connect (dbus_interface, MESSAGE_SERVICE_DBUS_SIGNAL_REGISTER_APPLICATION, + G_CALLBACK (register_application), NULL); + g_signal_connect (dbus_interface, MESSAGE_SERVICE_DBUS_SIGNAL_UNREGISTER_APPLICATION, + G_CALLBACK (unregister_application), NULL); + status_items = status_items_build (g_action_map_lookup_action (G_ACTION_MAP (actions), "status")); menu = g_menu_new (); diff --git a/src/messages-service.xml b/src/messages-service.xml index d79049e..a560187 100644 --- a/src/messages-service.xml +++ b/src/messages-service.xml @@ -10,6 +10,13 @@ + + + + + + + -- cgit v1.2.3 From 0f9764c90a24880a5bda8ff047585ef65958cad4 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Thu, 31 May 2012 15:59:02 +0200 Subject: Remove an application from the menu after it unregistered --- src/messages-service.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/src/messages-service.c b/src/messages-service.c index 7c1a2b5..134c4ee 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -56,7 +56,7 @@ add_application (const gchar *desktop_id, appinfo = g_desktop_app_info_new (desktop_id); if (!appinfo) { - g_warning ("could not find a desktop file with id '%s'\n", desktop_id); + g_warning ("could not add '%s', there's no desktop file with that id", desktop_id); return; } @@ -76,6 +76,55 @@ add_application (const gchar *desktop_id, g_object_unref (appinfo); } +/* g_menu_model_find_section: + * + * @Returns the index of the first menu item that is linked to #section, or -1 + * if there's no such item. + */ +static int +g_menu_find_section (GMenu *menu, + GMenuModel *section) +{ + int n_items = g_menu_model_get_n_items (G_MENU_MODEL (menu)); + int i; + + for (i = 0; i < n_items; i++) { + if (section == g_menu_model_get_item_link (G_MENU_MODEL (menu), i, G_MENU_LINK_SECTION)) + return i; + } + + return -1; +} + +static void +remove_application (const char *desktop_id) +{ + GDesktopAppInfo *appinfo; + const gchar *desktop_file; + AppMenuItem *menuitem; + + appinfo = g_desktop_app_info_new (desktop_id); + if (!appinfo) { + g_warning ("could not remove '%s', there's no desktop file with that id", desktop_id); + return; + } + + desktop_file = g_desktop_app_info_get_filename (appinfo); + + menuitem = g_hash_table_lookup (applications, desktop_file); + if (menuitem) { + int pos = g_menu_find_section (menu, app_menu_item_get_menu (menuitem)); + if (pos >= 0) + g_menu_remove (menu, pos); + } + else { + g_warning ("could not remove '%s', it's not registered", desktop_id); + } + + g_hash_table_remove (applications, desktop_file); + g_object_unref (appinfo); +} + /* This function turns a specific desktop id into a menu item and registers it appropriately with everyone */ static gboolean @@ -185,6 +234,8 @@ unregister_application (MessageServiceDbus *msd, g_settings_set_value (settings, "applications", g_variant_builder_end (&builder)); + remove_application (desktop_id); + g_strfreev (applications); } -- cgit v1.2.3 From 4f2dd60a130dcaeb4378219baca1f3d4e9637824 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Thu, 31 May 2012 18:55:06 +0200 Subject: Rename AppMenuItem to AppSection --- po/POTFILES.in | 3 - src/Makefile.am | 4 +- src/app-menu-item.c | 322 ------------------------------------------------- src/app-menu-item.h | 58 --------- src/app-section.c | 321 ++++++++++++++++++++++++++++++++++++++++++++++++ src/app-section.h | 58 +++++++++ src/messages-service.c | 18 +-- test/Makefile.am | 4 +- 8 files changed, 392 insertions(+), 396 deletions(-) delete mode 100644 src/app-menu-item.c delete mode 100644 src/app-menu-item.h create mode 100644 src/app-section.c create mode 100644 src/app-section.h diff --git a/po/POTFILES.in b/po/POTFILES.in index 051f8f3..2d93682 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -3,7 +3,4 @@ src/messages-service-dbus.c src/indicator-messages.c src/messages-service.c src/default-applications.c -src/launcher-menu-item.c -src/im-menu-item.c -src/app-menu-item.c src/status-items.c diff --git a/src/Makefile.am b/src/Makefile.am index 2527878..1dbb514 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -42,8 +42,8 @@ indicator_messages_service_SOURCES = \ messages-service-dbus.h \ gen-messages-service.xml.h \ gen-messages-service.xml.c \ - app-menu-item.c \ - app-menu-item.h \ + app-section.c \ + app-section.h \ dbus-data.h \ \ status-items.c \ diff --git a/src/app-menu-item.c b/src/app-menu-item.c deleted file mode 100644 index 7638eb5..0000000 --- a/src/app-menu-item.c +++ /dev/null @@ -1,322 +0,0 @@ -/* -An indicator to show information that is in messaging applications -that the user is using. - -Copyright 2009 Canonical Ltd. - -Authors: - Ted Gould - -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 . -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include "app-menu-item.h" -#include "dbus-data.h" - -typedef struct _AppMenuItemPrivate AppMenuItemPrivate; - -struct _AppMenuItemPrivate -{ - GDesktopAppInfo * appinfo; - guint unreadcount; - - IndicatorDesktopShortcuts * ids; - - GMenu *menu; - GSimpleActionGroup *static_shortcuts; -}; - -#define APP_MENU_ITEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), APP_MENU_ITEM_TYPE, AppMenuItemPrivate)) - -enum { - PROP_0, - PROP_APPINFO, - NUM_PROPERTIES -}; - -static GParamSpec *properties[NUM_PROPERTIES]; - -/* Prototypes */ -static void app_menu_item_class_init (AppMenuItemClass *klass); -static void app_menu_item_init (AppMenuItem *self); -static void app_menu_item_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec); -static void app_menu_item_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec); -static void app_menu_item_dispose (GObject *object); -static void activate_cb (GSimpleAction *action, - GVariant *param, - gpointer userdata); -static void app_menu_item_set_app_info (AppMenuItem *self, - GDesktopAppInfo *appinfo); - -/* GObject Boilerplate */ -G_DEFINE_TYPE (AppMenuItem, app_menu_item, G_TYPE_OBJECT); - -static void -app_menu_item_class_init (AppMenuItemClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (AppMenuItemPrivate)); - - object_class->get_property = app_menu_item_get_property; - object_class->set_property = app_menu_item_set_property; - object_class->dispose = app_menu_item_dispose; - - properties[PROP_APPINFO] = g_param_spec_object ("app-info", - "AppInfo", - "The GAppInfo for the app that this menu represents", - G_TYPE_APP_INFO, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); - - g_object_class_install_properties (object_class, NUM_PROPERTIES, properties); -} - -static void -app_menu_item_init (AppMenuItem *self) -{ - g_debug("Building new App Menu Item"); - AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self); - - priv->appinfo = NULL; - priv->unreadcount = 0; - - priv->menu = g_menu_new (); - priv->static_shortcuts = g_simple_action_group_new (); - - return; -} - -static void -app_menu_item_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - AppMenuItem *self = APP_MENU_ITEM (object); - - switch (property_id) - { - case PROP_APPINFO: - g_value_set_object (value, app_menu_item_get_app_info (self)); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - } -} - -static void -app_menu_item_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - AppMenuItem *self = APP_MENU_ITEM (object); - - switch (property_id) - { - case PROP_APPINFO: - app_menu_item_set_app_info (self, g_value_get_object (value)); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - } -} -static void -app_menu_item_dispose (GObject *object) -{ - AppMenuItem * self = APP_MENU_ITEM(object); - AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self); - - g_clear_object (&priv->menu); - g_clear_object (&priv->static_shortcuts); - - if (priv->ids != NULL) { - g_object_unref(priv->ids); - priv->ids = NULL; - } - - if (priv->appinfo != NULL) { - g_object_unref(priv->appinfo); - priv->appinfo = NULL; - } - - G_OBJECT_CLASS (app_menu_item_parent_class)->dispose (object); -} - -/* Respond to one of the shortcuts getting clicked on. */ -static void -nick_activate_cb (GSimpleAction *action, - GVariant *param, - gpointer userdata) -{ - const gchar * nick = g_action_get_name (G_ACTION (action)); - AppMenuItem * mi = APP_MENU_ITEM (userdata); - AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(mi); - - g_return_if_fail(priv->ids != NULL); - - if (!indicator_desktop_shortcuts_nick_exec(priv->ids, nick)) { - g_warning("Unable to execute nick '%s' for desktop file '%s'", - nick, g_desktop_app_info_get_filename (priv->appinfo)); - } -} - -static void -app_menu_item_set_app_info (AppMenuItem *self, - GDesktopAppInfo *appinfo) -{ - AppMenuItemPrivate *priv = APP_MENU_ITEM_GET_PRIVATE (self); - GSimpleAction *launch; - GMenuItem *menuitem; - GIcon *icon; - gchar *iconstr = NULL; - gchar *label; - - g_return_if_fail (priv->appinfo == NULL); - - if (appinfo == NULL) { - g_warning ("appinfo must not be NULL"); - return; - } - - priv->appinfo = g_object_ref (appinfo); - - icon = g_app_info_get_icon (G_APP_INFO(priv->appinfo)); - iconstr = g_icon_to_string (icon); - - launch = g_simple_action_new ("launch", NULL); - g_signal_connect (launch, "activate", G_CALLBACK (activate_cb), self); - g_simple_action_group_insert (priv->static_shortcuts, G_ACTION (launch)); - - if (priv->unreadcount > 0) - label = g_strdup_printf("%s (%d)", app_menu_item_get_name (self), priv->unreadcount); - else - label = g_strdup(app_menu_item_get_name (self)); - - menuitem = g_menu_item_new (label, "launch"); - g_menu_item_set_attribute (menuitem, INDICATOR_MENU_ATTRIBUTE_ICON_NAME, "s", iconstr); - g_menu_append_item (priv->menu, menuitem); - - /* Start to build static shortcuts */ - priv->ids = indicator_desktop_shortcuts_new(g_desktop_app_info_get_filename (priv->appinfo), "Messaging Menu"); - const gchar ** nicks = indicator_desktop_shortcuts_get_nicks(priv->ids); - gint i; - for (i = 0; nicks[i] != NULL; i++) { - gchar *name; - GSimpleAction *action; - GMenuItem *item; - - name = indicator_desktop_shortcuts_nick_get_name(priv->ids, nicks[i]); - - action = g_simple_action_new (name, NULL); - g_signal_connect(action, "activate", G_CALLBACK (nick_activate_cb), self); - g_simple_action_group_insert (priv->static_shortcuts, G_ACTION (action)); - - item = g_menu_item_new (name, name); - g_menu_append_item (priv->menu, item); - - g_object_unref (item); - g_free(name); - } - - g_free(label); - g_free(iconstr); - g_object_unref (launch); - g_object_unref (menuitem); -} - -AppMenuItem * -app_menu_item_new (GDesktopAppInfo *appinfo) -{ - return g_object_new (APP_MENU_ITEM_TYPE, - "app-info", appinfo, - NULL); -} - -static void -activate_cb (GSimpleAction *action, - GVariant *param, - gpointer userdata) -{ - AppMenuItem * mi = APP_MENU_ITEM (userdata); - AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(mi); - GError *error = NULL; - - if (!g_app_info_launch (G_APP_INFO (priv->appinfo), NULL, NULL, &error)) { - g_warning("Unable to execute application for desktop file '%s'", - g_desktop_app_info_get_filename (priv->appinfo)); - } -} - -guint -app_menu_item_get_count (AppMenuItem * appitem) -{ - g_return_val_if_fail(IS_APP_MENU_ITEM(appitem), 0); - AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(appitem); - - return priv->unreadcount; -} - -const gchar * -app_menu_item_get_name (AppMenuItem * appitem) -{ - g_return_val_if_fail(IS_APP_MENU_ITEM(appitem), NULL); - AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(appitem); - - if (priv->appinfo) { - return g_app_info_get_name(G_APP_INFO(priv->appinfo)); - } - return NULL; -} - -const gchar * -app_menu_item_get_desktop (AppMenuItem * appitem) -{ - g_return_val_if_fail(IS_APP_MENU_ITEM(appitem), NULL); - AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(appitem); - if (priv->appinfo) - return g_desktop_app_info_get_filename (priv->appinfo); - else - return NULL; -} - -GMenuModel * -app_menu_item_get_menu (AppMenuItem *appitem) -{ - AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(appitem); - return G_MENU_MODEL (priv->menu); -} - -GAppInfo * -app_menu_item_get_app_info (AppMenuItem *appitem) -{ - AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(appitem); - return G_APP_INFO (priv->appinfo); -} - diff --git a/src/app-menu-item.h b/src/app-menu-item.h deleted file mode 100644 index 1fb2762..0000000 --- a/src/app-menu-item.h +++ /dev/null @@ -1,58 +0,0 @@ -/* -An indicator to show information that is in messaging applications -that the user is using. - -Copyright 2009 Canonical Ltd. - -Authors: - Ted Gould - -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 . -*/ -#ifndef __APP_MENU_ITEM_H__ -#define __APP_MENU_ITEM_H__ - -#include - -G_BEGIN_DECLS - -#define APP_MENU_ITEM_TYPE (app_menu_item_get_type ()) -#define APP_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), APP_MENU_ITEM_TYPE, AppMenuItem)) -#define APP_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), APP_MENU_ITEM_TYPE, AppMenuItemClass)) -#define IS_APP_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), APP_MENU_ITEM_TYPE)) -#define IS_APP_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), APP_MENU_ITEM_TYPE)) -#define APP_MENU_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), APP_MENU_ITEM_TYPE, AppMenuItemClass)) - -typedef struct _AppMenuItem AppMenuItem; -typedef struct _AppMenuItemClass AppMenuItemClass; - -struct _AppMenuItemClass { - GObjectClass parent_class; -}; - -struct _AppMenuItem { - GObject parent; -}; - -GType app_menu_item_get_type (void); -AppMenuItem * app_menu_item_new (GDesktopAppInfo *appinfo); -guint app_menu_item_get_count (AppMenuItem * appitem); -const gchar * app_menu_item_get_name (AppMenuItem * appitem); -const gchar * app_menu_item_get_desktop (AppMenuItem * appitem); -GMenuModel * app_menu_item_get_menu (AppMenuItem *appitem); -GAppInfo * app_menu_item_get_app_info (AppMenuItem *appitem); - -G_END_DECLS - -#endif /* __APP_MENU_ITEM_H__ */ - diff --git a/src/app-section.c b/src/app-section.c new file mode 100644 index 0000000..5a5e838 --- /dev/null +++ b/src/app-section.c @@ -0,0 +1,321 @@ +/* +An indicator to show information that is in messaging applications +that the user is using. + +Copyright 2009 Canonical Ltd. + +Authors: + Ted Gould + +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 . +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include "app-section.h" +#include "dbus-data.h" + +typedef struct _AppSectionPrivate AppSectionPrivate; + +struct _AppSectionPrivate +{ + GDesktopAppInfo * appinfo; + guint unreadcount; + + IndicatorDesktopShortcuts * ids; + + GMenu *menu; + GSimpleActionGroup *static_shortcuts; +}; + +#define APP_SECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), APP_SECTION_TYPE, AppSectionPrivate)) + +enum { + PROP_0, + PROP_APPINFO, + NUM_PROPERTIES +}; + +static GParamSpec *properties[NUM_PROPERTIES]; + +/* Prototypes */ +static void app_section_class_init (AppSectionClass *klass); +static void app_section_init (AppSection *self); +static void app_section_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void app_section_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); +static void app_section_dispose (GObject *object); +static void activate_cb (GSimpleAction *action, + GVariant *param, + gpointer userdata); +static void app_section_set_app_info (AppSection *self, + GDesktopAppInfo *appinfo); + +/* GObject Boilerplate */ +G_DEFINE_TYPE (AppSection, app_section, G_TYPE_OBJECT); + +static void +app_section_class_init (AppSectionClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (AppSectionPrivate)); + + object_class->get_property = app_section_get_property; + object_class->set_property = app_section_set_property; + object_class->dispose = app_section_dispose; + + properties[PROP_APPINFO] = g_param_spec_object ("app-info", + "AppInfo", + "The GAppInfo for the app that this menu represents", + G_TYPE_APP_INFO, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + + g_object_class_install_properties (object_class, NUM_PROPERTIES, properties); +} + +static void +app_section_init (AppSection *self) +{ + AppSectionPrivate * priv = APP_SECTION_GET_PRIVATE(self); + + priv->appinfo = NULL; + priv->unreadcount = 0; + + priv->menu = g_menu_new (); + priv->static_shortcuts = g_simple_action_group_new (); + + return; +} + +static void +app_section_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + AppSection *self = APP_SECTION (object); + + switch (property_id) + { + case PROP_APPINFO: + g_value_set_object (value, app_section_get_app_info (self)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +app_section_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + AppSection *self = APP_SECTION (object); + + switch (property_id) + { + case PROP_APPINFO: + app_section_set_app_info (self, g_value_get_object (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} +static void +app_section_dispose (GObject *object) +{ + AppSection * self = APP_SECTION(object); + AppSectionPrivate * priv = APP_SECTION_GET_PRIVATE(self); + + g_clear_object (&priv->menu); + g_clear_object (&priv->static_shortcuts); + + if (priv->ids != NULL) { + g_object_unref(priv->ids); + priv->ids = NULL; + } + + if (priv->appinfo != NULL) { + g_object_unref(priv->appinfo); + priv->appinfo = NULL; + } + + G_OBJECT_CLASS (app_section_parent_class)->dispose (object); +} + +/* Respond to one of the shortcuts getting clicked on. */ +static void +nick_activate_cb (GSimpleAction *action, + GVariant *param, + gpointer userdata) +{ + const gchar * nick = g_action_get_name (G_ACTION (action)); + AppSection * mi = APP_SECTION (userdata); + AppSectionPrivate * priv = APP_SECTION_GET_PRIVATE(mi); + + g_return_if_fail(priv->ids != NULL); + + if (!indicator_desktop_shortcuts_nick_exec(priv->ids, nick)) { + g_warning("Unable to execute nick '%s' for desktop file '%s'", + nick, g_desktop_app_info_get_filename (priv->appinfo)); + } +} + +static void +app_section_set_app_info (AppSection *self, + GDesktopAppInfo *appinfo) +{ + AppSectionPrivate *priv = APP_SECTION_GET_PRIVATE (self); + GSimpleAction *launch; + GMenuItem *menuitem; + GIcon *icon; + gchar *iconstr = NULL; + gchar *label; + + g_return_if_fail (priv->appinfo == NULL); + + if (appinfo == NULL) { + g_warning ("appinfo must not be NULL"); + return; + } + + priv->appinfo = g_object_ref (appinfo); + + icon = g_app_info_get_icon (G_APP_INFO(priv->appinfo)); + iconstr = g_icon_to_string (icon); + + launch = g_simple_action_new ("launch", NULL); + g_signal_connect (launch, "activate", G_CALLBACK (activate_cb), self); + g_simple_action_group_insert (priv->static_shortcuts, G_ACTION (launch)); + + if (priv->unreadcount > 0) + label = g_strdup_printf("%s (%d)", app_section_get_name (self), priv->unreadcount); + else + label = g_strdup(app_section_get_name (self)); + + menuitem = g_menu_item_new (label, "launch"); + g_menu_item_set_attribute (menuitem, INDICATOR_MENU_ATTRIBUTE_ICON_NAME, "s", iconstr); + g_menu_append_item (priv->menu, menuitem); + + /* Start to build static shortcuts */ + priv->ids = indicator_desktop_shortcuts_new(g_desktop_app_info_get_filename (priv->appinfo), "Messaging Menu"); + const gchar ** nicks = indicator_desktop_shortcuts_get_nicks(priv->ids); + gint i; + for (i = 0; nicks[i] != NULL; i++) { + gchar *name; + GSimpleAction *action; + GMenuItem *item; + + name = indicator_desktop_shortcuts_nick_get_name(priv->ids, nicks[i]); + + action = g_simple_action_new (name, NULL); + g_signal_connect(action, "activate", G_CALLBACK (nick_activate_cb), self); + g_simple_action_group_insert (priv->static_shortcuts, G_ACTION (action)); + + item = g_menu_item_new (name, name); + g_menu_append_item (priv->menu, item); + + g_object_unref (item); + g_free(name); + } + + g_free(label); + g_free(iconstr); + g_object_unref (launch); + g_object_unref (menuitem); +} + +AppSection * +app_section_new (GDesktopAppInfo *appinfo) +{ + return g_object_new (APP_SECTION_TYPE, + "app-info", appinfo, + NULL); +} + +static void +activate_cb (GSimpleAction *action, + GVariant *param, + gpointer userdata) +{ + AppSection * mi = APP_SECTION (userdata); + AppSectionPrivate * priv = APP_SECTION_GET_PRIVATE(mi); + GError *error = NULL; + + if (!g_app_info_launch (G_APP_INFO (priv->appinfo), NULL, NULL, &error)) { + g_warning("Unable to execute application for desktop file '%s'", + g_desktop_app_info_get_filename (priv->appinfo)); + } +} + +guint +app_section_get_count (AppSection * self) +{ + g_return_val_if_fail(IS_APP_SECTION(self), 0); + AppSectionPrivate * priv = APP_SECTION_GET_PRIVATE(self); + + return priv->unreadcount; +} + +const gchar * +app_section_get_name (AppSection * self) +{ + g_return_val_if_fail(IS_APP_SECTION(self), NULL); + AppSectionPrivate * priv = APP_SECTION_GET_PRIVATE(self); + + if (priv->appinfo) { + return g_app_info_get_name(G_APP_INFO(priv->appinfo)); + } + return NULL; +} + +const gchar * +app_section_get_desktop (AppSection * self) +{ + g_return_val_if_fail(IS_APP_SECTION(self), NULL); + AppSectionPrivate * priv = APP_SECTION_GET_PRIVATE(self); + if (priv->appinfo) + return g_desktop_app_info_get_filename (priv->appinfo); + else + return NULL; +} + +GMenuModel * +app_section_get_menu (AppSection *self) +{ + AppSectionPrivate * priv = APP_SECTION_GET_PRIVATE(self); + return G_MENU_MODEL (priv->menu); +} + +GAppInfo * +app_section_get_app_info (AppSection *self) +{ + AppSectionPrivate * priv = APP_SECTION_GET_PRIVATE(self); + return G_APP_INFO (priv->appinfo); +} + diff --git a/src/app-section.h b/src/app-section.h new file mode 100644 index 0000000..7989824 --- /dev/null +++ b/src/app-section.h @@ -0,0 +1,58 @@ +/* +An indicator to show information that is in messaging applications +that the user is using. + +Copyright 2009 Canonical Ltd. + +Authors: + Ted Gould + +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 . +*/ +#ifndef __APP_SECTION_H__ +#define __APP_SECTION_H__ + +#include + +G_BEGIN_DECLS + +#define APP_SECTION_TYPE (app_section_get_type ()) +#define APP_SECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), APP_SECTION_TYPE, AppSection)) +#define APP_SECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), APP_SECTION_TYPE, AppSectionClass)) +#define IS_APP_SECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), APP_SECTION_TYPE)) +#define IS_APP_SECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), APP_SECTION_TYPE)) +#define APP_SECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), APP_SECTION_TYPE, AppSectionClass)) + +typedef struct _AppSection AppSection; +typedef struct _AppSectionClass AppSectionClass; + +struct _AppSectionClass { + GObjectClass parent_class; +}; + +struct _AppSection { + GObject parent; +}; + +GType app_section_get_type (void); +AppSection * app_section_new (GDesktopAppInfo *appinfo); +guint app_section_get_count (AppSection * appitem); +const gchar * app_section_get_name (AppSection * appitem); +const gchar * app_section_get_desktop (AppSection * appitem); +GMenuModel * app_section_get_menu (AppSection *appitem); +GAppInfo * app_section_get_app_info (AppSection *appitem); + +G_END_DECLS + +#endif /* __APP_SECTION_H__ */ + diff --git a/src/messages-service.c b/src/messages-service.c index 134c4ee..dcce1c5 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -30,7 +30,7 @@ with this program. If not, see . #include #include -#include "app-menu-item.h" +#include "app-section.h" #include "dbus-data.h" #include "messages-service-dbus.h" #include "status-items.h" @@ -63,14 +63,14 @@ add_application (const gchar *desktop_id, desktop_file = g_desktop_app_info_get_filename (appinfo); if (!g_hash_table_lookup (applications, desktop_file)) { - AppMenuItem *menuitem = app_menu_item_new(appinfo); + AppSection *section = app_section_new(appinfo); /* TODO insert it at the right position (alphabetically by application name) */ g_menu_insert_section (menu, 2, - app_menu_item_get_name (menuitem), - app_menu_item_get_menu (menuitem)); + app_section_get_name (section), + app_section_get_menu (section)); - g_hash_table_insert (applications, g_strdup (desktop_file), menuitem); + g_hash_table_insert (applications, g_strdup (desktop_file), section); } g_object_unref (appinfo); @@ -101,7 +101,7 @@ remove_application (const char *desktop_id) { GDesktopAppInfo *appinfo; const gchar *desktop_file; - AppMenuItem *menuitem; + AppSection *section; appinfo = g_desktop_app_info_new (desktop_id); if (!appinfo) { @@ -111,9 +111,9 @@ remove_application (const char *desktop_id) desktop_file = g_desktop_app_info_get_filename (appinfo); - menuitem = g_hash_table_lookup (applications, desktop_file); - if (menuitem) { - int pos = g_menu_find_section (menu, app_menu_item_get_menu (menuitem)); + section = g_hash_table_lookup (applications, desktop_file); + if (section) { + int pos = g_menu_find_section (menu, app_section_get_menu (section)); if (pos >= 0) g_menu_remove (menu, pos); } diff --git a/test/Makefile.am b/test/Makefile.am index 847d857..2b0f67e 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -40,7 +40,7 @@ lib_LTLIBRARIES = \ libindicator_messages_service_la_HEADERS = \ $(top_srcdir)/src/gen-messages-service.xml.h \ - $(top_srcdir)/src/app-menu-item.h \ + $(top_srcdir)/src/app-section.h \ $(top_srcdir)/src/dbus-data.h \ $(top_srcdir)/src/status-items.h @@ -48,7 +48,7 @@ libindicator_messages_service_la_SOURCES = \ $(top_srcdir)/src/messages-service.c \ $(top_srcdir)/src/messages-service-dbus.c \ $(top_srcdir)/src/gen-messages-service.xml.c \ - $(top_srcdir)/src/app-menu-item.c \ + $(top_srcdir)/src/app-section.c \ $(top_srcdir)/src/status-items.c libindicator_messages_service_ladir = \ -- cgit v1.2.3 From eea45a449eb4de159aab08bad864b27f584af519 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Thu, 31 May 2012 19:29:27 +0200 Subject: Put the 'launch' action onto app's menu sections This requires clients to make those menu sections clickable. --- src/app-section.c | 33 +++++++++++++++++++++------------ src/app-section.h | 1 + src/messages-service.c | 9 +++++---- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/app-section.c b/src/app-section.c index 5a5e838..5cb2c25 100644 --- a/src/app-section.c +++ b/src/app-section.c @@ -192,9 +192,6 @@ app_section_set_app_info (AppSection *self, { AppSectionPrivate *priv = APP_SECTION_GET_PRIVATE (self); GSimpleAction *launch; - GMenuItem *menuitem; - GIcon *icon; - gchar *iconstr = NULL; gchar *label; g_return_if_fail (priv->appinfo == NULL); @@ -206,9 +203,6 @@ app_section_set_app_info (AppSection *self, priv->appinfo = g_object_ref (appinfo); - icon = g_app_info_get_icon (G_APP_INFO(priv->appinfo)); - iconstr = g_icon_to_string (icon); - launch = g_simple_action_new ("launch", NULL); g_signal_connect (launch, "activate", G_CALLBACK (activate_cb), self); g_simple_action_group_insert (priv->static_shortcuts, G_ACTION (launch)); @@ -218,10 +212,6 @@ app_section_set_app_info (AppSection *self, else label = g_strdup(app_section_get_name (self)); - menuitem = g_menu_item_new (label, "launch"); - g_menu_item_set_attribute (menuitem, INDICATOR_MENU_ATTRIBUTE_ICON_NAME, "s", iconstr); - g_menu_append_item (priv->menu, menuitem); - /* Start to build static shortcuts */ priv->ids = indicator_desktop_shortcuts_new(g_desktop_app_info_get_filename (priv->appinfo), "Messaging Menu"); const gchar ** nicks = indicator_desktop_shortcuts_get_nicks(priv->ids); @@ -245,9 +235,7 @@ app_section_set_app_info (AppSection *self, } g_free(label); - g_free(iconstr); g_object_unref (launch); - g_object_unref (menuitem); } AppSection * @@ -319,3 +307,24 @@ app_section_get_app_info (AppSection *self) return G_APP_INFO (priv->appinfo); } +GMenuItem * +app_section_create_menu_item (AppSection *self) +{ + AppSectionPrivate *priv = APP_SECTION_GET_PRIVATE (self); + GMenuItem *item; + const gchar *name; + gchar *iconstr; + + g_return_val_if_fail (priv->appinfo != NULL, NULL); + + name = g_app_info_get_name (G_APP_INFO (priv->appinfo)); + iconstr = g_icon_to_string (g_app_info_get_icon (G_APP_INFO (priv->appinfo))); + + item = g_menu_item_new (name, "launch"); + g_menu_item_set_attribute (item, INDICATOR_MENU_ATTRIBUTE_ICON_NAME, "s", iconstr); + g_menu_item_set_section (item, G_MENU_MODEL (priv->menu)); + + g_free(iconstr); + return item; +} + diff --git a/src/app-section.h b/src/app-section.h index 7989824..e5c3892 100644 --- a/src/app-section.h +++ b/src/app-section.h @@ -51,6 +51,7 @@ const gchar * app_section_get_name (AppSection * appitem); const gchar * app_section_get_desktop (AppSection * appitem); GMenuModel * app_section_get_menu (AppSection *appitem); GAppInfo * app_section_get_app_info (AppSection *appitem); +GMenuItem * app_section_create_menu_item (AppSection *self); G_END_DECLS diff --git a/src/messages-service.c b/src/messages-service.c index dcce1c5..ddedee9 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -64,13 +64,14 @@ add_application (const gchar *desktop_id, if (!g_hash_table_lookup (applications, desktop_file)) { AppSection *section = app_section_new(appinfo); + GMenuItem *item = app_section_create_menu_item (section); + + g_hash_table_insert (applications, g_strdup (desktop_file), section); /* TODO insert it at the right position (alphabetically by application name) */ - g_menu_insert_section (menu, 2, - app_section_get_name (section), - app_section_get_menu (section)); + g_menu_insert_item (menu, 2, item); - g_hash_table_insert (applications, g_strdup (desktop_file), section); + g_object_unref (item); } g_object_unref (appinfo); -- cgit v1.2.3 From b4062c831c830df78baeecf092e7c5e7198afada Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Thu, 31 May 2012 19:34:44 +0200 Subject: app-section: fix indentation --- src/app-section.c | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/app-section.c b/src/app-section.c index 5cb2c25..6990611 100644 --- a/src/app-section.c +++ b/src/app-section.c @@ -55,22 +55,22 @@ enum { static GParamSpec *properties[NUM_PROPERTIES]; /* Prototypes */ -static void app_section_class_init (AppSectionClass *klass); -static void app_section_init (AppSection *self); -static void app_section_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec); -static void app_section_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec); -static void app_section_dispose (GObject *object); -static void activate_cb (GSimpleAction *action, - GVariant *param, - gpointer userdata); -static void app_section_set_app_info (AppSection *self, - GDesktopAppInfo *appinfo); +static void app_section_class_init (AppSectionClass *klass); +static void app_section_init (AppSection *self); +static void app_section_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void app_section_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); +static void app_section_dispose (GObject *object); +static void activate_cb (GSimpleAction *action, + GVariant *param, + gpointer userdata); +static void app_section_set_app_info (AppSection *self, + GDesktopAppInfo *appinfo); /* GObject Boilerplate */ G_DEFINE_TYPE (AppSection, app_section, G_TYPE_OBJECT); @@ -111,9 +111,9 @@ app_section_init (AppSection *self) static void app_section_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) + guint property_id, + GValue *value, + GParamSpec *pspec) { AppSection *self = APP_SECTION (object); @@ -130,9 +130,9 @@ app_section_get_property (GObject *object, static void app_section_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) + guint property_id, + const GValue *value, + GParamSpec *pspec) { AppSection *self = APP_SECTION (object); @@ -188,7 +188,7 @@ nick_activate_cb (GSimpleAction *action, static void app_section_set_app_info (AppSection *self, - GDesktopAppInfo *appinfo) + GDesktopAppInfo *appinfo) { AppSectionPrivate *priv = APP_SECTION_GET_PRIVATE (self); GSimpleAction *launch; -- cgit v1.2.3 From 21f3cac4cb191430abf89b7cebd0093952c827b0 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Sat, 2 Jun 2012 16:44:47 +0200 Subject: Listen to actions exported by applications --- src/app-section.c | 68 +++++++++++++++++++++++++++++++++++++++++++++ src/app-section.h | 5 ++++ src/messages-service-dbus.c | 4 +-- src/messages-service.c | 57 +++++++++++++++++++++++++------------ 4 files changed, 114 insertions(+), 20 deletions(-) diff --git a/src/app-section.c b/src/app-section.c index 6990611..6d00cf1 100644 --- a/src/app-section.c +++ b/src/app-section.c @@ -42,6 +42,9 @@ struct _AppSectionPrivate GMenu *menu; GSimpleActionGroup *static_shortcuts; + GActionGroup *actions; + + guint name_watch_id; }; #define APP_SECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), APP_SECTION_TYPE, AppSectionPrivate)) @@ -155,6 +158,12 @@ app_section_dispose (GObject *object) g_clear_object (&priv->menu); g_clear_object (&priv->static_shortcuts); + if (priv->actions) { + g_clear_object (&priv->actions); + g_bus_unwatch_name (priv->name_watch_id); + priv->name_watch_id = 0; + } + if (priv->ids != NULL) { g_object_unref(priv->ids); priv->ids = NULL; @@ -328,3 +337,62 @@ app_section_create_menu_item (AppSection *self) return item; } +static void +application_vanished (GDBusConnection *bus, + const gchar *name, + gpointer user_data) +{ + AppSection *self = user_data; + + app_section_unset_object_path (self); +} + +/* + * app_section_set_object_path: + * @self: an #AppSection + * @bus: a #GDBusConnection + * @bus_name: the bus name of the application + * @object_path: the object path on which the app exports its actions and menus + * + * Sets the D-Bus object path exported by an instance of the application + * associated with @self. Actions and menus exported on that path will be + * shown in the section. + */ +void +app_section_set_object_path (AppSection *self, + GDBusConnection *bus, + const gchar *bus_name, + const gchar *object_path) +{ + AppSectionPrivate *priv = APP_SECTION_GET_PRIVATE (self); + + if (priv->actions) { + g_clear_object (&priv->actions); + g_bus_unwatch_name (priv->name_watch_id); + } + + priv->actions = G_ACTION_GROUP (g_dbus_action_group_get (bus, bus_name, object_path)); + priv->name_watch_id = g_bus_watch_name_on_connection (bus, bus_name, 0, + NULL, application_vanished, + self, NULL); +} + +/* + * app_section_unset_object_path: + * @self: an #AppSection + * + * Unsets the object path set with app_section_set_object_path(). The section + * will return to only showing application name and static shortcuts in the + * menu. + */ +void +app_section_unset_object_path (AppSection *self) +{ + AppSectionPrivate *priv = APP_SECTION_GET_PRIVATE (self); + + if (priv->actions) { + g_clear_object (&priv->actions); + g_bus_unwatch_name (priv->name_watch_id); + } +} + diff --git a/src/app-section.h b/src/app-section.h index e5c3892..aa6ef75 100644 --- a/src/app-section.h +++ b/src/app-section.h @@ -52,6 +52,11 @@ const gchar * app_section_get_desktop (AppSection * appitem); GMenuModel * app_section_get_menu (AppSection *appitem); GAppInfo * app_section_get_app_info (AppSection *appitem); GMenuItem * app_section_create_menu_item (AppSection *self); +void app_section_set_object_path (AppSection *self, + GDBusConnection *bus, + const gchar *bus_name, + const gchar *object_path); +void app_section_unset_object_path (AppSection *self); G_END_DECLS diff --git a/src/messages-service-dbus.c b/src/messages-service-dbus.c index fec15e9..3a39172 100644 --- a/src/messages-service-dbus.c +++ b/src/messages-service-dbus.c @@ -109,7 +109,7 @@ message_service_dbus_class_init (MessageServiceDbusClass *klass) 0, NULL, NULL, g_cclosure_marshal_generic, - G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING); + G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); signals[UNREGISTER_APPLICATION] = g_signal_new(MESSAGE_SERVICE_DBUS_SIGNAL_UNREGISTER_APPLICATION, G_TYPE_FROM_CLASS(klass), @@ -439,7 +439,7 @@ bus_method_call (GDBusConnection * connection, const gchar * sender, const gchar } else if (g_strcmp0("RegisterApplication", method) == 0) { const gchar *desktop_id, *object_path; g_variant_get(params, "(&s&o)", &desktop_id, &object_path); - g_signal_emit(ms, signals[REGISTER_APPLICATION], 0, desktop_id, object_path); + g_signal_emit(ms, signals[REGISTER_APPLICATION], 0, sender, desktop_id, object_path); g_dbus_method_invocation_return_value(invocation, NULL); } else if (g_strcmp0("UnregisterApplication", method) == 0) { const gchar *desktop_id; diff --git a/src/messages-service.c b/src/messages-service.c index ddedee9..28a64a0 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -47,34 +47,36 @@ static GMainLoop * mainloop = NULL; static MessageServiceDbus * dbus_interface = NULL; -static void -add_application (const gchar *desktop_id, - const gchar *menu_path) +static AppSection * +add_application (const gchar *desktop_id) { GDesktopAppInfo *appinfo; const gchar *desktop_file; + AppSection *section; appinfo = g_desktop_app_info_new (desktop_id); if (!appinfo) { g_warning ("could not add '%s', there's no desktop file with that id", desktop_id); - return; + return NULL; } desktop_file = g_desktop_app_info_get_filename (appinfo); + section = g_hash_table_lookup (applications, desktop_file); - if (!g_hash_table_lookup (applications, desktop_file)) { - AppSection *section = app_section_new(appinfo); - GMenuItem *item = app_section_create_menu_item (section); + if (!section) { + GMenuItem *item; + section = app_section_new(appinfo); g_hash_table_insert (applications, g_strdup (desktop_file), section); + item = app_section_create_menu_item (section); /* TODO insert it at the right position (alphabetically by application name) */ g_menu_insert_item (menu, 2, item); - g_object_unref (item); } g_object_unref (appinfo); + return section; } /* g_menu_model_find_section: @@ -133,7 +135,7 @@ build_launcher (gpointer data) { gchar *desktop_id = data; - add_application (desktop_id, NULL); + add_application (desktop_id); g_free (desktop_id); return FALSE; @@ -186,22 +188,43 @@ clear_action_handler (MessageServiceDbus *msd, g_simple_action_set_enabled (action, attention); } +static gint +g_strv_find (gchar **str_array, + const gchar *key) +{ + gchar **it; + + g_return_val_if_fail (str_array != NULL, -1); + + for (it = str_array; *it; it++) { + if (!g_strcmp0 (key, *it)) + return it - str_array; + } + + return -1; +} + static void register_application (MessageServiceDbus *msd, + const gchar *sender, const gchar *desktop_id, const gchar *menu_path, gpointer user_data) { - gchar **applications = g_settings_get_strv (settings, "applications"); - gchar **app; + AppSection *section; + gchar **applications; - for (app = applications; *app; app++) { - if (!g_strcmp0 (desktop_id, *app)) - break; - } + section = add_application (desktop_id); + if (!section) + return; - if (*app == NULL) { + app_section_set_object_path (section, bus, sender, menu_path); + + /* remember this application in the settings key */ + applications = g_settings_get_strv (settings, "applications"); + if (g_strv_find (applications, desktop_id) < 0) { GVariantBuilder builder; + gchar **app; g_variant_builder_init (&builder, (GVariantType *)"as"); for (app = applications; *app; app++) @@ -210,8 +233,6 @@ register_application (MessageServiceDbus *msd, g_settings_set_value (settings, "applications", g_variant_builder_end (&builder)); - - add_application (desktop_id, menu_path); } g_strfreev (applications); -- cgit v1.2.3 From 7989e5c7bb1e012d3703716bfd54e20586bd412c Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Sat, 2 Jun 2012 16:50:37 +0200 Subject: Listen to menus exported by applications --- src/app-section.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/app-section.c b/src/app-section.c index 6d00cf1..9a905bc 100644 --- a/src/app-section.c +++ b/src/app-section.c @@ -42,6 +42,8 @@ struct _AppSectionPrivate GMenu *menu; GSimpleActionGroup *static_shortcuts; + + GMenuModel *remote_menu; GActionGroup *actions; guint name_watch_id; @@ -158,12 +160,14 @@ app_section_dispose (GObject *object) g_clear_object (&priv->menu); g_clear_object (&priv->static_shortcuts); - if (priv->actions) { - g_clear_object (&priv->actions); + if (priv->name_watch_id) { g_bus_unwatch_name (priv->name_watch_id); priv->name_watch_id = 0; } + g_clear_object (&priv->actions); + g_clear_object (&priv->remote_menu); + if (priv->ids != NULL) { g_object_unref(priv->ids); priv->ids = NULL; @@ -366,12 +370,14 @@ app_section_set_object_path (AppSection *self, { AppSectionPrivate *priv = APP_SECTION_GET_PRIVATE (self); - if (priv->actions) { - g_clear_object (&priv->actions); + if (priv->remote_menu) g_bus_unwatch_name (priv->name_watch_id); - } + g_clear_object (&priv->actions); + g_clear_object (&priv->remote_menu); priv->actions = G_ACTION_GROUP (g_dbus_action_group_get (bus, bus_name, object_path)); + priv->remote_menu = G_MENU_MODEL (g_dbus_menu_model_get (bus, bus_name, object_path)); + priv->name_watch_id = g_bus_watch_name_on_connection (bus, bus_name, 0, NULL, application_vanished, self, NULL); @@ -390,9 +396,9 @@ app_section_unset_object_path (AppSection *self) { AppSectionPrivate *priv = APP_SECTION_GET_PRIVATE (self); - if (priv->actions) { - g_clear_object (&priv->actions); + if (priv->remote_menu) g_bus_unwatch_name (priv->name_watch_id); - } + g_clear_object (&priv->actions); + g_clear_object (&priv->remote_menu); } -- cgit v1.2.3 From a6d889c175d136cfb1d63a9c04bb2156f210a09e Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Sat, 2 Jun 2012 16:57:35 +0200 Subject: app-section: only call g_bus_unwatch_name if we're watching a name --- src/app-section.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/app-section.c b/src/app-section.c index 9a905bc..6218f37 100644 --- a/src/app-section.c +++ b/src/app-section.c @@ -370,7 +370,7 @@ app_section_set_object_path (AppSection *self, { AppSectionPrivate *priv = APP_SECTION_GET_PRIVATE (self); - if (priv->remote_menu) + if (priv->name_watch_id) g_bus_unwatch_name (priv->name_watch_id); g_clear_object (&priv->actions); g_clear_object (&priv->remote_menu); @@ -396,8 +396,10 @@ app_section_unset_object_path (AppSection *self) { AppSectionPrivate *priv = APP_SECTION_GET_PRIVATE (self); - if (priv->remote_menu) + if (priv->name_watch_id) { g_bus_unwatch_name (priv->name_watch_id); + priv->name_watch_id = 0; + } g_clear_object (&priv->actions); g_clear_object (&priv->remote_menu); } -- cgit v1.2.3 From 6872c840672049695904d61c1a3baba22c6d9627 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Sun, 3 Jun 2012 08:33:31 +0200 Subject: Add GActionMuxer This is a new implementation of an action muxer with the same interface as the one in the gtk tree. Its implementation is considerably simpler, mostly because it doesn't need to implement GActionObservable. In addition to muxing different action groups with the . scheme, it has the notion of global, prefix-less actions. Indicator-messages needs those for the status and clear actions. --- src/Makefile.am | 5 +- src/gactionmuxer.c | 456 +++++++++++++++++++++++++++++++++++++++++++++++++ src/gactionmuxer.h | 44 +++++ src/messages-service.c | 7 +- test/Makefile.am | 6 +- 5 files changed, 513 insertions(+), 5 deletions(-) create mode 100644 src/gactionmuxer.c create mode 100644 src/gactionmuxer.h diff --git a/src/Makefile.am b/src/Makefile.am index 1dbb514..183d729 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -45,9 +45,10 @@ indicator_messages_service_SOURCES = \ app-section.c \ app-section.h \ dbus-data.h \ - \ status-items.c \ - status-items.h + status-items.h \ + gactionmuxer.c \ + gactionmuxer.h indicator_messages_service_CFLAGS = \ $(APPLET_CFLAGS) \ diff --git a/src/gactionmuxer.c b/src/gactionmuxer.c new file mode 100644 index 0000000..cccfeda --- /dev/null +++ b/src/gactionmuxer.c @@ -0,0 +1,456 @@ +/* + * Copyright 2012 Canonical Ltd. + * + * 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 . + * + * Authors: + * Lars Uebernickel + * Ryan Lortie + */ + +#include "gactionmuxer.h" + +#include + +/* + * SECTION:gactionmuxer + * @short_description: Aggregate several action groups + * + * #GActionMuxer is a #GActionGroup that is capable of containing other + * #GActionGroup instances. + * + * The typical use is aggregating all of the actions applicable to a + * particular context into a single action group, with namespacing. + * + * Consider the case of two action groups -- one containing actions + * applicable to an entire application (such as 'quit') and one + * containing actions applicable to a particular window in the + * application (such as 'fullscreen'). + * + * In this case, each of these action groups could be added to a + * #GActionMuxer with the prefixes "app" and "win", respectively. This + * would expose the actions as "app.quit" and "win.fullscreen" on the + * #GActionGroup interface presented by the #GActionMuxer. + * + * Activations and state change requests on the #GActionMuxer are wired + * through to the underlying action group in the expected way. + */ + +typedef GObjectClass GActionMuxerClass; + +struct _GActionMuxer +{ + GObject parent; + GActionGroup *global_actions; + GHashTable *groups; /* prefix -> subgroup */ + GHashTable *reverse; /* subgroup -> prefix */ +}; + + +static void g_action_muxer_group_init (GActionGroupInterface *iface); +static void g_action_muxer_dispose (GObject *object); +static void g_action_muxer_finalize (GObject *object); +static gchar ** g_action_muxer_list_actions (GActionGroup *group); +static void g_action_muxer_activate_action (GActionGroup *group, + const gchar *action_name, + GVariant *parameter); +static void g_action_muxer_change_action_state (GActionGroup *group, + const gchar *action_name, + GVariant *value); +static gboolean g_action_muxer_query_action (GActionGroup *group, + const gchar *action_name, + gboolean *enabled, + const GVariantType **parameter_type, + const GVariantType **state_type, + GVariant **state_hint, + GVariant **state); +static void g_action_muxer_action_added (GActionGroup *group, + gchar *action_name, + gpointer user_data); +static void g_action_muxer_action_removed (GActionGroup *group, + gchar *action_name, + gpointer user_data); +static void g_action_muxer_action_state_changed (GActionGroup *group, + gchar *action_name, + GVariant *value, + gpointer user_data); +static void g_action_muxer_action_enabled_changed (GActionGroup *group, + gchar *action_name, + gboolean enabled, + gpointer user_data); + +G_DEFINE_TYPE_WITH_CODE (GActionMuxer, g_action_muxer, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP, g_action_muxer_group_init)); + + +static void +g_action_muxer_class_init (GObjectClass *klass) +{ + klass->dispose = g_action_muxer_dispose; + klass->finalize = g_action_muxer_finalize; +} + +static void +g_action_muxer_init (GActionMuxer *muxer) +{ + muxer->global_actions = NULL; + muxer->groups = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); + muxer->reverse = g_hash_table_new (g_direct_hash, g_direct_equal); +} + +static void +g_action_muxer_group_init (GActionGroupInterface *iface) +{ + iface->list_actions = g_action_muxer_list_actions; + iface->activate_action = g_action_muxer_activate_action; + iface->change_action_state = g_action_muxer_change_action_state; + iface->query_action = g_action_muxer_query_action; +} + +static void +g_action_muxer_dispose (GObject *object) +{ + GActionMuxer *muxer = G_ACTION_MUXER (object); + GHashTableIter it; + gchar *prefix; + + g_clear_object (&muxer->global_actions); + + g_hash_table_iter_init (&it, muxer->groups); + while (g_hash_table_iter_next (&it, (gpointer *) &prefix, NULL)) + g_action_muxer_remove (muxer, prefix); +} + +static void +g_action_muxer_finalize (GObject *object) +{ + GActionMuxer *muxer = G_ACTION_MUXER (object); + + g_hash_table_unref (muxer->groups); + g_hash_table_unref (muxer->reverse); + + G_OBJECT_CLASS (g_action_muxer_parent_class)->finalize (object); +} + +static GActionGroup * +g_action_muxer_lookup_group (GActionMuxer *muxer, + const gchar *full_name, + const gchar **action_name) +{ + const gchar *sep; + GActionGroup *group; + + sep = strchr (full_name, '.'); + + if (sep) + { + gchar *prefix; + prefix = g_strndup (full_name, sep - full_name); + group = g_hash_table_lookup (muxer->groups, prefix); + g_free (prefix); + if (action_name) + *action_name = sep + 1; + } + else + { + group = muxer->global_actions; + if (action_name) + *action_name = full_name; + } + + return group; +} + +static gchar * +g_action_muxer_lookup_full_name (GActionMuxer *muxer, + GActionGroup *subgroup, + const gchar *action_name) +{ + gpointer prefix; + + if (subgroup == muxer->global_actions) + return g_strdup (action_name); + + if (g_hash_table_lookup_extended (muxer->reverse, subgroup, NULL, &prefix)) + return g_strdup_printf ("%s.%s", (gchar *) prefix, action_name); + + return NULL; +} + +static gchar ** +g_action_muxer_list_actions (GActionGroup *group) +{ + GActionMuxer *muxer = G_ACTION_MUXER (group); + GHashTableIter it; + GArray *all_actions; + gchar *prefix; + GActionGroup *subgroup; + gchar **actions; + gchar **a; + + all_actions = g_array_sized_new (TRUE, FALSE, sizeof (gchar *), 8); + + actions = g_action_group_list_actions (muxer->global_actions); + for (a = actions; *a; a++) + { + gchar *name = g_strdup (*a); + g_array_append_val (all_actions, name); + } + g_strfreev (actions); + + g_hash_table_iter_init (&it, muxer->groups); + while (g_hash_table_iter_next (&it, (gpointer *) &prefix, (gpointer *) &subgroup)) + { + actions = g_action_group_list_actions (subgroup); + for (a = actions; *a; a++) + { + gchar *full_name = g_strdup_printf ("%s.%s", prefix, *a); + g_array_append_val (all_actions, full_name); + } + g_strfreev (actions); + } + + return (gchar **) g_array_free (all_actions, FALSE); +} + +static void +g_action_muxer_activate_action (GActionGroup *group, + const gchar *action_name, + GVariant *parameter) +{ + GActionMuxer *muxer = G_ACTION_MUXER (group); + GActionGroup *subgroup; + const gchar *action; + + subgroup = g_action_muxer_lookup_group (muxer, action_name, &action); + + if (subgroup) + g_action_group_activate_action (subgroup, action, parameter); +} + +static void +g_action_muxer_change_action_state (GActionGroup *group, + const gchar *action_name, + GVariant *value) +{ + GActionMuxer *muxer = G_ACTION_MUXER (group); + GActionGroup *subgroup; + const gchar *action; + + subgroup = g_action_muxer_lookup_group (muxer, action_name, &action); + + if (subgroup) + g_action_group_change_action_state (subgroup, action, value); +} + +static gboolean +g_action_muxer_query_action (GActionGroup *group, + const gchar *action_name, + gboolean *enabled, + const GVariantType **parameter_type, + const GVariantType **state_type, + GVariant **state_hint, + GVariant **state) +{ + GActionMuxer *muxer = G_ACTION_MUXER (group); + GActionGroup *subgroup; + const gchar *action; + + subgroup = g_action_muxer_lookup_group (muxer, action_name, &action); + + if (!subgroup) + return FALSE; + + return g_action_group_query_action (subgroup, action, enabled, parameter_type, + state_type, state_hint, state); +} + +static void +g_action_muxer_action_added (GActionGroup *group, + gchar *action_name, + gpointer user_data) +{ + GActionMuxer *muxer = user_data; + gchar *full_name; + + full_name = g_action_muxer_lookup_full_name (muxer, group, action_name); + + if (full_name) + { + g_action_group_action_added (G_ACTION_GROUP (muxer), full_name); + g_free (full_name); + } +} + +static void +g_action_muxer_action_removed (GActionGroup *group, + gchar *action_name, + gpointer user_data) +{ + GActionMuxer *muxer = user_data; + gchar *full_name; + + full_name = g_action_muxer_lookup_full_name (muxer, group, action_name); + + if (full_name) + { + g_action_group_action_removed (G_ACTION_GROUP (muxer), full_name); + g_free (full_name); + } +} + +static void +g_action_muxer_action_state_changed (GActionGroup *group, + gchar *action_name, + GVariant *value, + gpointer user_data) +{ + GActionMuxer *muxer = user_data; + gchar *full_name; + + full_name = g_action_muxer_lookup_full_name (muxer, group, action_name); + + if (full_name) + { + g_action_group_action_state_changed (G_ACTION_GROUP (muxer), full_name, value); + g_free (full_name); + } +} + +static void +g_action_muxer_action_enabled_changed (GActionGroup *group, + gchar *action_name, + gboolean enabled, + gpointer user_data) +{ + GActionMuxer *muxer = user_data; + gchar *full_name; + + full_name = g_action_muxer_lookup_full_name (muxer, group, action_name); + + if (full_name) + { + g_action_group_action_enabled_changed (G_ACTION_GROUP (muxer), full_name, enabled); + g_free (full_name); + } +} + +/* + * g_action_muxer_new: + * + * Creates a new #GActionMuxer. + */ +GActionMuxer * +g_action_muxer_new (void) +{ + return g_object_new (G_TYPE_ACTION_MUXER, NULL); +} + +/* + * g_action_muxer_insert: + * @muxer: a #GActionMuxer + * @prefix: (allow-none): the prefix string for the action group, or NULL + * @group: a #GActionGroup + * + * Adds the actions in @group to the list of actions provided by @muxer. + * @prefix is prefixed to each action name, such that for each action + * x in @group, there is an equivalent action + * @prefix.x in @muxer. + * + * For example, if @prefix is "app" and @group contains an + * action called "quit", then @muxer will now contain an + * action called "app.quit". + * + * If @prefix is NULL, the actions in @group will be added + * to @muxer without prefix. + * + * There may only be one group per prefix (including the + * NULL-prefix). If a group has been added with @prefix in + * a previous call to this function, it will be removed. + * + * @prefix must not contain a dot ('.'). + */ +void +g_action_muxer_insert (GActionMuxer *muxer, + const gchar *prefix, + GActionGroup *group) +{ + gchar *prefix_copy; + gchar **actions; + gchar **action; + + g_return_if_fail (G_IS_ACTION_MUXER (muxer)); + g_return_if_fail (G_IS_ACTION_GROUP (group)); + + g_action_muxer_remove (muxer, prefix); + + if (prefix) + { + prefix_copy = g_strdup (prefix); + g_hash_table_insert (muxer->groups, prefix_copy, g_object_ref (group)); + g_hash_table_insert (muxer->reverse, group, prefix_copy); + } + else + muxer->global_actions = g_object_ref (group); + + actions = g_action_group_list_actions (group); + for (action = actions; *action; action++) + g_action_muxer_action_added (group, *action, muxer); + g_strfreev (actions); + + g_signal_connect (group, "action-added", G_CALLBACK (g_action_muxer_action_added), muxer); + g_signal_connect (group, "action-removed", G_CALLBACK (g_action_muxer_action_removed), muxer); + g_signal_connect (group, "action-enabled-changed", G_CALLBACK (g_action_muxer_action_enabled_changed), muxer); + g_signal_connect (group, "action-state-changed", G_CALLBACK (g_action_muxer_action_state_changed), muxer); +} + +/* + * g_action_muxer_remove: + * @muxer: a #GActionMuxer + * @prefix: (allow-none): the prefix of the action group to remove, or NULL + * + * Removes a #GActionGroup from the #GActionMuxer. + */ +void +g_action_muxer_remove (GActionMuxer *muxer, + const gchar *prefix) +{ + GActionGroup *subgroup; + gchar **actions; + gchar **action; + + g_return_if_fail (G_IS_ACTION_MUXER (muxer)); + + subgroup = prefix ? g_hash_table_lookup (muxer->groups, prefix) : muxer->global_actions; + if (!subgroup) + return; + + actions = g_action_group_list_actions (subgroup); + for (action = actions; *action; action++) + g_action_muxer_action_removed (subgroup, *action, muxer); + g_strfreev (actions); + + g_signal_handlers_disconnect_by_func (subgroup, g_action_muxer_action_added, muxer); + g_signal_handlers_disconnect_by_func (subgroup, g_action_muxer_action_removed, muxer); + g_signal_handlers_disconnect_by_func (subgroup, g_action_muxer_action_enabled_changed, muxer); + g_signal_handlers_disconnect_by_func (subgroup, g_action_muxer_action_state_changed, muxer); + + if (prefix) + { + g_hash_table_remove (muxer->groups, prefix); + g_hash_table_remove (muxer->reverse, subgroup); + } + else + g_clear_object (&muxer->global_actions); +} + diff --git a/src/gactionmuxer.h b/src/gactionmuxer.h new file mode 100644 index 0000000..5c5e839 --- /dev/null +++ b/src/gactionmuxer.h @@ -0,0 +1,44 @@ +/* + * Copyright 2012 Canonical Ltd. + * + * 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 . + * + * Authors: + * Lars Uebernickel + * Ryan Lortie + */ + +#ifndef __G_ACTION_MUXER_H__ +#define __G_ACTION_MUXER_H__ + +#include + +#define G_TYPE_ACTION_MUXER (g_action_muxer_get_type ()) +#define G_ACTION_MUXER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_ACTION_MUXER, GActionMuxer)) +#define G_IS_ACTION_MUXER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_ACTION_MUXER)) + +typedef struct _GActionMuxer GActionMuxer; + +GType g_action_muxer_get_type (void) G_GNUC_CONST; + +GActionMuxer * g_action_muxer_new (void); + +void g_action_muxer_insert (GActionMuxer *muxer, + const gchar *prefix, + GActionGroup *group); + +void g_action_muxer_remove (GActionMuxer *muxer, + const gchar *prefix); + +#endif + diff --git a/src/messages-service.c b/src/messages-service.c index 28a64a0..c1069b8 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -34,12 +34,14 @@ with this program. If not, see . #include "dbus-data.h" #include "messages-service-dbus.h" #include "status-items.h" +#include "gactionmuxer.h" static IndicatorService * service = NULL; static GHashTable *applications; static GDBusConnection *bus; static GSimpleActionGroup *actions; +static GActionMuxer *action_muxer; static GMenu *menu; static GSettings *settings; static GMainLoop * mainloop = NULL; @@ -296,8 +298,11 @@ main (int argc, char ** argv) actions = g_simple_action_group_new (); g_simple_action_group_add_entries (actions, entries, G_N_ELEMENTS (entries), NULL); + + action_muxer = g_action_muxer_new (); + g_action_muxer_insert (action_muxer, NULL, G_ACTION_GROUP (actions)); g_dbus_connection_export_action_group (bus, INDICATOR_MESSAGES_DBUS_OBJECT, - G_ACTION_GROUP (actions), &error); + G_ACTION_GROUP (action_muxer), &error); if (error) { g_warning ("unable to export action group on dbus: %s", error->message); g_error_free (error); diff --git a/test/Makefile.am b/test/Makefile.am index 2b0f67e..977c1ed 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -42,14 +42,16 @@ libindicator_messages_service_la_HEADERS = \ $(top_srcdir)/src/gen-messages-service.xml.h \ $(top_srcdir)/src/app-section.h \ $(top_srcdir)/src/dbus-data.h \ - $(top_srcdir)/src/status-items.h + $(top_srcdir)/src/status-items.h \ + $(top_srcdir)/src/gactionmuxer.h libindicator_messages_service_la_SOURCES = \ $(top_srcdir)/src/messages-service.c \ $(top_srcdir)/src/messages-service-dbus.c \ $(top_srcdir)/src/gen-messages-service.xml.c \ $(top_srcdir)/src/app-section.c \ - $(top_srcdir)/src/status-items.c + $(top_srcdir)/src/status-items.c \ + $(top_srcdir)/src/gactionmuxer.c libindicator_messages_service_ladir = \ $(includedir)/libindicator-messages-service/ -- cgit v1.2.3 From 76b172f49929b8feb1375df830042f6d47121f67 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Sun, 3 Jun 2012 09:00:10 +0200 Subject: Use ids instead of .desktop file names to identify applications --- src/messages-service.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/src/messages-service.c b/src/messages-service.c index c1069b8..ec12cbe 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -49,11 +49,26 @@ static GMainLoop * mainloop = NULL; static MessageServiceDbus * dbus_interface = NULL; +static gchar * +g_app_info_get_simple_id (GAppInfo *appinfo) +{ + const gchar *id; + + id = g_app_info_get_id (appinfo); + if (!id) + return NULL; + + if (g_str_has_suffix (id, ".desktop")) + return g_strndup (id, strlen (id) - 8); + else + return g_strdup (id); +} + static AppSection * add_application (const gchar *desktop_id) { GDesktopAppInfo *appinfo; - const gchar *desktop_file; + gchar *id; AppSection *section; appinfo = g_desktop_app_info_new (desktop_id); @@ -62,14 +77,14 @@ add_application (const gchar *desktop_id) return NULL; } - desktop_file = g_desktop_app_info_get_filename (appinfo); - section = g_hash_table_lookup (applications, desktop_file); + id = g_app_info_get_simple_id (G_APP_INFO (appinfo)); + section = g_hash_table_lookup (applications, id); if (!section) { GMenuItem *item; section = app_section_new(appinfo); - g_hash_table_insert (applications, g_strdup (desktop_file), section); + g_hash_table_insert (applications, g_strdup (id), section); item = app_section_create_menu_item (section); /* TODO insert it at the right position (alphabetically by application name) */ @@ -77,6 +92,7 @@ add_application (const gchar *desktop_id) g_object_unref (item); } + g_free (id); g_object_unref (appinfo); return section; } @@ -105,7 +121,7 @@ static void remove_application (const char *desktop_id) { GDesktopAppInfo *appinfo; - const gchar *desktop_file; + gchar *id; AppSection *section; appinfo = g_desktop_app_info_new (desktop_id); @@ -114,9 +130,9 @@ remove_application (const char *desktop_id) return; } - desktop_file = g_desktop_app_info_get_filename (appinfo); + id = g_app_info_get_simple_id (G_APP_INFO (appinfo)); - section = g_hash_table_lookup (applications, desktop_file); + section = g_hash_table_lookup (applications, id); if (section) { int pos = g_menu_find_section (menu, app_section_get_menu (section)); if (pos >= 0) @@ -126,7 +142,8 @@ remove_application (const char *desktop_id) g_warning ("could not remove '%s', it's not registered", desktop_id); } - g_hash_table_remove (applications, desktop_file); + g_hash_table_remove (applications, id); + g_free (id); g_object_unref (appinfo); } -- cgit v1.2.3 From 98538a540ba7a741a68b4cff6d3e192a43d61077 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Sun, 3 Jun 2012 12:59:43 +0200 Subject: Reexport application actions --- src/app-section.c | 21 +++++++++++++++++++++ src/app-section.h | 1 + src/messages-service.c | 21 +++++++++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/src/app-section.c b/src/app-section.c index 6218f37..f23f412 100644 --- a/src/app-section.c +++ b/src/app-section.c @@ -54,6 +54,7 @@ struct _AppSectionPrivate enum { PROP_0, PROP_APPINFO, + PROP_ACTIONS, NUM_PROPERTIES }; @@ -97,6 +98,12 @@ app_section_class_init (AppSectionClass *klass) G_TYPE_APP_INFO, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + properties[PROP_ACTIONS] = g_param_spec_object ("actions", + "Actions", + "The actions exported by this application", + G_TYPE_ACTION_GROUP, + G_PARAM_READABLE); + g_object_class_install_properties (object_class, NUM_PROPERTIES, properties); } @@ -247,6 +254,9 @@ app_section_set_app_info (AppSection *self, g_free(name); } + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_APPINFO]); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACTIONS]); + g_free(label); g_object_unref (launch); } @@ -306,6 +316,13 @@ app_section_get_desktop (AppSection * self) return NULL; } +GActionGroup * +app_section_get_actions (AppSection *self) +{ + AppSectionPrivate * priv = APP_SECTION_GET_PRIVATE(self); + return priv->actions ? priv->actions : G_ACTION_GROUP (priv->static_shortcuts); +} + GMenuModel * app_section_get_menu (AppSection *self) { @@ -381,6 +398,8 @@ app_section_set_object_path (AppSection *self, priv->name_watch_id = g_bus_watch_name_on_connection (bus, bus_name, 0, NULL, application_vanished, self, NULL); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACTIONS]); } /* @@ -402,5 +421,7 @@ app_section_unset_object_path (AppSection *self) } g_clear_object (&priv->actions); g_clear_object (&priv->remote_menu); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACTIONS]); } diff --git a/src/app-section.h b/src/app-section.h index aa6ef75..24074b8 100644 --- a/src/app-section.h +++ b/src/app-section.h @@ -49,6 +49,7 @@ AppSection * app_section_new (GDesktopAppInfo *appinfo); guint app_section_get_count (AppSection * appitem); const gchar * app_section_get_name (AppSection * appitem); const gchar * app_section_get_desktop (AppSection * appitem); +GActionGroup * app_section_get_actions (AppSection *self); GMenuModel * app_section_get_menu (AppSection *appitem); GAppInfo * app_section_get_app_info (AppSection *appitem); GMenuItem * app_section_create_menu_item (AppSection *self); diff --git a/src/messages-service.c b/src/messages-service.c index ec12cbe..e302219 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -64,6 +64,22 @@ g_app_info_get_simple_id (GAppInfo *appinfo) return g_strdup (id); } +static void +actions_changed (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + AppSection *section = APP_SECTION (object); + gchar *id; + GActionGroup *actions; + + id = g_app_info_get_simple_id (app_section_get_app_info (section)); + actions = app_section_get_actions (section); + + g_action_muxer_insert (action_muxer, id, actions); + g_free (id); +} + static AppSection * add_application (const gchar *desktop_id) { @@ -86,6 +102,10 @@ add_application (const gchar *desktop_id) section = app_section_new(appinfo); g_hash_table_insert (applications, g_strdup (id), section); + g_action_muxer_insert (action_muxer, id, app_section_get_actions (section)); + g_signal_connect (section, "notify::actions", + G_CALLBACK (actions_changed), NULL); + item = app_section_create_menu_item (section); /* TODO insert it at the right position (alphabetically by application name) */ g_menu_insert_item (menu, 2, item); @@ -137,6 +157,7 @@ remove_application (const char *desktop_id) int pos = g_menu_find_section (menu, app_section_get_menu (section)); if (pos >= 0) g_menu_remove (menu, pos); + g_action_muxer_remove (action_muxer, id); } else { g_warning ("could not remove '%s', it's not registered", desktop_id); -- cgit v1.2.3 From 1a21c582c91dfa1df8bcb8e2f822b2ad025c64f5 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Sun, 3 Jun 2012 13:03:29 +0200 Subject: gactionmuxer: allow passing a NULL action group to insert() --- src/gactionmuxer.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/gactionmuxer.c b/src/gactionmuxer.c index cccfeda..e2cee3f 100644 --- a/src/gactionmuxer.c +++ b/src/gactionmuxer.c @@ -360,7 +360,7 @@ g_action_muxer_new (void) * g_action_muxer_insert: * @muxer: a #GActionMuxer * @prefix: (allow-none): the prefix string for the action group, or NULL - * @group: a #GActionGroup + * @group: (allow-none): a #GActionGroup, or NULL * * Adds the actions in @group to the list of actions provided by @muxer. * @prefix is prefixed to each action name, such that for each action @@ -374,6 +374,9 @@ g_action_muxer_new (void) * If @prefix is NULL, the actions in @group will be added * to @muxer without prefix. * + * If @group is NULL, this function has the same effect as + * calling g_action_muxer_remove() with @prefix. + * * There may only be one group per prefix (including the * NULL-prefix). If a group has been added with @prefix in * a previous call to this function, it will be removed. @@ -394,6 +397,9 @@ g_action_muxer_insert (GActionMuxer *muxer, g_action_muxer_remove (muxer, prefix); + if (!group) + return; + if (prefix) { prefix_copy = g_strdup (prefix); -- cgit v1.2.3 From 806686a1635bcd72c6e509a85ce8af9246ea551c Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Sun, 3 Jun 2012 13:07:09 +0200 Subject: Name actions after the shortcut nick instead of its label --- src/app-section.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app-section.c b/src/app-section.c index f23f412..340bbd7 100644 --- a/src/app-section.c +++ b/src/app-section.c @@ -243,11 +243,11 @@ app_section_set_app_info (AppSection *self, name = indicator_desktop_shortcuts_nick_get_name(priv->ids, nicks[i]); - action = g_simple_action_new (name, NULL); + action = g_simple_action_new (nicks[i], NULL); g_signal_connect(action, "activate", G_CALLBACK (nick_activate_cb), self); g_simple_action_group_insert (priv->static_shortcuts, G_ACTION (action)); - item = g_menu_item_new (name, name); + item = g_menu_item_new (name, nicks[i]); g_menu_append_item (priv->menu, item); g_object_unref (item); -- cgit v1.2.3 From 7eae3f378e7d1b3bf4cc291649dfb35b8e2b93eb Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 4 Jun 2012 11:06:31 +0200 Subject: app-section: replace G_TYPE_INSTANCE_GET_PRIVATE calls with a priv member --- src/app-section.c | 37 +++++++++++++++++++------------------ src/app-section.h | 7 +++++-- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/app-section.c b/src/app-section.c index 340bbd7..61d4db3 100644 --- a/src/app-section.c +++ b/src/app-section.c @@ -31,8 +31,6 @@ with this program. If not, see . #include "app-section.h" #include "dbus-data.h" -typedef struct _AppSectionPrivate AppSectionPrivate; - struct _AppSectionPrivate { GDesktopAppInfo * appinfo; @@ -49,8 +47,6 @@ struct _AppSectionPrivate guint name_watch_id; }; -#define APP_SECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), APP_SECTION_TYPE, AppSectionPrivate)) - enum { PROP_0, PROP_APPINFO, @@ -110,7 +106,12 @@ app_section_class_init (AppSectionClass *klass) static void app_section_init (AppSection *self) { - AppSectionPrivate * priv = APP_SECTION_GET_PRIVATE(self); + AppSectionPrivate *priv; + + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + APP_SECTION_TYPE, + AppSectionPrivate); + priv = self->priv; priv->appinfo = NULL; priv->unreadcount = 0; @@ -162,7 +163,7 @@ static void app_section_dispose (GObject *object) { AppSection * self = APP_SECTION(object); - AppSectionPrivate * priv = APP_SECTION_GET_PRIVATE(self); + AppSectionPrivate * priv = self->priv; g_clear_object (&priv->menu); g_clear_object (&priv->static_shortcuts); @@ -196,7 +197,7 @@ nick_activate_cb (GSimpleAction *action, { const gchar * nick = g_action_get_name (G_ACTION (action)); AppSection * mi = APP_SECTION (userdata); - AppSectionPrivate * priv = APP_SECTION_GET_PRIVATE(mi); + AppSectionPrivate * priv = mi->priv; g_return_if_fail(priv->ids != NULL); @@ -210,7 +211,7 @@ static void app_section_set_app_info (AppSection *self, GDesktopAppInfo *appinfo) { - AppSectionPrivate *priv = APP_SECTION_GET_PRIVATE (self); + AppSectionPrivate *priv = self->priv; GSimpleAction *launch; gchar *label; @@ -275,7 +276,7 @@ activate_cb (GSimpleAction *action, gpointer userdata) { AppSection * mi = APP_SECTION (userdata); - AppSectionPrivate * priv = APP_SECTION_GET_PRIVATE(mi); + AppSectionPrivate * priv = mi->priv; GError *error = NULL; if (!g_app_info_launch (G_APP_INFO (priv->appinfo), NULL, NULL, &error)) { @@ -288,7 +289,7 @@ guint app_section_get_count (AppSection * self) { g_return_val_if_fail(IS_APP_SECTION(self), 0); - AppSectionPrivate * priv = APP_SECTION_GET_PRIVATE(self); + AppSectionPrivate * priv = self->priv; return priv->unreadcount; } @@ -297,7 +298,7 @@ const gchar * app_section_get_name (AppSection * self) { g_return_val_if_fail(IS_APP_SECTION(self), NULL); - AppSectionPrivate * priv = APP_SECTION_GET_PRIVATE(self); + AppSectionPrivate * priv = self->priv; if (priv->appinfo) { return g_app_info_get_name(G_APP_INFO(priv->appinfo)); @@ -309,7 +310,7 @@ const gchar * app_section_get_desktop (AppSection * self) { g_return_val_if_fail(IS_APP_SECTION(self), NULL); - AppSectionPrivate * priv = APP_SECTION_GET_PRIVATE(self); + AppSectionPrivate * priv = self->priv; if (priv->appinfo) return g_desktop_app_info_get_filename (priv->appinfo); else @@ -319,28 +320,28 @@ app_section_get_desktop (AppSection * self) GActionGroup * app_section_get_actions (AppSection *self) { - AppSectionPrivate * priv = APP_SECTION_GET_PRIVATE(self); + AppSectionPrivate * priv = self->priv; return priv->actions ? priv->actions : G_ACTION_GROUP (priv->static_shortcuts); } GMenuModel * app_section_get_menu (AppSection *self) { - AppSectionPrivate * priv = APP_SECTION_GET_PRIVATE(self); + AppSectionPrivate * priv = self->priv; return G_MENU_MODEL (priv->menu); } GAppInfo * app_section_get_app_info (AppSection *self) { - AppSectionPrivate * priv = APP_SECTION_GET_PRIVATE(self); + AppSectionPrivate * priv = self->priv; return G_APP_INFO (priv->appinfo); } GMenuItem * app_section_create_menu_item (AppSection *self) { - AppSectionPrivate *priv = APP_SECTION_GET_PRIVATE (self); + AppSectionPrivate *priv = self->priv; GMenuItem *item; const gchar *name; gchar *iconstr; @@ -385,7 +386,7 @@ app_section_set_object_path (AppSection *self, const gchar *bus_name, const gchar *object_path) { - AppSectionPrivate *priv = APP_SECTION_GET_PRIVATE (self); + AppSectionPrivate *priv = self->priv; if (priv->name_watch_id) g_bus_unwatch_name (priv->name_watch_id); @@ -413,7 +414,7 @@ app_section_set_object_path (AppSection *self, void app_section_unset_object_path (AppSection *self) { - AppSectionPrivate *priv = APP_SECTION_GET_PRIVATE (self); + AppSectionPrivate *priv = self->priv; if (priv->name_watch_id) { g_bus_unwatch_name (priv->name_watch_id); diff --git a/src/app-section.h b/src/app-section.h index 24074b8..1ef191a 100644 --- a/src/app-section.h +++ b/src/app-section.h @@ -33,8 +33,10 @@ G_BEGIN_DECLS #define IS_APP_SECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), APP_SECTION_TYPE)) #define APP_SECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), APP_SECTION_TYPE, AppSectionClass)) -typedef struct _AppSection AppSection; -typedef struct _AppSectionClass AppSectionClass; +typedef struct _AppSection AppSection; +typedef struct _AppSectionClass AppSectionClass; +typedef struct _AppSectionPrivate AppSectionPrivate; + struct _AppSectionClass { GObjectClass parent_class; @@ -42,6 +44,7 @@ struct _AppSectionClass { struct _AppSection { GObject parent; + AppSectionPrivate *priv; }; GType app_section_get_type (void); -- cgit v1.2.3 From cd8e4e8d16d67c6601a0536fc2554bc45c10728e Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 4 Jun 2012 11:56:15 +0200 Subject: Reexport application menu as a separate section below the shortcuts --- src/app-section.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/app-section.c b/src/app-section.c index 61d4db3..b59bfc1 100644 --- a/src/app-section.c +++ b/src/app-section.c @@ -391,11 +391,17 @@ app_section_set_object_path (AppSection *self, if (priv->name_watch_id) g_bus_unwatch_name (priv->name_watch_id); g_clear_object (&priv->actions); - g_clear_object (&priv->remote_menu); + + if (priv->remote_menu) { + g_menu_remove (priv->menu, 0); + g_clear_object (&priv->remote_menu); + } priv->actions = G_ACTION_GROUP (g_dbus_action_group_get (bus, bus_name, object_path)); priv->remote_menu = G_MENU_MODEL (g_dbus_menu_model_get (bus, bus_name, object_path)); + g_menu_append_section (priv->menu, NULL, priv->remote_menu); + priv->name_watch_id = g_bus_watch_name_on_connection (bus, bus_name, 0, NULL, application_vanished, self, NULL); @@ -421,7 +427,11 @@ app_section_unset_object_path (AppSection *self) priv->name_watch_id = 0; } g_clear_object (&priv->actions); - g_clear_object (&priv->remote_menu); + + if (priv->remote_menu) { + g_menu_remove (priv->menu, 0); + g_clear_object (&priv->remote_menu); + } g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACTIONS]); } -- cgit v1.2.3 From 0a82aeba13c568e75b187b7f64d9c8327a246b4b Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 4 Jun 2012 12:16:33 +0200 Subject: POTFILES.in: remove old file --- po/POTFILES.in | 1 - 1 file changed, 1 deletion(-) diff --git a/po/POTFILES.in b/po/POTFILES.in index 2d93682..39d3ce7 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -2,5 +2,4 @@ src/messages-service-dbus.c src/indicator-messages.c src/messages-service.c -src/default-applications.c src/status-items.c -- cgit v1.2.3 From 3eb45ac840a66511537cdf2bd2c9f7c68c6e1761 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 4 Jun 2012 12:23:51 +0200 Subject: Include different header in test case to fix `make check` --- src/app-section.h | 1 + test/test-gtest.cpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/app-section.h b/src/app-section.h index 1ef191a..a81b4df 100644 --- a/src/app-section.h +++ b/src/app-section.h @@ -23,6 +23,7 @@ with this program. If not, see . #define __APP_SECTION_H__ #include +#include G_BEGIN_DECLS diff --git a/test/test-gtest.cpp b/test/test-gtest.cpp index 1cc97be..fd9fec1 100644 --- a/test/test-gtest.cpp +++ b/test/test-gtest.cpp @@ -3,10 +3,10 @@ #include extern "C" { - #include "launcher-menu-item.h" + #include "app-section.h" } -TEST(LauncherMenuItem, NameInitialized) { +TEST(AppSection, NameInitialized) { g_type_init(); EXPECT_TRUE(true); } -- cgit v1.2.3 From 7d4fcf06c92e71fa0abb1927ac21705ab88478c0 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 4 Jun 2012 18:13:24 +0200 Subject: Add a first gactionmuxer test --- test/Makefile.am | 13 +++++++- test/test-gactionmuxer.cpp | 76 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 test/test-gactionmuxer.cpp diff --git a/test/Makefile.am b/test/Makefile.am index 977c1ed..f1ab408 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,6 +1,6 @@ check_LIBRARIES = libgtest.a -check_PROGRAMS = test-gtest +check_PROGRAMS = test-gtest test-gactionmuxer TESTS = @@ -31,6 +31,17 @@ test_gtest_LDADD = \ libgtest.a +TESTS += test-gactionmuxer + +test_gactionmuxer_SOURCES = \ + test-gactionmuxer.cpp \ + $(top_srcdir)/src/gactionmuxer.c \ + $(top_srcdir)/src/gactionmuxer.h + +test_gactionmuxer_CPPFLAGS = $(APPLET_CFLAGS) $(AM_CPPFLAGS) +test_gactionmuxer_LDADD = $(APPLET_LIBS) libgtest.a + + ###################################### # Lib containing code under test ###################################### diff --git a/test/test-gactionmuxer.cpp b/test/test-gactionmuxer.cpp new file mode 100644 index 0000000..fb32452 --- /dev/null +++ b/test/test-gactionmuxer.cpp @@ -0,0 +1,76 @@ + +#include +#include +#include + +extern "C" { +#include "app-section.h" +#include "gactionmuxer.h" +} + +static gboolean +strv_contains (gchar **str_array, + const gchar *str) +{ + gchar **it; + + for (it = str_array; *it; it++) { + if (!g_strcmp0 (*it, str)) + return TRUE; + } + + return FALSE; +} + +TEST(GActionMuxerTest, General) { + const GActionEntry entries1[] = { { "one" }, { "two" }, { "three" } }; + const GActionEntry entries2[] = { { "gb" }, { "es" }, { "fr" } }; + const GActionEntry entries3[] = { { "foo" }, { "bar" } }; + GSimpleActionGroup *group1; + GSimpleActionGroup *group2; + GSimpleActionGroup *group3; + GActionMuxer *muxer; + gchar **actions; + + g_type_init (); + + group1 = g_simple_action_group_new (); + g_simple_action_group_add_entries (group1, + entries1, + G_N_ELEMENTS (entries1), + NULL); + + group2 = g_simple_action_group_new (); + g_simple_action_group_add_entries (group2, + entries2, + G_N_ELEMENTS (entries2), + NULL); + + group3 = g_simple_action_group_new (); + g_simple_action_group_add_entries (group3, + entries3, + G_N_ELEMENTS (entries3), + NULL); + + muxer = g_action_muxer_new (); + g_action_muxer_insert (muxer, "first", G_ACTION_GROUP (group1)); + g_action_muxer_insert (muxer, "second", G_ACTION_GROUP (group2)); + g_action_muxer_insert (muxer, NULL, G_ACTION_GROUP (group3)); + + actions = g_action_group_list_actions (G_ACTION_GROUP (muxer)); + EXPECT_EQ (8, g_strv_length (actions)); + EXPECT_TRUE (strv_contains (actions, "first.one")); + EXPECT_TRUE (strv_contains (actions, "first.two")); + EXPECT_TRUE (strv_contains (actions, "first.three")); + EXPECT_TRUE (strv_contains (actions, "second.gb")); + EXPECT_TRUE (strv_contains (actions, "second.es")); + EXPECT_TRUE (strv_contains (actions, "second.fr")); + EXPECT_TRUE (strv_contains (actions, "foo")); + EXPECT_TRUE (strv_contains (actions, "bar")); + g_strfreev (actions); + + g_object_unref (muxer); + g_object_unref (group1); + g_object_unref (group2); + g_object_unref (group3); +} -- cgit v1.2.3 From 6ee454ecc225d186195206465254133473bfd749 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 4 Jun 2012 18:15:46 +0200 Subject: Remove dummy test case --- test/Makefile.am | 16 +--------------- test/test-gtest.cpp | 12 ------------ 2 files changed, 1 insertion(+), 27 deletions(-) delete mode 100644 test/test-gtest.cpp diff --git a/test/Makefile.am b/test/Makefile.am index f1ab408..6ceb1d4 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,6 +1,6 @@ check_LIBRARIES = libgtest.a -check_PROGRAMS = test-gtest test-gactionmuxer +check_PROGRAMS = test-gactionmuxer TESTS = @@ -17,20 +17,6 @@ libgtest_a_CXXFLAGS = \ libgtest_a_CPPFLAGS = \ $(AM_CPPFLAGS) -TESTS += test-gtest - -test_gtest_SOURCES = \ - test-gtest.cpp -test_gtest_CPPFLAGS = \ - $(APPLET_CFLAGS) \ - $(AM_CPPFLAGS) -test_gtest_LDFLAGS = -pthread -test_gtest_LDADD = \ - $(APPLET_LIBS) \ - $(top_builddir)/src/.libs/libindicator-messages-status-provider.la \ - libgtest.a - - TESTS += test-gactionmuxer test_gactionmuxer_SOURCES = \ diff --git a/test/test-gtest.cpp b/test/test-gtest.cpp deleted file mode 100644 index fd9fec1..0000000 --- a/test/test-gtest.cpp +++ /dev/null @@ -1,12 +0,0 @@ - -#include -#include - -extern "C" { - #include "app-section.h" -} - -TEST(AppSection, NameInitialized) { - g_type_init(); - EXPECT_TRUE(true); -} -- cgit v1.2.3 From 2fee65e88f9a5de775df5fe99fe8a9a160bbbdf8 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 4 Jun 2012 18:21:11 +0200 Subject: test: remove warnings in Makefile.am (duplicate vars) --- test/Makefile.am | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/test/Makefile.am b/test/Makefile.am index 6ceb1d4..a790ba2 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -2,7 +2,7 @@ check_LIBRARIES = libgtest.a check_PROGRAMS = test-gactionmuxer -TESTS = +TESTS = $(check_PROGRAMS) AM_CPPFLAGS = $(GTEST_CPPFLAGS) \ -I${top_srcdir}/src @@ -11,13 +11,11 @@ nodist_libgtest_a_SOURCES = \ $(GTEST_SOURCE)/src/gtest-all.cc \ $(GTEST_SOURCE)/src/gtest_main.cc libgtest_a_CPPFLAGS = \ - $(GTEST_CPPFLAGS) -w + $(GTEST_CPPFLAGS) -w \ + $(AM_CPPFLAGS) libgtest_a_CXXFLAGS = \ $(AM_CXXFLAGS) -libgtest_a_CPPFLAGS = \ - $(AM_CPPFLAGS) -TESTS += test-gactionmuxer test_gactionmuxer_SOURCES = \ test-gactionmuxer.cpp \ -- cgit v1.2.3 From fab2ebfc84ded877f392369d8643634b0e5446f8 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 4 Jun 2012 18:46:08 +0200 Subject: gactiongroup: don't remove items from the hash while iterating over it --- src/gactionmuxer.c | 47 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/src/gactionmuxer.c b/src/gactionmuxer.c index e2cee3f..6c4d08b 100644 --- a/src/gactionmuxer.c +++ b/src/gactionmuxer.c @@ -60,6 +60,8 @@ struct _GActionMuxer static void g_action_muxer_group_init (GActionGroupInterface *iface); static void g_action_muxer_dispose (GObject *object); static void g_action_muxer_finalize (GObject *object); +static void g_action_muxer_disconnect_group (GActionMuxer *muxer, + GActionGroup *subgroup); static gchar ** g_action_muxer_list_actions (GActionGroup *group); static void g_action_muxer_activate_action (GActionGroup *group, const gchar *action_name, @@ -122,13 +124,20 @@ g_action_muxer_dispose (GObject *object) { GActionMuxer *muxer = G_ACTION_MUXER (object); GHashTableIter it; - gchar *prefix; + GActionGroup *subgroup; - g_clear_object (&muxer->global_actions); + if (muxer->global_actions) + { + g_action_muxer_disconnect_group (muxer, muxer->global_actions); + g_clear_object (&muxer->global_actions); + } g_hash_table_iter_init (&it, muxer->groups); - while (g_hash_table_iter_next (&it, (gpointer *) &prefix, NULL)) - g_action_muxer_remove (muxer, prefix); + while (g_hash_table_iter_next (&it, NULL, (gpointer *) &subgroup)) + g_action_muxer_disconnect_group (muxer, subgroup); + + g_hash_table_remove_all (muxer->groups); + g_hash_table_remove_all (muxer->reverse); } static void @@ -187,6 +196,24 @@ g_action_muxer_lookup_full_name (GActionMuxer *muxer, return NULL; } +static void +g_action_muxer_disconnect_group (GActionMuxer *muxer, + GActionGroup *subgroup) +{ + gchar **actions; + gchar **action; + + actions = g_action_group_list_actions (subgroup); + for (action = actions; *action; action++) + g_action_muxer_action_removed (subgroup, *action, muxer); + g_strfreev (actions); + + g_signal_handlers_disconnect_by_func (subgroup, g_action_muxer_action_added, muxer); + g_signal_handlers_disconnect_by_func (subgroup, g_action_muxer_action_removed, muxer); + g_signal_handlers_disconnect_by_func (subgroup, g_action_muxer_action_enabled_changed, muxer); + g_signal_handlers_disconnect_by_func (subgroup, g_action_muxer_action_state_changed, muxer); +} + static gchar ** g_action_muxer_list_actions (GActionGroup *group) { @@ -432,8 +459,6 @@ g_action_muxer_remove (GActionMuxer *muxer, const gchar *prefix) { GActionGroup *subgroup; - gchar **actions; - gchar **action; g_return_if_fail (G_IS_ACTION_MUXER (muxer)); @@ -441,15 +466,7 @@ g_action_muxer_remove (GActionMuxer *muxer, if (!subgroup) return; - actions = g_action_group_list_actions (subgroup); - for (action = actions; *action; action++) - g_action_muxer_action_removed (subgroup, *action, muxer); - g_strfreev (actions); - - g_signal_handlers_disconnect_by_func (subgroup, g_action_muxer_action_added, muxer); - g_signal_handlers_disconnect_by_func (subgroup, g_action_muxer_action_removed, muxer); - g_signal_handlers_disconnect_by_func (subgroup, g_action_muxer_action_enabled_changed, muxer); - g_signal_handlers_disconnect_by_func (subgroup, g_action_muxer_action_state_changed, muxer); + g_action_muxer_disconnect_group (muxer, subgroup); if (prefix) { -- cgit v1.2.3 From 2c7ad39202242c83265dcd94e384b8ad12979d83 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 4 Jun 2012 18:56:44 +0200 Subject: gactionmuxer: don't crash when no global actions are given --- src/gactionmuxer.c | 13 ++++++++----- test/test-gactionmuxer.cpp | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/gactionmuxer.c b/src/gactionmuxer.c index 6c4d08b..ac3f8e4 100644 --- a/src/gactionmuxer.c +++ b/src/gactionmuxer.c @@ -227,13 +227,16 @@ g_action_muxer_list_actions (GActionGroup *group) all_actions = g_array_sized_new (TRUE, FALSE, sizeof (gchar *), 8); - actions = g_action_group_list_actions (muxer->global_actions); - for (a = actions; *a; a++) + if (muxer->global_actions) { - gchar *name = g_strdup (*a); - g_array_append_val (all_actions, name); + actions = g_action_group_list_actions (muxer->global_actions); + for (a = actions; *a; a++) + { + gchar *name = g_strdup (*a); + g_array_append_val (all_actions, name); + } + g_strfreev (actions); } - g_strfreev (actions); g_hash_table_iter_init (&it, muxer->groups); while (g_hash_table_iter_next (&it, (gpointer *) &prefix, (gpointer *) &subgroup)) diff --git a/test/test-gactionmuxer.cpp b/test/test-gactionmuxer.cpp index fb32452..9f0ac3b 100644 --- a/test/test-gactionmuxer.cpp +++ b/test/test-gactionmuxer.cpp @@ -22,6 +22,21 @@ strv_contains (gchar **str_array, return FALSE; } +TEST(GActionMuxerTest, Empty) { + GActionMuxer *muxer; + gchar **actions; + + g_type_init (); + + muxer = g_action_muxer_new (); + + actions = g_action_group_list_actions (G_ACTION_GROUP (muxer)); + EXPECT_EQ (0, g_strv_length (actions)); + + g_strfreev (actions); + g_object_unref (muxer); +} + TEST(GActionMuxerTest, General) { const GActionEntry entries1[] = { { "one" }, { "two" }, { "three" } }; const GActionEntry entries2[] = { { "gb" }, { "es" }, { "fr" } }; -- cgit v1.2.3 From a2efe98ce72aedae472637154a3e45f5ddd25675 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 4 Jun 2012 20:03:15 +0200 Subject: Test gactionmuxer more extensively --- test/test-gactionmuxer.cpp | 167 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 166 insertions(+), 1 deletion(-) diff --git a/test/test-gactionmuxer.cpp b/test/test-gactionmuxer.cpp index 9f0ac3b..aa877fb 100644 --- a/test/test-gactionmuxer.cpp +++ b/test/test-gactionmuxer.cpp @@ -37,7 +37,7 @@ TEST(GActionMuxerTest, Empty) { g_object_unref (muxer); } -TEST(GActionMuxerTest, General) { +TEST(GActionMuxerTest, AddAndRemove) { const GActionEntry entries1[] = { { "one" }, { "two" }, { "three" } }; const GActionEntry entries2[] = { { "gb" }, { "es" }, { "fr" } }; const GActionEntry entries3[] = { { "foo" }, { "bar" } }; @@ -73,6 +73,8 @@ TEST(GActionMuxerTest, General) { g_action_muxer_insert (muxer, NULL, G_ACTION_GROUP (group3)); actions = g_action_group_list_actions (G_ACTION_GROUP (muxer)); + EXPECT_TRUE (g_action_group_has_action (G_ACTION_GROUP (muxer), "first.one")); + EXPECT_FALSE (g_action_group_has_action (G_ACTION_GROUP (muxer), "one")); EXPECT_EQ (8, g_strv_length (actions)); EXPECT_TRUE (strv_contains (actions, "first.one")); EXPECT_TRUE (strv_contains (actions, "first.two")); @@ -84,8 +86,171 @@ TEST(GActionMuxerTest, General) { EXPECT_TRUE (strv_contains (actions, "bar")); g_strfreev (actions); + g_action_muxer_remove (muxer, NULL); + EXPECT_FALSE (g_action_group_has_action (G_ACTION_GROUP (muxer), "foo")); + EXPECT_TRUE (g_action_group_has_action (G_ACTION_GROUP (muxer), "first.one")); + actions = g_action_group_list_actions (G_ACTION_GROUP (muxer)); + EXPECT_EQ (6, g_strv_length (actions)); + EXPECT_FALSE (strv_contains (actions, "foo")); + EXPECT_TRUE (strv_contains (actions, "first.one")); + g_strfreev (actions); + + g_action_muxer_remove (muxer, "first"); + EXPECT_FALSE (g_action_group_has_action (G_ACTION_GROUP (muxer), "first.two")); + EXPECT_TRUE (g_action_group_has_action (G_ACTION_GROUP (muxer), "second.es")); + actions = g_action_group_list_actions (G_ACTION_GROUP (muxer)); + EXPECT_EQ (3, g_strv_length (actions)); + EXPECT_FALSE (strv_contains (actions, "first.two")); + EXPECT_TRUE (strv_contains (actions, "second.es")); + g_strfreev (actions); + g_object_unref (muxer); g_object_unref (group1); g_object_unref (group2); g_object_unref (group3); } + +static gboolean +g_variant_equal0 (gconstpointer one, + gconstpointer two) +{ + if (one == NULL) + return two == NULL; + else + return g_variant_equal (one, two); +} + +TEST(GActionMuxerTest, ActionAttributes) { + GSimpleActionGroup *group; + GSimpleAction *action; + GActionMuxer *muxer; + gboolean enabled[2]; + const GVariantType *param_type[2]; + const GVariantType *state_type[2]; + GVariant *state_hint[2]; + GVariant *state[2]; + + g_type_init (); + + group = g_simple_action_group_new (); + action = g_simple_action_new ("one", G_VARIANT_TYPE_STRING); + g_simple_action_group_insert (group, G_ACTION (action)); + + muxer = g_action_muxer_new (); + g_action_muxer_insert (muxer, "first", G_ACTION_GROUP (group)); + + /* test two of the convenience functions */ + ASSERT_TRUE (g_action_group_get_action_enabled (G_ACTION_GROUP (muxer), "first.one")); + g_simple_action_set_enabled (action, FALSE); + ASSERT_FALSE (g_action_group_get_action_enabled (G_ACTION_GROUP (muxer), "first.one")); + + ASSERT_STREQ ((gchar *) g_action_group_get_action_parameter_type (G_ACTION_GROUP (muxer), "first.one"), + (gchar *) G_VARIANT_TYPE_STRING); + + /* query_action */ + g_action_group_query_action (G_ACTION_GROUP (group), "one", + &enabled[0], ¶m_type[0], &state_type[0], &state_hint[0], &state[0]); + g_action_group_query_action (G_ACTION_GROUP (muxer), "first.one", + &enabled[1], ¶m_type[1], &state_type[1], &state_hint[1], &state[1]); + ASSERT_EQ (enabled[0], enabled[1]); + ASSERT_STREQ ((gchar *) param_type[0], (gchar *) param_type[1]); + ASSERT_STREQ ((gchar *) state_type[0], (gchar *) state_type[1]); + ASSERT_TRUE (g_variant_equal0 ((gconstpointer) state_hint[0], (gconstpointer) state_hint[1])); + ASSERT_TRUE (g_variant_equal0 ((gconstpointer) state[0], (gconstpointer) state[1])); + + g_object_unref (action); + g_object_unref (group); + g_object_unref (muxer); +} + +typedef struct { + gboolean signal_ran; + const gchar *name; +} TestSignalClosure; + +static void +action_added (GActionGroup *group, + gchar *action_name, + gpointer user_data) +{ + TestSignalClosure *c = (TestSignalClosure *)user_data; + EXPECT_STREQ (c->name, action_name); + c->signal_ran = TRUE; +} + +static void +action_enabled_changed (GActionGroup *group, + gchar *action_name, + gboolean enabled, + gpointer user_data) +{ + TestSignalClosure *c = (TestSignalClosure *)user_data; + EXPECT_EQ (enabled, FALSE); + c->signal_ran = TRUE; +} + +static void +action_removed (GActionGroup *group, + gchar *action_name, + gpointer user_data) +{ + TestSignalClosure *c = (TestSignalClosure *)user_data; + EXPECT_STREQ (c->name, action_name); + c->signal_ran = TRUE; +} + +TEST(GActionMuxerTest, Signals) { + GSimpleActionGroup *group; + GSimpleAction *action; + GActionMuxer *muxer; + TestSignalClosure closure; + + group = g_simple_action_group_new (); + + action = g_simple_action_new ("one", G_VARIANT_TYPE_STRING); + g_simple_action_group_insert (group, G_ACTION (action)); + g_object_unref (action); + + muxer = g_action_muxer_new (); + + g_signal_connect (muxer, "action-added", + G_CALLBACK (action_added), (gpointer) &closure); + g_signal_connect (muxer, "action-enabled-changed", + G_CALLBACK (action_enabled_changed), (gpointer) &closure); + g_signal_connect (muxer, "action-removed", + G_CALLBACK (action_removed), (gpointer) &closure); + + /* add the group with "one" action and check whether the signal is emitted */ + closure.signal_ran = FALSE; + closure.name = "first.one"; + g_action_muxer_insert (muxer, "first", G_ACTION_GROUP (group)); + ASSERT_TRUE (closure.signal_ran); + + /* add a second action after the group was added to the muxer */ + closure.signal_ran = FALSE; + closure.name = "first.two"; + action = g_simple_action_new ("two", G_VARIANT_TYPE_STRING); + g_simple_action_group_insert (group, G_ACTION (action)); + ASSERT_TRUE (closure.signal_ran); + + /* disable the action */ + closure.signal_ran = FALSE; + g_simple_action_set_enabled (action, FALSE); + ASSERT_TRUE (closure.signal_ran); + g_object_unref (action); + + /* remove the first action */ + closure.signal_ran = FALSE; + closure.name = "first.one"; + g_simple_action_group_remove (group, "one"); + ASSERT_TRUE (closure.signal_ran); + + /* remove the whole group, should be notified about "first.two" */ + closure.signal_ran = FALSE; + closure.name = "first.two"; + g_action_muxer_remove (muxer, "first"); + ASSERT_TRUE (closure.signal_ran); + + g_object_unref (group); + g_object_unref (muxer); +} -- cgit v1.2.3 From a804cc56b3632fca85887f588746196950259aa8 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 4 Jun 2012 20:03:48 +0200 Subject: Update .bzrignore --- .bzrignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.bzrignore b/.bzrignore index ea0968a..5e323fa 100644 --- a/.bzrignore +++ b/.bzrignore @@ -38,3 +38,5 @@ stamp-* /src/status-provider-telepathy-marshal.h /src/indicator-messages-status-provider-0.5.pc /src/indicator-messages-status-provider-0.5.pc.in + +test/test-gactionmuxer -- cgit v1.2.3 From 26d7cfc736224403c4cb9f6f0a91aaa78020f80c Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 4 Jun 2012 22:18:31 +0200 Subject: Link test against a static lib to clean up lcov reporting If specifying the sources in src/ directly for each test, lcov generates reports for tests itself. That's fairly useless, as the ASSERT_* branches in the tests should (hopefully) never be taken. --- test/Makefile.am | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/test/Makefile.am b/test/Makefile.am index a790ba2..26dd867 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -18,12 +18,16 @@ libgtest_a_CXXFLAGS = \ test_gactionmuxer_SOURCES = \ - test-gactionmuxer.cpp \ - $(top_srcdir)/src/gactionmuxer.c \ - $(top_srcdir)/src/gactionmuxer.h + test-gactionmuxer.cpp -test_gactionmuxer_CPPFLAGS = $(APPLET_CFLAGS) $(AM_CPPFLAGS) -test_gactionmuxer_LDADD = $(APPLET_LIBS) libgtest.a +test_gactionmuxer_CPPFLAGS = \ + $(APPLET_CFLAGS) \ + $(AM_CPPFLAGS) + +test_gactionmuxer_LDADD = \ + $(APPLET_LIBS) \ + libindicator-messages-service.la \ + libgtest.a ###################################### @@ -41,7 +45,6 @@ libindicator_messages_service_la_HEADERS = \ $(top_srcdir)/src/gactionmuxer.h libindicator_messages_service_la_SOURCES = \ - $(top_srcdir)/src/messages-service.c \ $(top_srcdir)/src/messages-service-dbus.c \ $(top_srcdir)/src/gen-messages-service.xml.c \ $(top_srcdir)/src/app-section.c \ -- cgit v1.2.3 From 9de8f2d74171cc6ac4a7c63060979929caa29c24 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 4 Jun 2012 23:20:28 +0200 Subject: Add coverage results to .bzrignore --- .bzrignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.bzrignore b/.bzrignore index 5e323fa..e89bdf7 100644 --- a/.bzrignore +++ b/.bzrignore @@ -9,6 +9,8 @@ Makefile.in.in .libs *.valid stamp-* +*.gcno +*.gcda /COPYING /INSTALL @@ -23,6 +25,8 @@ stamp-* /autom4te.cache /depcomp /mkinstalldirs +/coverage.info +/coveragereport /m4/* /po/POTFILES -- cgit v1.2.3 From 0af65b6e3b8deb4010643fa61ed78d4ac89f6123 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 4 Jun 2012 23:38:11 +0200 Subject: gactionmuxer: remove unnecessary NULL check --- src/gactionmuxer.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/gactionmuxer.c b/src/gactionmuxer.c index ac3f8e4..4b90065 100644 --- a/src/gactionmuxer.c +++ b/src/gactionmuxer.c @@ -427,9 +427,6 @@ g_action_muxer_insert (GActionMuxer *muxer, g_action_muxer_remove (muxer, prefix); - if (!group) - return; - if (prefix) { prefix_copy = g_strdup (prefix); -- cgit v1.2.3 From 59b1408df2dec946511d092283b179b92f1aa343 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 4 Jun 2012 23:43:56 +0200 Subject: gactionmuxer: check for NULL in public API --- src/gactionmuxer.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/gactionmuxer.c b/src/gactionmuxer.c index 4b90065..2b1d11a 100644 --- a/src/gactionmuxer.c +++ b/src/gactionmuxer.c @@ -262,6 +262,8 @@ g_action_muxer_activate_action (GActionGroup *group, GActionGroup *subgroup; const gchar *action; + g_return_if_fail (action_name != NULL); + subgroup = g_action_muxer_lookup_group (muxer, action_name, &action); if (subgroup) @@ -277,6 +279,8 @@ g_action_muxer_change_action_state (GActionGroup *group, GActionGroup *subgroup; const gchar *action; + g_return_if_fail (action_name != NULL); + subgroup = g_action_muxer_lookup_group (muxer, action_name, &action); if (subgroup) @@ -296,6 +300,8 @@ g_action_muxer_query_action (GActionGroup *group, GActionGroup *subgroup; const gchar *action; + g_return_val_if_fail (action_name != NULL, FALSE); + subgroup = g_action_muxer_lookup_group (muxer, action_name, &action); if (!subgroup) -- cgit v1.2.3 From 0eda2f38aeb7abdb4c342305fef15388ec3fa248 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 4 Jun 2012 23:44:13 +0200 Subject: gactionmuxer: more tests --- test/test-gactionmuxer.cpp | 111 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 110 insertions(+), 1 deletion(-) diff --git a/test/test-gactionmuxer.cpp b/test/test-gactionmuxer.cpp index aa877fb..64c0d20 100644 --- a/test/test-gactionmuxer.cpp +++ b/test/test-gactionmuxer.cpp @@ -22,6 +22,26 @@ strv_contains (gchar **str_array, return FALSE; } +TEST(GActionMuxerTest, Sanity) { + GActionMuxer *muxer; + + g_type_init (); + + g_action_muxer_insert (NULL, NULL, NULL); + g_action_muxer_remove (NULL, NULL); + + muxer = g_action_muxer_new (); + + g_action_muxer_insert (muxer, NULL, NULL); + g_action_muxer_remove (muxer, NULL); + EXPECT_FALSE (g_action_group_has_action (G_ACTION_GROUP (muxer), NULL)); + EXPECT_FALSE (g_action_group_get_action_enabled (G_ACTION_GROUP (muxer), NULL)); + EXPECT_FALSE (g_action_group_query_action (G_ACTION_GROUP (muxer), NULL, NULL, NULL, NULL, NULL, NULL)); + g_action_group_activate_action (G_ACTION_GROUP (muxer), NULL, NULL); + + g_object_unref (muxer); +} + TEST(GActionMuxerTest, Empty) { GActionMuxer *muxer; gchar **actions; @@ -104,6 +124,16 @@ TEST(GActionMuxerTest, AddAndRemove) { EXPECT_TRUE (strv_contains (actions, "second.es")); g_strfreev (actions); + g_action_muxer_insert (muxer, "second", G_ACTION_GROUP (group2)); + actions = g_action_group_list_actions (G_ACTION_GROUP (muxer)); + EXPECT_EQ (3, g_strv_length (actions)); + g_strfreev (actions); + + g_action_muxer_insert (muxer, NULL, G_ACTION_GROUP (group3)); + actions = g_action_group_list_actions (G_ACTION_GROUP (muxer)); + EXPECT_EQ (5, g_strv_length (actions)); + g_strfreev (actions); + g_object_unref (muxer); g_object_unref (group1); g_object_unref (group2); @@ -189,6 +219,17 @@ action_enabled_changed (GActionGroup *group, c->signal_ran = TRUE; } +static void +action_state_changed (GActionGroup *group, + gchar *action_name, + GVariant *value, + gpointer user_data) +{ + TestSignalClosure *c = (TestSignalClosure *)user_data; + EXPECT_STREQ (g_variant_get_string (value, NULL), "off"); + c->signal_ran = TRUE; +} + static void action_removed (GActionGroup *group, gchar *action_name, @@ -217,6 +258,8 @@ TEST(GActionMuxerTest, Signals) { G_CALLBACK (action_added), (gpointer) &closure); g_signal_connect (muxer, "action-enabled-changed", G_CALLBACK (action_enabled_changed), (gpointer) &closure); + g_signal_connect (muxer, "action-state-changed", + G_CALLBACK (action_state_changed), (gpointer) &closure); g_signal_connect (muxer, "action-removed", G_CALLBACK (action_removed), (gpointer) &closure); @@ -229,7 +272,8 @@ TEST(GActionMuxerTest, Signals) { /* add a second action after the group was added to the muxer */ closure.signal_ran = FALSE; closure.name = "first.two"; - action = g_simple_action_new ("two", G_VARIANT_TYPE_STRING); + action = g_simple_action_new_stateful ("two", G_VARIANT_TYPE_STRING, + g_variant_new_string ("on")); g_simple_action_group_insert (group, G_ACTION (action)); ASSERT_TRUE (closure.signal_ran); @@ -237,6 +281,11 @@ TEST(GActionMuxerTest, Signals) { closure.signal_ran = FALSE; g_simple_action_set_enabled (action, FALSE); ASSERT_TRUE (closure.signal_ran); + + /* change its state */ + closure.signal_ran = FALSE; + g_simple_action_set_state (action, g_variant_new_string ("off")); + ASSERT_TRUE (closure.signal_ran); g_object_unref (action); /* remove the first action */ @@ -254,3 +303,63 @@ TEST(GActionMuxerTest, Signals) { g_object_unref (group); g_object_unref (muxer); } + +static void +action_activated (GSimpleAction *simple, + GVariant *parameter, + gpointer user_data) +{ + gboolean *signal_ran = (gboolean *)user_data; + + ASSERT_STREQ (g_variant_get_string (parameter, NULL), "value"); + *signal_ran = TRUE; +} + +static void +action_change_state (GSimpleAction *simple, + GVariant *value, + gpointer user_data) +{ + gboolean *signal_ran = (gboolean *)user_data; + + ASSERT_STREQ (g_variant_get_string (value, NULL), "off"); + *signal_ran = TRUE; +} + +TEST(GActionMuxerTest, ActivateAction) { + GSimpleActionGroup *group; + GSimpleAction *action; + GActionMuxer *muxer; + gboolean signal_ran; + + group = g_simple_action_group_new (); + + action = g_simple_action_new ("one", G_VARIANT_TYPE_STRING); + g_simple_action_group_insert (group, G_ACTION (action)); + g_signal_connect (action, "activate", + G_CALLBACK (action_activated), (gpointer) &signal_ran); + g_object_unref (action); + + action = g_simple_action_new_stateful ("two", NULL, + g_variant_new_string ("on")); + g_simple_action_group_insert (group, G_ACTION (action)); + g_signal_connect (action, "change-state", + G_CALLBACK (action_change_state), (gpointer) &signal_ran); + g_object_unref (action); + + muxer = g_action_muxer_new (); + g_action_muxer_insert (muxer, "first", G_ACTION_GROUP (group)); + + signal_ran = FALSE; + g_action_group_activate_action (G_ACTION_GROUP (muxer), "first.one", + g_variant_new_string ("value")); + ASSERT_TRUE (signal_ran); + + signal_ran = FALSE; + g_action_group_change_action_state (G_ACTION_GROUP (muxer), "first.two", + g_variant_new_string ("off")); + ASSERT_TRUE (signal_ran); + + g_object_unref (group); + g_object_unref (muxer); +} -- cgit v1.2.3 From 368b17f9ab5cbe934d796ddd19f4510bbf01cab8 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 4 Jun 2012 23:47:13 +0200 Subject: testing: use EXPECT_* instead of ASSERT_* --- test/test-gactionmuxer.cpp | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/test/test-gactionmuxer.cpp b/test/test-gactionmuxer.cpp index 64c0d20..6304853 100644 --- a/test/test-gactionmuxer.cpp +++ b/test/test-gactionmuxer.cpp @@ -170,11 +170,11 @@ TEST(GActionMuxerTest, ActionAttributes) { g_action_muxer_insert (muxer, "first", G_ACTION_GROUP (group)); /* test two of the convenience functions */ - ASSERT_TRUE (g_action_group_get_action_enabled (G_ACTION_GROUP (muxer), "first.one")); + EXPECT_TRUE (g_action_group_get_action_enabled (G_ACTION_GROUP (muxer), "first.one")); g_simple_action_set_enabled (action, FALSE); - ASSERT_FALSE (g_action_group_get_action_enabled (G_ACTION_GROUP (muxer), "first.one")); + EXPECT_FALSE (g_action_group_get_action_enabled (G_ACTION_GROUP (muxer), "first.one")); - ASSERT_STREQ ((gchar *) g_action_group_get_action_parameter_type (G_ACTION_GROUP (muxer), "first.one"), + EXPECT_STREQ ((gchar *) g_action_group_get_action_parameter_type (G_ACTION_GROUP (muxer), "first.one"), (gchar *) G_VARIANT_TYPE_STRING); /* query_action */ @@ -182,11 +182,11 @@ TEST(GActionMuxerTest, ActionAttributes) { &enabled[0], ¶m_type[0], &state_type[0], &state_hint[0], &state[0]); g_action_group_query_action (G_ACTION_GROUP (muxer), "first.one", &enabled[1], ¶m_type[1], &state_type[1], &state_hint[1], &state[1]); - ASSERT_EQ (enabled[0], enabled[1]); - ASSERT_STREQ ((gchar *) param_type[0], (gchar *) param_type[1]); - ASSERT_STREQ ((gchar *) state_type[0], (gchar *) state_type[1]); - ASSERT_TRUE (g_variant_equal0 ((gconstpointer) state_hint[0], (gconstpointer) state_hint[1])); - ASSERT_TRUE (g_variant_equal0 ((gconstpointer) state[0], (gconstpointer) state[1])); + EXPECT_EQ (enabled[0], enabled[1]); + EXPECT_STREQ ((gchar *) param_type[0], (gchar *) param_type[1]); + EXPECT_STREQ ((gchar *) state_type[0], (gchar *) state_type[1]); + EXPECT_TRUE (g_variant_equal0 ((gconstpointer) state_hint[0], (gconstpointer) state_hint[1])); + EXPECT_TRUE (g_variant_equal0 ((gconstpointer) state[0], (gconstpointer) state[1])); g_object_unref (action); g_object_unref (group); @@ -267,7 +267,7 @@ TEST(GActionMuxerTest, Signals) { closure.signal_ran = FALSE; closure.name = "first.one"; g_action_muxer_insert (muxer, "first", G_ACTION_GROUP (group)); - ASSERT_TRUE (closure.signal_ran); + EXPECT_TRUE (closure.signal_ran); /* add a second action after the group was added to the muxer */ closure.signal_ran = FALSE; @@ -275,30 +275,30 @@ TEST(GActionMuxerTest, Signals) { action = g_simple_action_new_stateful ("two", G_VARIANT_TYPE_STRING, g_variant_new_string ("on")); g_simple_action_group_insert (group, G_ACTION (action)); - ASSERT_TRUE (closure.signal_ran); + EXPECT_TRUE (closure.signal_ran); /* disable the action */ closure.signal_ran = FALSE; g_simple_action_set_enabled (action, FALSE); - ASSERT_TRUE (closure.signal_ran); + EXPECT_TRUE (closure.signal_ran); /* change its state */ closure.signal_ran = FALSE; g_simple_action_set_state (action, g_variant_new_string ("off")); - ASSERT_TRUE (closure.signal_ran); + EXPECT_TRUE (closure.signal_ran); g_object_unref (action); /* remove the first action */ closure.signal_ran = FALSE; closure.name = "first.one"; g_simple_action_group_remove (group, "one"); - ASSERT_TRUE (closure.signal_ran); + EXPECT_TRUE (closure.signal_ran); /* remove the whole group, should be notified about "first.two" */ closure.signal_ran = FALSE; closure.name = "first.two"; g_action_muxer_remove (muxer, "first"); - ASSERT_TRUE (closure.signal_ran); + EXPECT_TRUE (closure.signal_ran); g_object_unref (group); g_object_unref (muxer); @@ -311,7 +311,7 @@ action_activated (GSimpleAction *simple, { gboolean *signal_ran = (gboolean *)user_data; - ASSERT_STREQ (g_variant_get_string (parameter, NULL), "value"); + EXPECT_STREQ (g_variant_get_string (parameter, NULL), "value"); *signal_ran = TRUE; } @@ -322,7 +322,7 @@ action_change_state (GSimpleAction *simple, { gboolean *signal_ran = (gboolean *)user_data; - ASSERT_STREQ (g_variant_get_string (value, NULL), "off"); + EXPECT_STREQ (g_variant_get_string (value, NULL), "off"); *signal_ran = TRUE; } @@ -353,12 +353,12 @@ TEST(GActionMuxerTest, ActivateAction) { signal_ran = FALSE; g_action_group_activate_action (G_ACTION_GROUP (muxer), "first.one", g_variant_new_string ("value")); - ASSERT_TRUE (signal_ran); + EXPECT_TRUE (signal_ran); signal_ran = FALSE; g_action_group_change_action_state (G_ACTION_GROUP (muxer), "first.two", g_variant_new_string ("off")); - ASSERT_TRUE (signal_ran); + EXPECT_TRUE (signal_ran); g_object_unref (group); g_object_unref (muxer); -- cgit v1.2.3 From 179a6a300da632b507c8152d0897a1012c8de05d Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Fri, 8 Jun 2012 10:59:37 +0200 Subject: Use autoreconf instead of gnome-autogen.sh Also remove INSTALL. An up-to-date version is copied into the tree by autoreconf. Note: autogen.sh does not call configure anymore. --- autogen.sh | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/autogen.sh b/autogen.sh index 1abf3a7..a49cd41 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,11 +1,5 @@ -#!/bin/sh +#!/bin/sh -e -PKG_NAME="indicator-messages" - -which gnome-autogen.sh || { - echo "You need gnome-common from GNOME SVN" - exit 1 -} - -USE_GNOME2_MACROS=1 \ -. gnome-autogen.sh +autoreconf -i -f +intltoolize +gtkdocize -- cgit v1.2.3 From bc9cd727c2bb0116c94e1bf258e257d5bff406f8 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Wed, 13 Jun 2012 17:57:09 +0200 Subject: Don't install convenience library used for the tests --- test/Makefile.am | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/test/Makefile.am b/test/Makefile.am index 26dd867..ca4965e 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -34,22 +34,20 @@ test_gactionmuxer_LDADD = \ # Lib containing code under test ###################################### -lib_LTLIBRARIES = \ +noinst_LTLIBRARIES = \ libindicator-messages-service.la -libindicator_messages_service_la_HEADERS = \ - $(top_srcdir)/src/gen-messages-service.xml.h \ - $(top_srcdir)/src/app-section.h \ - $(top_srcdir)/src/dbus-data.h \ - $(top_srcdir)/src/status-items.h \ - $(top_srcdir)/src/gactionmuxer.h - libindicator_messages_service_la_SOURCES = \ $(top_srcdir)/src/messages-service-dbus.c \ $(top_srcdir)/src/gen-messages-service.xml.c \ + $(top_srcdir)/src/gen-messages-service.xml.h \ $(top_srcdir)/src/app-section.c \ + $(top_srcdir)/src/app-section.h \ $(top_srcdir)/src/status-items.c \ - $(top_srcdir)/src/gactionmuxer.c + $(top_srcdir)/src/status-items.h \ + $(top_srcdir)/src/gactionmuxer.c \ + $(top_srcdir)/src/gactionmuxer.h + $(top_srcdir)/src/dbus-data.h libindicator_messages_service_ladir = \ $(includedir)/libindicator-messages-service/ -- cgit v1.2.3 From 78edb4ee5c8a585986fa092ee4ec81fad442f64f Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Fri, 15 Jun 2012 14:59:15 +0200 Subject: Add first version of a libmessaging-menu client library --- .bzrignore | 4 + Makefile.am | 1 + configure.ac | 4 + libmessaging-menu/Makefile.am | 35 ++ libmessaging-menu/messaging-menu.c | 746 +++++++++++++++++++++++++++++++++ libmessaging-menu/messaging-menu.h | 130 ++++++ libmessaging-menu/messaging-menu.pc.in | 11 + 7 files changed, 931 insertions(+) create mode 100644 libmessaging-menu/Makefile.am create mode 100644 libmessaging-menu/messaging-menu.c create mode 100644 libmessaging-menu/messaging-menu.h create mode 100644 libmessaging-menu/messaging-menu.pc.in diff --git a/.bzrignore b/.bzrignore index e89bdf7..431e715 100644 --- a/.bzrignore +++ b/.bzrignore @@ -43,4 +43,8 @@ stamp-* /src/indicator-messages-status-provider-0.5.pc /src/indicator-messages-status-provider-0.5.pc.in +/libmessaging-menu/messaging-menu.pc +/libmessaging-menu/indicator-messages-service.c +/libmessaging-menu/indicator-messages-service.h + test/test-gactionmuxer diff --git a/Makefile.am b/Makefile.am index bef67bd..9bd3903 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,7 @@ SUBDIRS = \ src \ + libmessaging-menu \ data \ po diff --git a/configure.ac b/configure.ac index e3beaa2..9ef2438 100644 --- a/configure.ac +++ b/configure.ac @@ -52,6 +52,8 @@ PKG_CHECK_MODULES(APPLET, gtk+-3.0 >= $GTK_REQUIRED_VERSION gmodule-2.0 >= $GLIB_REQUIRED_VERSION menu-factory-gtk >= $MENU_FACTORY_REQUIRED_VERSION) +PKG_CHECK_MODULES(GIO, gio-unix-2.0 >= $GIO_UNIX_REQUIRED_VERSION) + AC_SUBST(APPLET_CFLAGS) AC_SUBST(APPLET_LIBS) @@ -198,6 +200,8 @@ data/icons/scalable/status/Makefile data/icons/scalable/categories/Makefile po/Makefile.in test/Makefile +libmessaging-menu/Makefile +libmessaging-menu/messaging-menu.pc ]) ########################### diff --git a/libmessaging-menu/Makefile.am b/libmessaging-menu/Makefile.am new file mode 100644 index 0000000..a0da51e --- /dev/null +++ b/libmessaging-menu/Makefile.am @@ -0,0 +1,35 @@ + +lib_LTLIBRARIES = libmessaging-menu.la + +libmessaging_menu_ladir = $(includedir)/messaging-menu + +libmessaging_menu_la_SOURCES = \ + messaging-menu.c \ + $(BUILT_SOURCES) + +libmessaging_menu_la_HEADERS = \ + messaging-menu.h + +libmessaging_menu_la_LIBADD = $(GIO_LIBS) + +libmessaging_menu_la_CFLAGS = \ + $(GIO_CFLAGS) \ + -Wall + +BUILT_SOURCES = \ + indicator-messages-service.c \ + indicator-messages-service.h + +CLEANFILES = $(BUILT_SOURCES) + +indicator-messages-service.c: $(top_srcdir)/src/messages-service.xml + $(AM_V_GEN) gdbus-codegen \ + --interface-prefix com.canonical.indicator.messages. \ + --generate-c-code indicator-messages-service \ + --c-namespace IndicatorMessages \ + $^ +indicator-messages-service.h: indicator-messages-service.c + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = messaging-menu.pc + diff --git a/libmessaging-menu/messaging-menu.c b/libmessaging-menu/messaging-menu.c new file mode 100644 index 0000000..5b786af --- /dev/null +++ b/libmessaging-menu/messaging-menu.c @@ -0,0 +1,746 @@ +/* + * Copyright 2012 Canonical Ltd. + * + * 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 . + * + * Authors: + * Lars Uebernickel + */ + +#include "messaging-menu.h" +#include "indicator-messages-service.h" + +#include + +/** + * SECTION:messagingmenuapp + * @title: MessagingMenuApp + * @short_description: An application section in the messaging menu + */ +struct _MessagingMenuApp +{ + GObject parent_instance; + + GDesktopAppInfo *appinfo; + int registered; /* -1 for unknown */ + MessagingMenuStatus status; + GSimpleActionGroup *source_actions; + GMenu *menu; + + IndicatorMessagesService *messages_service; + + GCancellable *cancellable; +}; + +G_DEFINE_TYPE (MessagingMenuApp, messaging_menu_app, G_TYPE_OBJECT); + +enum { + PROP_0, + PROP_DESKTOP_ID, + N_PROPERTIES +}; + +enum { + ACTIVATE_SOURCE, + N_SIGNALS +}; + +static GParamSpec *properties[N_PROPERTIES]; +static guint signals[N_SIGNALS]; + +static void +messaging_menu_app_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MessagingMenuApp *app = MESSAGING_MENU_APP (object); + + switch (prop_id) + { + case PROP_DESKTOP_ID: + app->appinfo = g_desktop_app_info_new (g_value_get_string (value)); + if (app->appinfo == NULL) + { + g_warning ("could not find the desktop file for '%s'", + g_value_get_string (value)); + } + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +messaging_menu_app_finalize (GObject *object) +{ + G_OBJECT_CLASS (messaging_menu_app_parent_class)->finalize (object); +} + +static void +messaging_menu_app_dispose (GObject *object) +{ + MessagingMenuApp *app = MESSAGING_MENU_APP (object); + + if (app->cancellable) + { + g_cancellable_cancel (app->cancellable); + g_object_unref (app->cancellable); + app->cancellable = NULL; + } + + g_clear_object (&app->appinfo); + g_clear_object (&app->source_actions); + g_clear_object (&app->menu); + + G_OBJECT_CLASS (messaging_menu_app_parent_class)->dispose (object); +} + +static void +messaging_menu_app_class_init (MessagingMenuAppClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->set_property = messaging_menu_app_set_property; + object_class->finalize = messaging_menu_app_finalize; + object_class->dispose = messaging_menu_app_dispose; + + properties[PROP_DESKTOP_ID] = g_param_spec_string ("desktop-id", + "Desktop Id", + "The desktop id of the associated application", + NULL, + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, N_PROPERTIES, properties); + + signals[ACTIVATE_SOURCE] = g_signal_new ("activate-source", + MESSAGING_MENU_TYPE_APP, + G_SIGNAL_RUN_FIRST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, G_TYPE_STRING); +} + +static void +created_messages_service (GObject *source_object, + GAsyncResult *result, + gpointer user_data) +{ + MessagingMenuApp *app = user_data; + GError *error = NULL; + + app->messages_service = indicator_messages_service_proxy_new_finish (result, &error); + if (!app->messages_service) + { + g_warning ("unable to connect to the mesaging menu service: %s", error->message); + g_error_free (error); + return; + } + + /* sync current status */ + if (app->registered == TRUE) + messaging_menu_app_register (app); + else if (app->registered == FALSE) + messaging_menu_app_unregister (app); +} + +static void +got_session_bus (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + MessagingMenuApp *app = user_data; + GDBusConnection *bus; + GError *error = NULL; + guint id; + + bus = g_bus_get_finish (res, &error); + if (bus == NULL) + { + g_warning ("unable to connect to session bus: %s", error->message); + g_error_free (error); + return; + } + + id = g_dbus_connection_export_action_group (bus, + "/com/canonical/indicator/messages", + G_ACTION_GROUP (app->source_actions), + &error); + if (!id) + { + g_warning ("unable to export action group: %s", error->message); + g_error_free (error); + } + + id = g_dbus_connection_export_menu_model (bus, + "/com/canonical/indicator/messages", + G_MENU_MODEL (app->menu), + &error); + if (!id) + { + g_warning ("unable to export menu: %s", error->message); + g_error_free (error); + } + + indicator_messages_service_proxy_new (bus, + G_DBUS_PROXY_FLAGS_NONE, + "com.canonical.indicator.messages", + "/com/canonical/indicator/messages/service", + app->cancellable, + created_messages_service, + app); + + g_object_unref (bus); +} + +static void +messaging_menu_app_init (MessagingMenuApp *app) +{ + app->registered = -1; + app->status = MESSAGING_MENU_STATUS_OFFLINE; + + app->cancellable = g_cancellable_new (); + + app->source_actions = g_simple_action_group_new (); + app->menu = g_menu_new (); + + app->cancellable = g_cancellable_new (); + + + g_bus_get (G_BUS_TYPE_SESSION, + app->cancellable, + got_session_bus, + app); +} + +/** + * messaging_menu_new: + * @desktop_id: a desktop file id. See g_desktop_app_info_new() + * + * Creates a new #MessagingMenuApp for the application associated with + * @desktop_id. + * + * If the application is already registered with the messaging menu, it will be + * marked as "running". Otherwise, call messaging_menu_app_register(). + * + * The messaging menu will return to marking the application as not running as + * soon as the returned #MessagingMenuApp is destroyed. + * + * Returns: (transfer-full): a new #MessagingMenuApp + */ +MessagingMenuApp * +messaging_menu_app_new (const gchar *desktop_id) +{ + return g_object_new (MESSAGING_MENU_TYPE_APP, + "desktop-id", desktop_id, + NULL); +} + +/** + * messaging_menu_app_register: + * @app: a #MessagingMenuApp + * + * Registers @app with the messaging menu. + * + * The messaging menu will add a section with an app launcher and the shortcuts + * defined in its desktop file. + * + * The application will be marked as "running" as long as @app is alive or + * messaging_menu_app_unregister() is called. + */ +void +messaging_menu_app_register (MessagingMenuApp *app) +{ + app->registered = TRUE; + + /* state will be synced right after connecting to the service */ + if (!app->messages_service) + return; + + indicator_messages_service_call_register_application (app->messages_service, + g_app_info_get_id (G_APP_INFO (app->appinfo)), + "/com/canonical/indicator/messages", + app->cancellable, + NULL, NULL); +} + +/** + * messaging_menu_app_unregister: + * @app: a #MessagingMenuApp + * + * Completely removes the application associated with @desktop_id from the + * messaging menu. + * + * Note: @app will remain valid and usable after this call. + */ +void +messaging_menu_app_unregister (MessagingMenuApp *app) +{ + app->registered = FALSE; + + /* state will be synced right after connecting to the service */ + if (!app->messages_service) + return; + + indicator_messages_service_call_unregister_application (app->messages_service, + g_app_info_get_id (G_APP_INFO (app->appinfo)), + app->cancellable, + NULL, NULL); +} + +/** + * messaging_menu_app_set_status: + * @app: a #MessagingMenuApp + * @status: a #MessagingMenuStatus + */ +void +messaging_menu_app_set_status (MessagingMenuApp *app, + MessagingMenuStatus status) +{ + g_warning ("%s: not yet implemented", G_STRFUNC); +} + +static void +source_action_activated (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + MessagingMenuApp *app = user_data; + + g_signal_emit (app, signals[ACTIVATE_SOURCE], 0, + g_action_get_name (G_ACTION (action))); +} + +static void +messaging_menu_app_insert_source_action (MessagingMenuApp *app, + gint position, + const gchar *id, + GIcon *icon, + const gchar *label, + GVariant *state) +{ + GSimpleAction *action; + GMenuItem *menuitem; + + g_return_if_fail (MESSAGING_MENU_IS_APP (app)); + g_return_if_fail (id != NULL); + + if (g_simple_action_group_lookup (app->source_actions, id)) + { + g_warning ("a source with id '%s' already exists", id); + return; + } + + action = g_simple_action_new_stateful (id, NULL, state); + g_signal_connect (action, "activate", + G_CALLBACK (source_action_activated), app); + g_simple_action_group_insert (app->source_actions, G_ACTION (action)); + g_object_unref (action); + + menuitem = g_menu_item_new (label, id); + if (icon) + { + gchar *icon_name = g_icon_to_string (icon); + g_menu_item_set_attribute (menuitem, "indicator-icon-name", icon_name); + g_free (icon_name); + } + g_menu_insert_item (app->menu, position, menuitem); + g_object_unref (menuitem); +} + +static void +messaging_menu_app_set_source_action (MessagingMenuApp *app, + const gchar *source_id, + GVariant *state) +{ + GAction *action; + + g_return_if_fail (MESSAGING_MENU_IS_APP (app)); + g_return_if_fail (source_id != NULL); + + action = g_simple_action_group_lookup (app->source_actions, source_id); + if (action == NULL) + { + g_warning ("a source with id '%s' doesn't exist", source_id); + return; + } + + g_simple_action_set_state (G_SIMPLE_ACTION (action), state); +} + +/** + * messaging_menu_app_insert_source: + * @app: a #MessagingMenuApp + * @position: the position at which to insert the source + * @id: a unique identifier for the source to be added + * @icon: the icon associated with the source + * @label: a user-visible string best describing the source + * + * Inserts a new message source into the section representing @app. Equivalent + * to calling messaging_menu_app_insert_source_with_time() with the current + * time. + * + * It is an error to insert a source with an @id which already exists. Use + * messaging_menu_app_has_source() to find out whether there is such a source. + */ +void +messaging_menu_app_insert_source (MessagingMenuApp *app, + gint position, + const gchar *id, + GIcon *icon, + const gchar *label) +{ + messaging_menu_app_insert_source_with_time (app, position, id, icon, label, + g_get_real_time ()); +} + +/** + * messaging_menu_app_append_source: + * @app: a #MessagingMenuApp + * @id: a unique identifier for the source to be added + * @icon: the icon associated with the source + * @label: a user-visible string best describing the source + * + * Appends a new message source to the end of the section representing @app. + * Equivalent to calling messaging_menu_app_append_source_with_time() with the + * current time. + * + * It is an error to add a source with an @id which already exists. Use + * messaging_menu_app_has_source() to find out whether there is such a source. + */ +void +messaging_menu_app_append_source (MessagingMenuApp *app, + const gchar *id, + GIcon *icon, + const gchar *label) +{ + messaging_menu_app_insert_source (app, -1, id, icon, label); +} + +/** + * messaging_menu_app_insert_source_with_count: + * @app: a #MessagingMenuApp + * @position: the position at which to insert the source + * @id: a unique identifier for the source to be added + * @icon: the icon associated with the source + * @label: a user-visible string best describing the source + * @count: the count for the source + * + * Inserts a new message source into the section representing @app and + * initializes it with @count. + * + * To update the count, use messaging_menu_app_set_source_count(). + * + * It is an error to insert a source with an @id which already exists. Use + * messaging_menu_app_has_source() to find out whether there is such a source. + */ +void +messaging_menu_app_insert_source_with_count (MessagingMenuApp *app, + gint position, + const gchar *id, + GIcon *icon, + const gchar *label, + guint count) +{ + messaging_menu_app_insert_source_action (app, position, id, icon, label, + g_variant_new ("(uxs)", count, 0, "")); +} + +/** + * messaging_menu_app_append_source_with_count: + * @app: a #MessagingMenuApp + * @id: a unique identifier for the source to be added + * @icon: the icon associated with the source + * @label: a user-visible string best describing the source + * @count: the count for the source + * + * Appends a new message source to the end of the section representing @app and + * initializes it with @count. + * + * To update the count, use messaging_menu_app_set_source_count(). + * + * It is an error to add a source with an @id which already exists. Use + * messaging_menu_app_has_source() to find out whether there is such a source. + */ +void messaging_menu_app_append_source_with_count (MessagingMenuApp *app, + const gchar *id, + GIcon *icon, + const gchar *label, + guint count) +{ + messaging_menu_app_insert_source_with_count (app, -1, id, icon, label, count); +} + +/** + * messaging_menu_app_insert_source_with_time: + * @app: a #MessagingMenuApp + * @position: the position at which to insert the source + * @id: a unique identifier for the source to be added + * @icon: the icon associated with the source + * @label: a user-visible string best describing the source + * @time: the time when the source was created + * + * Inserts a new message source into the section representing @app and + * initializes it with @time. + * + * To change the time, use messaging_menu_app_set_source_time(). + * + * It is an error to insert a source with an @id which already exists. Use + * messaging_menu_app_has_source() to find out whether there is such a source. + */ +void +messaging_menu_app_insert_source_with_time (MessagingMenuApp *app, + gint position, + const gchar *id, + GIcon *icon, + const gchar *label, + gint64 time) +{ + messaging_menu_app_insert_source_action (app, position, id, icon, label, + g_variant_new ("(uxs)", 0, time, "")); +} + +/** + * messaging_menu_app_append_source_with_time: + * @app: a #MessagingMenuApp + * @position: the position at which to insert the source + * @id: a unique identifier for the source to be added + * @icon: the icon associated with the source + * @label: a user-visible string best describing the source + * @time: the time when the source was created + * + * Appends a new message source to the end of the section representing @app and + * initializes it with @time. + * + * To change the time, use messaging_menu_app_set_source_time(). + * + * It is an error to insert a source with an @id which already exists. Use + * messaging_menu_app_has_source() to find out whether there is such a source. + */ +void +messaging_menu_app_append_source_with_time (MessagingMenuApp *app, + const gchar *id, + GIcon *icon, + const gchar *label, + gint64 time) +{ + messaging_menu_app_insert_source_with_time (app, -1, id, icon, label, time); +} + +/** + * messaging_menu_app_insert_source_with_string: + * @app: a #MessagingMenuApp + * @position: the position at which to insert the source + * @id: a unique identifier for the source to be added + * @icon: the icon associated with the source + * @label: a user-visible string best describing the source + * @str: a string associated with the source + * + * Inserts a new message source into the section representing @app and + * initializes it with @str. + * + * To update the string, use messaging_menu_app_set_source_string(). + * + * It is an error to insert a source with an @id which already exists. Use + * messaging_menu_app_has_source() to find out whether there is such a source. + */ +void +messaging_menu_app_insert_source_with_string (MessagingMenuApp *app, + gint position, + const gchar *id, + GIcon *icon, + const gchar *label, + const gchar *str) +{ + messaging_menu_app_insert_source_action (app, position, id, icon, label, + g_variant_new ("(uxs)", 0, 0, str)); +} + +/** + * messaging_menu_app_append_source_with_string: + * @app: a #MessagingMenuApp + * @position: the position at which to insert the source + * @id: a unique identifier for the source to be added + * @icon: the icon associated with the source + * @label: a user-visible string best describing the source + * @str: a string associated with the source + * + * Appends a new message source to the end of the section representing @app and + * initializes it with @str. + * + * To update the string, use messaging_menu_app_set_source_string(). + * + * It is an error to insert a source with an @id which already exists. Use + * messaging_menu_app_has_source() to find out whether there is such a source. + */ +void +messaging_menu_app_append_source_with_string (MessagingMenuApp *app, + const gchar *id, + GIcon *icon, + const gchar *label, + const gchar *str) +{ + messaging_menu_app_insert_source_with_string (app, -1, id, icon, label, str); +} + +/** + * messaging_menu_app_remove_source: + * @app: a #MessagingMenuApp + * @source_id: the id of the source to remove + * + * Removes the source corresponding to @source_id from the menu. + */ +void +messaging_menu_app_remove_source (MessagingMenuApp *app, + const gchar *source_id) +{ + int n_items; + int i; + + g_return_if_fail (MESSAGING_MENU_IS_APP (app)); + g_return_if_fail (source_id != NULL); + + if (g_simple_action_group_lookup (app->source_actions, source_id) == NULL) + { + g_warning ("%s: a source with id '%s' doesn't exist", G_STRFUNC, source_id); + return; + } + + n_items = g_menu_model_get_n_items (G_MENU_MODEL (app->menu)); + for (i = 0; i < n_items; i++) + { + const gchar *action = NULL; + + g_menu_model_get_item_attribute (G_MENU_MODEL (app->menu), i, + "action", "&s", &action); + if (!g_strcmp0 (action, source_id)) + { + g_menu_remove (app->menu, i); + break; + } + } + + g_simple_action_group_remove (app->source_actions, source_id); +} + +/** + * messaging_menu_app_has_source: + * @app: a #MessagingMenuApp + * @source_id: a source id + * + * Returns: TRUE if there is a source associated with @source_id + */ +gboolean +messaging_menu_app_has_source (MessagingMenuApp *app, + const gchar *source_id) +{ + g_return_val_if_fail (MESSAGING_MENU_IS_APP (app), FALSE); + g_return_val_if_fail (source_id != NULL, FALSE); + + return g_simple_action_group_lookup (app->source_actions, source_id) != NULL; +} + +/** + * messaging_menu_app_set_source_count: + * @app: a #MessagingMenuApp + * @source_id: a source id + * @count: the new count for the source + * + * Updates the count of @source_id to @count. + */ +void messaging_menu_app_set_source_count (MessagingMenuApp *app, + const gchar *source_id, + guint count) +{ + messaging_menu_app_set_source_action (app, source_id, + g_variant_new ("(uxs)", count, 0, "")); +} + +/** + * messaging_menu_app_set_source_time: + * @app: a #MessagingMenuApp + * @source_id: a source id + * @time: the new time for the source + * + * Updates the time of @source_id to @time. + * + * Note that the time is only displayed if the source does not also have a + * count associated with it. + */ +void +messaging_menu_app_set_source_time (MessagingMenuApp *app, + const gchar *source_id, + gint64 time) +{ + messaging_menu_app_set_source_action (app, source_id, + g_variant_new ("(uxs)", 0, time, "")); +} + +/** + * messaging_menu_app_set_source_string: + * @app: a #MessagingMenuApp + * @source_id: a source id + * @string: the new string for the source + * + * Updates the string displayed next to @source_id to @str. + * + * Note that the string is only displayed if the source does not also have a + * count or time associated with it. + */ +void +messaging_menu_app_set_source_string (MessagingMenuApp *app, + const gchar *source_id, + const gchar *str) +{ + messaging_menu_app_set_source_action (app, source_id, + g_variant_new ("(uxs)", 0, 0, str)); +} + +/** + * messaging_menu_app_draw_attention: + * @app: a #MessagingMenuApp + * @source_id: a source id + * + * Indicates that @source_id has important unread messages. Currently, this + * means that the messaging menu's envelope icon will turn blue. + * + * Use messaging_menu_app_remove_attention() to stop indicating that the source + * needs attention. + */ +void +messaging_menu_app_draw_attention (MessagingMenuApp *app, + const gchar *source_id) +{ + g_warning ("%s: not yet implemented", G_STRFUNC); +} + +/** + * messaging_menu_app_remove_attention: + * @app: a #MessagingMenuApp + * @source_id: a source id + * + * Stop indicating that @source_id needs attention. + * + * Use messaging_menu_app_draw_attention() to make @source_id draw attention + * again. + */ +void +messaging_menu_app_remove_attention (MessagingMenuApp *app, + const gchar *source_id) +{ + g_warning ("%s: not yet implemented", G_STRFUNC); +} diff --git a/libmessaging-menu/messaging-menu.h b/libmessaging-menu/messaging-menu.h new file mode 100644 index 0000000..7ce2981 --- /dev/null +++ b/libmessaging-menu/messaging-menu.h @@ -0,0 +1,130 @@ +/* + * Copyright 2012 Canonical Ltd. + * + * 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 . + * + * Authors: + * Lars Uebernickel + */ + +#ifndef __messaging_menu_h__ +#define __messaging_menu_h__ + +#include + +G_BEGIN_DECLS + +#define MESSAGING_MENU_TYPE_APP messaging_menu_app_get_type() +#define MESSAGING_MENU_APP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MESSAGING_MENU_TYPE_APP, MessagingMenuApp)) +#define MESSAGING_MENU_APP_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), MESSAGING_MENU_TYPE_APP, MessagingMenuAppClass)) +#define MESSAGING_MENU_IS_APP(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MESSAGING_MENU_TYPE_APP)) + +typedef enum { + MESSAGING_MENU_STATUS_AVAILABLE, + MESSAGING_MENU_STATUS_AWAY, + MESSAGING_MENU_STATUS_BUSY, + MESSAGING_MENU_STATUS_HIDDEN, + MESSAGING_MENU_STATUS_OFFLINE +} MessagingMenuStatus; + + +typedef GObjectClass MessagingMenuAppClass; +typedef struct _MessagingMenuApp MessagingMenuApp; + +GType messaging_menu_app_get_type (void) G_GNUC_CONST; + +MessagingMenuApp * messaging_menu_app_new (const gchar *desktop_id); + +void messaging_menu_app_register (MessagingMenuApp *app); +void messaging_menu_app_unregister (MessagingMenuApp *app); + +void messaging_menu_app_set_status (MessagingMenuApp *app, + MessagingMenuStatus status); + +void messaging_menu_app_insert_source (MessagingMenuApp *app, + gint position, + const gchar *id, + GIcon *icon, + const gchar *label); + +void messaging_menu_app_append_source (MessagingMenuApp *app, + const gchar *id, + GIcon *icon, + const gchar *label); + +void messaging_menu_app_insert_source_with_count (MessagingMenuApp *app, + gint position, + const gchar *id, + GIcon *icon, + const gchar *label, + guint count); + +void messaging_menu_app_append_source_with_count (MessagingMenuApp *app, + const gchar *id, + GIcon *icon, + const gchar *label, + guint count); + +void messaging_menu_app_insert_source_with_time (MessagingMenuApp *app, + gint position, + const gchar *id, + GIcon *icon, + const gchar *label, + gint64 time); + +void messaging_menu_app_append_source_with_time (MessagingMenuApp *app, + const gchar *id, + GIcon *icon, + const gchar *label, + gint64 time); + +void messaging_menu_app_append_source_with_string (MessagingMenuApp *app, + const gchar *id, + GIcon *icon, + const gchar *label, + const gchar *str); + +void messaging_menu_app_insert_source_with_string (MessagingMenuApp *app, + gint position, + const gchar *id, + GIcon *icon, + const gchar *label, + const gchar *str); + +void messaging_menu_app_remove_source (MessagingMenuApp *app, + const gchar *source_id); + +gboolean messaging_menu_app_has_source (MessagingMenuApp *app, + const gchar *source_id); + +void messaging_menu_app_set_source_count (MessagingMenuApp *app, + const gchar *source_id, + guint count); + +void messaging_menu_app_set_source_time (MessagingMenuApp *app, + const gchar *source_id, + gint64 time); + +void messaging_menu_app_set_source_string (MessagingMenuApp *app, + const gchar *source_id, + const gchar *str); + +void messaging_menu_app_draw_attention (MessagingMenuApp *app, + const gchar *source_id); + +void messaging_menu_app_remove_attention (MessagingMenuApp *app, + const gchar *source_id); + +G_END_DECLS + +#endif diff --git a/libmessaging-menu/messaging-menu.pc.in b/libmessaging-menu/messaging-menu.pc.in new file mode 100644 index 0000000..486300f --- /dev/null +++ b/libmessaging-menu/messaging-menu.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@/messaging-menu + +Name: Messaging Menu Library +Description: Messaging Menu client library +Version: @VERSION@ +Requires: gio-unix-2.0 +Libs: -L${libdir} -lmessaging-menu +Cflags: -I${includedir} -- cgit v1.2.3 From ac1a11bdf1df0efb426654cfe6b7ad4d5deb3815 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Fri, 15 Jun 2012 15:03:01 +0200 Subject: Check parameter types in public API --- libmessaging-menu/messaging-menu.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libmessaging-menu/messaging-menu.c b/libmessaging-menu/messaging-menu.c index 5b786af..6d2eab5 100644 --- a/libmessaging-menu/messaging-menu.c +++ b/libmessaging-menu/messaging-menu.c @@ -265,6 +265,8 @@ messaging_menu_app_new (const gchar *desktop_id) void messaging_menu_app_register (MessagingMenuApp *app) { + g_return_if_fail (MESSAGING_MENU_IS_APP (app)); + app->registered = TRUE; /* state will be synced right after connecting to the service */ @@ -290,6 +292,8 @@ messaging_menu_app_register (MessagingMenuApp *app) void messaging_menu_app_unregister (MessagingMenuApp *app) { + g_return_if_fail (MESSAGING_MENU_IS_APP (app)); + app->registered = FALSE; /* state will be synced right after connecting to the service */ -- cgit v1.2.3 From 40c73ac73cb2e45136c6820086f901ea1cf72874 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Fri, 15 Jun 2012 15:08:35 +0200 Subject: libmessaging-menu: add source name detail to "active-source" signal --- libmessaging-menu/messaging-menu.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libmessaging-menu/messaging-menu.c b/libmessaging-menu/messaging-menu.c index 6d2eab5..d848651 100644 --- a/libmessaging-menu/messaging-menu.c +++ b/libmessaging-menu/messaging-menu.c @@ -128,7 +128,8 @@ messaging_menu_app_class_init (MessagingMenuAppClass *class) signals[ACTIVATE_SOURCE] = g_signal_new ("activate-source", MESSAGING_MENU_TYPE_APP, - G_SIGNAL_RUN_FIRST, + G_SIGNAL_RUN_FIRST | + G_SIGNAL_DETAILED, 0, NULL, NULL, g_cclosure_marshal_VOID__STRING, @@ -324,9 +325,10 @@ source_action_activated (GSimpleAction *action, gpointer user_data) { MessagingMenuApp *app = user_data; + const gchar *name = g_action_get_name (G_ACTION (action)); + GQuark q = g_quark_from_string (name); - g_signal_emit (app, signals[ACTIVATE_SOURCE], 0, - g_action_get_name (G_ACTION (action))); + g_signal_emit (app, signals[ACTIVATE_SOURCE], q, name); } static void -- cgit v1.2.3 From feffbc694e36abdf24cc2b744fa3c2ff488bc3b8 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 18 Jun 2012 15:02:34 +0200 Subject: tests: pull generated files from the build directory --- test/Makefile.am | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/Makefile.am b/test/Makefile.am index 1d28dc4..f2c86d9 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -41,7 +41,7 @@ lib_LTLIBRARIES = \ libindicator_messages_service_la_HEADERS = \ $(top_srcdir)/src/default-applications.h \ $(top_srcdir)/src/messages-service-dbus.h \ - $(top_srcdir)/src/gen-messages-service.xml.h \ + $(top_builddir)/src/gen-messages-service.xml.h \ $(top_srcdir)/src/im-menu-item.h \ $(top_srcdir)/src/app-menu-item.h \ $(top_srcdir)/src/launcher-menu-item.h \ @@ -54,7 +54,7 @@ libindicator_messages_service_la_SOURCES = \ $(top_srcdir)/src/default-applications.c \ $(top_srcdir)/src/messages-service.c \ $(top_srcdir)/src/messages-service-dbus.c \ - $(top_srcdir)/src/gen-messages-service.xml.c \ + $(top_builddir)/src/gen-messages-service.xml.c \ $(top_srcdir)/src/im-menu-item.c \ $(top_srcdir)/src/app-menu-item.c \ $(top_srcdir)/src/launcher-menu-item.c \ @@ -67,6 +67,7 @@ libindicator_messages_service_ladir = \ libindicator_messages_service_la_CFLAGS = \ $(APPLET_CFLAGS) \ $(COVERAGE_CFLAGS) \ + -I$(top_builddir)/src \ -Wall \ -Wl,-Bsymbolic-functions \ -Wl,-z,defs \ -- cgit v1.2.3 From 787dff35a9a9e0c491e960754b8bbdeb46ae800c Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 25 Jun 2012 16:40:26 +0200 Subject: Put launcher and shortcut menu items into the same gmenu section --- src/app-section.c | 58 +++++++++++++++++++------------------------------- src/app-section.h | 1 - src/messages-service.c | 6 +----- 3 files changed, 23 insertions(+), 42 deletions(-) diff --git a/src/app-section.c b/src/app-section.c index b59bfc1..7bbbbbb 100644 --- a/src/app-section.c +++ b/src/app-section.c @@ -207,13 +207,25 @@ nick_activate_cb (GSimpleAction *action, } } +static void +g_menu_item_set_icon (GMenuItem *item, + GIcon *icon) +{ + gchar *iconstr; + + iconstr = g_icon_to_string (icon); + g_menu_item_set_attribute (item, INDICATOR_MENU_ATTRIBUTE_ICON_NAME, "s", iconstr); + + g_free (iconstr); +} + static void app_section_set_app_info (AppSection *self, GDesktopAppInfo *appinfo) { AppSectionPrivate *priv = self->priv; GSimpleAction *launch; - gchar *label; + GMenuItem *item; g_return_if_fail (priv->appinfo == NULL); @@ -228,10 +240,9 @@ app_section_set_app_info (AppSection *self, g_signal_connect (launch, "activate", G_CALLBACK (activate_cb), self); g_simple_action_group_insert (priv->static_shortcuts, G_ACTION (launch)); - if (priv->unreadcount > 0) - label = g_strdup_printf("%s (%d)", app_section_get_name (self), priv->unreadcount); - else - label = g_strdup(app_section_get_name (self)); + item = g_menu_item_new (g_app_info_get_name (G_APP_INFO (priv->appinfo)), "launch"); + g_menu_item_set_icon (item, g_app_info_get_icon (G_APP_INFO (priv->appinfo))); + g_menu_append_item (priv->menu, item); /* Start to build static shortcuts */ priv->ids = indicator_desktop_shortcuts_new(g_desktop_app_info_get_filename (priv->appinfo), "Messaging Menu"); @@ -258,7 +269,6 @@ app_section_set_app_info (AppSection *self, g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_APPINFO]); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACTIONS]); - g_free(label); g_object_unref (launch); } @@ -338,27 +348,6 @@ app_section_get_app_info (AppSection *self) return G_APP_INFO (priv->appinfo); } -GMenuItem * -app_section_create_menu_item (AppSection *self) -{ - AppSectionPrivate *priv = self->priv; - GMenuItem *item; - const gchar *name; - gchar *iconstr; - - g_return_val_if_fail (priv->appinfo != NULL, NULL); - - name = g_app_info_get_name (G_APP_INFO (priv->appinfo)); - iconstr = g_icon_to_string (g_app_info_get_icon (G_APP_INFO (priv->appinfo))); - - item = g_menu_item_new (name, "launch"); - g_menu_item_set_attribute (item, INDICATOR_MENU_ATTRIBUTE_ICON_NAME, "s", iconstr); - g_menu_item_set_section (item, G_MENU_MODEL (priv->menu)); - - g_free(iconstr); - return item; -} - static void application_vanished (GDBusConnection *bus, const gchar *name, @@ -388,14 +377,8 @@ app_section_set_object_path (AppSection *self, { AppSectionPrivate *priv = self->priv; - if (priv->name_watch_id) - g_bus_unwatch_name (priv->name_watch_id); - g_clear_object (&priv->actions); - - if (priv->remote_menu) { - g_menu_remove (priv->menu, 0); - g_clear_object (&priv->remote_menu); - } + g_object_freeze_notify (G_OBJECT (self)); + app_section_unset_object_path (self); priv->actions = G_ACTION_GROUP (g_dbus_action_group_get (bus, bus_name, object_path)); priv->remote_menu = G_MENU_MODEL (g_dbus_menu_model_get (bus, bus_name, object_path)); @@ -407,6 +390,7 @@ app_section_set_object_path (AppSection *self, self, NULL); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACTIONS]); + g_object_thaw_notify (G_OBJECT (self)); } /* @@ -429,7 +413,9 @@ app_section_unset_object_path (AppSection *self) g_clear_object (&priv->actions); if (priv->remote_menu) { - g_menu_remove (priv->menu, 0); + /* the last menu item points is linked to the app's menumodel */ + gint n_items = g_menu_model_get_n_items (G_MENU_MODEL (priv->menu)); + g_menu_remove (priv->menu, n_items -1); g_clear_object (&priv->remote_menu); } diff --git a/src/app-section.h b/src/app-section.h index a81b4df..36e091d 100644 --- a/src/app-section.h +++ b/src/app-section.h @@ -56,7 +56,6 @@ const gchar * app_section_get_desktop (AppSection * appitem); GActionGroup * app_section_get_actions (AppSection *self); GMenuModel * app_section_get_menu (AppSection *appitem); GAppInfo * app_section_get_app_info (AppSection *appitem); -GMenuItem * app_section_create_menu_item (AppSection *self); void app_section_set_object_path (AppSection *self, GDBusConnection *bus, const gchar *bus_name, diff --git a/src/messages-service.c b/src/messages-service.c index e302219..805e684 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -97,8 +97,6 @@ add_application (const gchar *desktop_id) section = g_hash_table_lookup (applications, id); if (!section) { - GMenuItem *item; - section = app_section_new(appinfo); g_hash_table_insert (applications, g_strdup (id), section); @@ -106,10 +104,8 @@ add_application (const gchar *desktop_id) g_signal_connect (section, "notify::actions", G_CALLBACK (actions_changed), NULL); - item = app_section_create_menu_item (section); /* TODO insert it at the right position (alphabetically by application name) */ - g_menu_insert_item (menu, 2, item); - g_object_unref (item); + g_menu_insert_section (menu, 2, NULL, app_section_get_menu (section)); } g_free (id); -- cgit v1.2.3 From 27dbefcc92d9c91bb090f94ba64910867baa605b Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 25 Jun 2012 16:52:05 +0200 Subject: Set action namespace on application sections --- src/messages-service.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/messages-service.c b/src/messages-service.c index 805e684..fcceb58 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -97,6 +97,8 @@ add_application (const gchar *desktop_id) section = g_hash_table_lookup (applications, id); if (!section) { + GMenuItem *menuitem; + section = app_section_new(appinfo); g_hash_table_insert (applications, g_strdup (id), section); @@ -105,7 +107,10 @@ add_application (const gchar *desktop_id) G_CALLBACK (actions_changed), NULL); /* TODO insert it at the right position (alphabetically by application name) */ - g_menu_insert_section (menu, 2, NULL, app_section_get_menu (section)); + menuitem = g_menu_item_new_section (NULL, app_section_get_menu (section)); + g_menu_item_set_attribute (menuitem, "action-namespace", "s", id); + g_menu_insert_item (menu, 2, menuitem); + g_object_unref (menuitem); } g_free (id); -- cgit v1.2.3 From b942b3f993ce9bc89ff04ad7a79878902fd1922f Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 25 Jun 2012 16:52:48 +0200 Subject: Set user_data that action handlers expect --- src/messages-service.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/messages-service.c b/src/messages-service.c index fcceb58..203156e 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -336,7 +336,7 @@ main (int argc, char ** argv) } actions = g_simple_action_group_new (); - g_simple_action_group_add_entries (actions, entries, G_N_ELEMENTS (entries), NULL); + g_simple_action_group_add_entries (actions, entries, G_N_ELEMENTS (entries), dbus_interface); action_muxer = g_action_muxer_new (); g_action_muxer_insert (action_muxer, NULL, G_ACTION_GROUP (actions)); -- cgit v1.2.3 From 3da349e33e434c13a27f956374e97c75ef0480a0 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 25 Jun 2012 22:40:59 +0200 Subject: Remove status providers Applications will be able to set and retrieve status through libmessaging-menu and telepathy. --- configure.ac | 23 -- po/POTFILES.in | 1 - src/Makefile.am | 193 +-------- ...indicator-messages-status-provider-0.5.pc.in.in | 15 - src/messages-service.c | 54 ++- src/status-items.c | 323 --------------- src/status-items.h | 36 -- src/status-provider-emesene.c | 348 ----------------- src/status-provider-emesene.h | 56 --- src/status-provider-mc5.c | 308 --------------- src/status-provider-mc5.h | 56 --- src/status-provider-mc5.list | 1 - src/status-provider-pidgin.c | 433 --------------------- src/status-provider-pidgin.h | 56 --- src/status-provider-pidgin.list | 1 - src/status-provider-telepathy.c | 385 ------------------ src/status-provider-telepathy.h | 56 --- src/status-provider-telepathy.list | 1 - src/status-provider.c | 101 ----- src/status-provider.h | 81 ---- test/Makefile.am | 8 +- 21 files changed, 53 insertions(+), 2483 deletions(-) delete mode 100644 src/indicator-messages-status-provider-0.5.pc.in.in delete mode 100644 src/status-items.c delete mode 100644 src/status-items.h delete mode 100644 src/status-provider-emesene.c delete mode 100644 src/status-provider-emesene.h delete mode 100644 src/status-provider-mc5.c delete mode 100644 src/status-provider-mc5.h delete mode 100644 src/status-provider-mc5.list delete mode 100644 src/status-provider-pidgin.c delete mode 100644 src/status-provider-pidgin.h delete mode 100644 src/status-provider-pidgin.list delete mode 100644 src/status-provider-telepathy.c delete mode 100644 src/status-provider-telepathy.h delete mode 100644 src/status-provider-telepathy.list delete mode 100644 src/status-provider.c delete mode 100644 src/status-provider.h diff --git a/configure.ac b/configure.ac index 9ef2438..11c9bd8 100644 --- a/configure.ac +++ b/configure.ac @@ -59,28 +59,6 @@ AC_SUBST(APPLET_LIBS) GLIB_GSETTINGS -########################### -# Status Provider Deps -########################### - -PKG_CHECK_MODULES(STATUS_PROVIDER_PIDGIN, dbus-glib-1) -AC_SUBST(STATUS_PROVIDER_PIDGIN_CFLAGS) -AC_SUBST(STATUS_PROVIDER_PIDGIN_LIBS) - -PKG_CHECK_MODULES(STATUS_PROVIDER_TELEPATHY, dbus-glib-1) -AC_SUBST(STATUS_PROVIDER_TELEPATHY_CFLAGS) -AC_SUBST(STATUS_PROVIDER_TELEPATHY_LIBS) - -TELEPATHYGLIB_REQUIRED_VERSION=0.9.0 -PKG_CHECK_MODULES(STATUS_PROVIDER_MC5, dbus-glib-1 - telepathy-glib >= $TELEPATHYGLIB_REQUIRED_VERSION) -AC_SUBST(STATUS_PROVIDER_MC5_CFLAGS) -AC_SUBST(STATUS_PROVIDER_MC5_LIBS) - -PKG_CHECK_MODULES(STATUS_PROVIDER_EMESENE, dbus-glib-1) -AC_SUBST(STATUS_PROVIDER_EMESENE_CFLAGS) -AC_SUBST(STATUS_PROVIDER_EMESENE_LIBS) - ########################### # gcov coverage reporting ########################### @@ -179,7 +157,6 @@ AM_GLIB_GNU_GETTEXT AC_OUTPUT([ Makefile src/Makefile -src/indicator-messages-status-provider-0.5.pc.in data/Makefile data/icons/Makefile data/icons/16x16/Makefile diff --git a/po/POTFILES.in b/po/POTFILES.in index 39d3ce7..21cd0b1 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -2,4 +2,3 @@ src/messages-service-dbus.c src/indicator-messages.c src/messages-service.c -src/status-items.c diff --git a/src/Makefile.am b/src/Makefile.am index 183d729..95a6258 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -45,8 +45,6 @@ indicator_messages_service_SOURCES = \ app-section.c \ app-section.h \ dbus-data.h \ - status-items.c \ - status-items.h \ gactionmuxer.c \ gactionmuxer.h @@ -58,12 +56,10 @@ indicator_messages_service_CFLAGS = \ -Wl,-z,defs \ -Wl,--as-needed \ -Werror \ - -DG_LOG_DOMAIN=\"Indicator-Messages\" \ - -DSTATUS_PROVIDER_DIR=\"$(STATUS_PROVIDER_DIR)\" + -DG_LOG_DOMAIN=\"Indicator-Messages\" indicator_messages_service_LDADD = \ - $(APPLET_LIBS) \ - libindicator-messages-status-provider.la + $(APPLET_LIBS) indicator_messages_service_LDFLAGS = \ $(COVERAGE_LDFLAGS) @@ -85,191 +81,6 @@ BUILT_SOURCES += \ 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 deleted file mode 100644 index 3fe4cf2..0000000 --- a/src/indicator-messages-status-provider-0.5.pc.in.in +++ /dev/null @@ -1,15 +0,0 @@ -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 203156e..9f4cddc 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -33,7 +33,6 @@ with this program. If not, see . #include "app-section.h" #include "dbus-data.h" #include "messages-service-dbus.h" -#include "status-items.h" #include "gactionmuxer.h" static IndicatorService * service = NULL; @@ -220,6 +219,22 @@ clear_action_activate (GSimpleAction *simple, message_service_dbus_set_attention(msg_service, FALSE); } +static void +radio_item_activate (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + g_action_change_state (G_ACTION (action), parameter); +} + +static void +change_status (GSimpleAction *action, + GVariant *value, + gpointer user_data) +{ + g_message ("changing status to %s", g_variant_get_string (value, NULL)); +} + static void clear_action_handler (MessageServiceDbus *msd, gboolean attention, @@ -302,12 +317,42 @@ unregister_application (MessageServiceDbus *msd, g_strfreev (applications); } +static void +g_menu_append_with_icon (GMenu *menu, + const gchar *label, + const gchar *icon_name, + const gchar *detailed_action) +{ + GMenuItem *item; + + item = g_menu_item_new (label, detailed_action); + g_menu_item_set_attribute (item, INDICATOR_MENU_ATTRIBUTE_ICON_NAME, "s", icon_name); + + g_menu_append_item (menu, item); + g_object_unref (item); +} + +GMenuModel * +create_status_section () +{ + GMenu *menu; + + menu = g_menu_new (); + g_menu_append_with_icon (menu, _("Available"), "user-available", "status::available"); + g_menu_append_with_icon (menu, _("Away"), "user-away", "status::away"); + g_menu_append_with_icon (menu, _("Busy"), "user-busy", "status::busy"); + g_menu_append_with_icon (menu, _("Invisible"), "user-invisible", "status::invisible"); + g_menu_append_with_icon (menu, _("Offline"), "user-offline", "status::offline"); + + return G_MENU_MODEL (menu); +} + int main (int argc, char ** argv) { GError *error = NULL; GActionEntry entries[] = { - { "status", NULL, "s", "'offline'", NULL }, + { "status", radio_item_activate, "s", "'offline'", change_status }, { "clear", clear_action_activate } }; GMenuModel *status_items; @@ -357,9 +402,8 @@ main (int argc, char ** argv) g_signal_connect (dbus_interface, MESSAGE_SERVICE_DBUS_SIGNAL_UNREGISTER_APPLICATION, G_CALLBACK (unregister_application), NULL); - status_items = status_items_build (g_action_map_lookup_action (G_ACTION_MAP (actions), "status")); - menu = g_menu_new (); + status_items = create_status_section (); g_menu_append_section (menu, _("Status"), status_items); g_menu_append (menu, _("Clear"), "clear"); @@ -382,7 +426,7 @@ main (int argc, char ** argv) g_main_loop_run(mainloop); /* Clean up */ - status_items_cleanup(); + g_object_unref (status_items); g_object_unref (settings); g_hash_table_unref (applications); return 0; diff --git a/src/status-items.c b/src/status-items.c deleted file mode 100644 index a2e3a02..0000000 --- a/src/status-items.c +++ /dev/null @@ -1,323 +0,0 @@ -/* -Code to build and maintain the status adjustment menuitems. - -Copyright 2011 Canonical Ltd. - -Authors: - Ted Gould - -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 . -*/ - -#include -#include -#include - -#include "status-items.h" -#include "status-provider.h" -#include "dbus-data.h" - -static const gchar * status_ids [STATUS_PROVIDER_STATUS_LAST] = { - /* STATUS_PROVIDER_STATUS_ONLINE, */ "available", - /* STATUS_PROVIDER_STATUS_AWAY, */ "away", - /* STATUS_PROVIDER_STATUS_DND */ "busy", - /* STATUS_PROVIDER_STATUS_INVISIBLE */ "invisible", - /* STATUS_PROVIDER_STATUS_OFFLINE, */ "offline", - /* STATUS_PROVIDER_STATUS_DISCONNECTED*/ "offline" -}; - -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 (GSimpleAction *action, - GVariant *value, - gpointer user_data); - -/* Globals */ -static StatusProviderStatus current_status = STATUS_PROVIDER_STATUS_DISCONNECTED; -static GMenu * menu; -static GAction *status_action; -static GList * status_providers = NULL; - -/* Build the inital status items and start kicking off the async code - for handling all the statuses */ -GMenuModel * -status_items_build (GAction *action) -{ - int i; - menu = g_menu_new (); - - status_action = action; - g_signal_connect (action, "change-state", G_CALLBACK (user_status_change), NULL); - - for (i = STATUS_PROVIDER_STATUS_ONLINE; i < STATUS_PROVIDER_STATUS_DISCONNECTED; i++) { - GMenuItem *item = g_menu_item_new (_(status_strings[i]), NULL); - - g_menu_item_set_action_and_target (item, g_action_get_name (action), "s", status_ids[i]); - - g_menu_item_set_attribute (item, INDICATOR_MENU_ATTRIBUTE_ICON_NAME, "s", status_icons[i]); - g_menu_item_set_attribute (item, INDICATOR_MENU_ATTRIBUTE_VISIBLE, "b", TRUE); - g_menu_item_set_attribute (item, INDICATOR_MENU_ATTRIBUTE_ENABLED, "b", FALSE); - - g_menu_append_item (menu, item); - g_object_unref (item); - } - - 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 G_MENU_MODEL (menu); -} - -/* 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; - - g_action_change_state (status_action, g_variant_new_string (status_ids[current_status])); - - return; -} - -/* Handle the user requesting a status change */ -static void -user_status_change (GSimpleAction *action, - GVariant *value, - gpointer user_data) -{ - const gchar *status_id; - int i; - StatusProviderStatus status = STATUS_PROVIDER_STATUS_DISCONNECTED; - GList * provider; - - g_return_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING)); - - status_id = g_variant_get_string (value, NULL); - - for (i = STATUS_PROVIDER_STATUS_ONLINE; i < STATUS_PROVIDER_STATUS_DISCONNECTED; i++) { - if (!strcmp (status_id, status_ids [i])) { - status = i; - break; - } - } - - /* 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 = dir; - - /* load the module */ - GModule * module = NULL; - if (g_file_test(provider, G_FILE_TEST_EXISTS)) { - g_debug("Loading status provider: %s", provider); - module = g_module_open(provider, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL); - if (module == NULL) { - g_warning("Unable to open module: %s", provider); - } - } - - /* find the status provider's GType */ - GType provider_type = 0; - if (module != NULL) { - 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); - } else { - provider_type = type_func(); - if (provider_type == 0) { - g_warning("Unable to create type from: %s", provider); - } - } - } - - /* instantiate the status provider */ - StatusProvider * sprovider = NULL; - if (provider_type != 0) { - sprovider = STATUS_PROVIDER(g_object_new(provider_type, NULL)); - if (sprovider == NULL) { - g_warning("Unable to build provider from: %s", provider); - } - } - - /* use the provider */ - if (sprovider != NULL) { - /* 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 closed automatically. */ - g_object_set_data_full(G_OBJECT(sprovider), - "status-provider-module", - module, module_destroy_in_idle); - module = NULL; /* don't close module in this func */ - - status_providers = g_list_prepend(status_providers, sprovider); - - /* Force an update to ensure a consistent state */ - update_status(); - } - - /* cleanup */ - if (module != NULL) - g_module_close(module); - g_free(provider); - return FALSE; /* only call this idle func once */ -} diff --git a/src/status-items.h b/src/status-items.h deleted file mode 100644 index ff35dfc..0000000 --- a/src/status-items.h +++ /dev/null @@ -1,36 +0,0 @@ -/* -Code to build and maintain the status adjustment menuitems. - -Copyright 2011 Canonical Ltd. - -Authors: - Ted Gould - -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 . -*/ - -#ifndef __STATUS_ITEMS_H__ -#define __STATUS_ITEMS_H__ - -#include - -G_BEGIN_DECLS - -GMenuModel * status_items_build (GAction *action); -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 deleted file mode 100644 index 5aa6698..0000000 --- a/src/status-provider-emesene.c +++ /dev/null @@ -1,348 +0,0 @@ -/* -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 - -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 . -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "status-provider.h" -#include "status-provider-emesene.h" - -#include - -typedef enum { - EM_STATUS_ONLINE, - EM_STATUS_INVISIBLE, - EM_STATUS_BUSY, - EM_STATUS_AWAY, - EM_STATUS_IDLE, - EM_STATUS_OFFLINE -} em_status_t; - -static const StatusProviderStatus em_to_sp_map[] = { - /* EM_STATUS_ONLINE, */ STATUS_PROVIDER_STATUS_ONLINE, - /* EM_STATUS_INVISIBLE, */ STATUS_PROVIDER_STATUS_INVISIBLE, - /* EM_STATUS_BUSY, */ STATUS_PROVIDER_STATUS_DND, - /* EM_STATUS_AWAY, */ STATUS_PROVIDER_STATUS_AWAY, - /* EM_STATUS_IDLE, */ STATUS_PROVIDER_STATUS_AWAY, - /* EM_STATUS_OFFLINE, */ STATUS_PROVIDER_STATUS_OFFLINE -}; - -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_INVISIBLE, - /* 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 deleted file mode 100644 index 2309684..0000000 --- a/src/status-provider-emesene.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -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 - -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 . -*/ - -#ifndef __STATUS_PROVIDER_EMESENE_H__ -#define __STATUS_PROVIDER_EMESENE_H__ - -#include -#include - -#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 deleted file mode 100644 index 3f23565..0000000 --- a/src/status-provider-mc5.c +++ /dev/null @@ -1,308 +0,0 @@ -/* -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 - -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 . -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#include "status-provider.h" -#include "status-provider-mc5.h" -#include "status-provider-mc5-marshal.h" - -#include -#include - -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_OFFLINE; - 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_OFFLINE; - 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_OFFLINE; - } - - 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 deleted file mode 100644 index 4d5659d..0000000 --- a/src/status-provider-mc5.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -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 - -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 . -*/ - -#ifndef __STATUS_PROVIDER_MC5_H__ -#define __STATUS_PROVIDER_MC5_H__ - -#include -#include - -#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 deleted file mode 100644 index 5ab45bf..0000000 --- a/src/status-provider-mc5.list +++ /dev/null @@ -1 +0,0 @@ -VOID:UINT,STRING diff --git a/src/status-provider-pidgin.c b/src/status-provider-pidgin.c deleted file mode 100644 index 6c73d56..0000000 --- a/src/status-provider-pidgin.c +++ /dev/null @@ -1,433 +0,0 @@ -/* -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 - -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 . -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "status-provider.h" -#include "status-provider-pidgin.h" -#include "status-provider-pidgin-marshal.h" - -#include - -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 deleted file mode 100644 index 54b1718..0000000 --- a/src/status-provider-pidgin.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -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 - -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 . -*/ - -#ifndef __STATUS_PROVIDER_PIDGIN_H__ -#define __STATUS_PROVIDER_PIDGIN_H__ - -#include -#include - -#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 deleted file mode 100644 index 1f953dd..0000000 --- a/src/status-provider-pidgin.list +++ /dev/null @@ -1 +0,0 @@ -VOID:INT,INT diff --git a/src/status-provider-telepathy.c b/src/status-provider-telepathy.c deleted file mode 100644 index 948e965..0000000 --- a/src/status-provider-telepathy.c +++ /dev/null @@ -1,385 +0,0 @@ -/* -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 - -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 . -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "status-provider.h" -#include "status-provider-telepathy.h" -#include "status-provider-telepathy-marshal.h" - -#include - -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, &mcstatus, - 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 deleted file mode 100644 index a67ee40..0000000 --- a/src/status-provider-telepathy.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -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 - -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 . -*/ - -#ifndef __STATUS_PROVIDER_TELEPATHY_H__ -#define __STATUS_PROVIDER_TELEPATHY_H__ - -#include -#include - -#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 deleted file mode 100644 index 5ab45bf..0000000 --- a/src/status-provider-telepathy.list +++ /dev/null @@ -1 +0,0 @@ -VOID:UINT,STRING diff --git a/src/status-provider.c b/src/status-provider.c deleted file mode 100644 index 1139e54..0000000 --- a/src/status-provider.c +++ /dev/null @@ -1,101 +0,0 @@ -/* -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 - -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 . -*/ - -#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 deleted file mode 100644 index 45433fc..0000000 --- a/src/status-provider.h +++ /dev/null @@ -1,81 +0,0 @@ -/* -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 - -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 . -*/ - -#ifndef __STATUS_PROVIDER_H__ -#define __STATUS_PROVIDER_H__ - -#include -#include - -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 diff --git a/test/Makefile.am b/test/Makefile.am index ca4965e..d0ea499 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -43,8 +43,6 @@ libindicator_messages_service_la_SOURCES = \ $(top_srcdir)/src/gen-messages-service.xml.h \ $(top_srcdir)/src/app-section.c \ $(top_srcdir)/src/app-section.h \ - $(top_srcdir)/src/status-items.c \ - $(top_srcdir)/src/status-items.h \ $(top_srcdir)/src/gactionmuxer.c \ $(top_srcdir)/src/gactionmuxer.h $(top_srcdir)/src/dbus-data.h @@ -60,12 +58,10 @@ libindicator_messages_service_la_CFLAGS = \ -Wl,-z,defs \ -Wl,--as-needed \ -Werror \ - -DG_LOG_DOMAIN=\"Indicator-Messages\" \ - -DSTATUS_PROVIDER_DIR=\"$(STATUS_PROVIDER_DIR)\" + -DG_LOG_DOMAIN=\"Indicator-Messages\" libindicator_messages_service_la_LIBADD = \ - $(APPLET_LIBS) \ - $(top_builddir)/src/.libs/libindicator-messages-status-provider.la + $(APPLET_LIBS) libindicator_messages_service_la_LDFLAGS = \ $(COVERAGE_LDFLAGS) -- cgit v1.2.3 From e500cbf335ba59066db88088ff18a86a4b45113c Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 25 Jun 2012 22:45:55 +0200 Subject: messages-service.c: removee unused includes --- src/messages-service.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/messages-service.c b/src/messages-service.c index 9f4cddc..15ddc22 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -20,11 +20,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#include -#include -#include #include -#include +#include #include #include #include -- cgit v1.2.3 From cf241b32dd111b6b57ddd95bb06f3ad558c00a88 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 25 Jun 2012 23:05:01 +0200 Subject: messages-service.c: get session bus asynchronously --- src/messages-service-dbus.c | 11 +++++++++ src/messages-service-dbus.h | 1 + src/messages-service.c | 59 +++++++++++++++++++++++++++------------------ 3 files changed, 48 insertions(+), 23 deletions(-) diff --git a/src/messages-service-dbus.c b/src/messages-service-dbus.c index 3a39172..211b1f5 100644 --- a/src/messages-service-dbus.c +++ b/src/messages-service-dbus.c @@ -498,3 +498,14 @@ message_service_dbus_set_icon (MessageServiceDbus * self, gboolean hidden) } return; } + +GDBusConnection * +message_service_dbus_get_connection (MessageServiceDbus *msd) +{ + MessageServiceDbusPrivate * priv; + + g_return_val_if_fail (IS_MESSAGE_SERVICE_DBUS (msd), NULL); + + priv = MESSAGE_SERVICE_DBUS_GET_PRIVATE(msd); + return priv->connection; +} diff --git a/src/messages-service-dbus.h b/src/messages-service-dbus.h index f95b61b..63564b6 100644 --- a/src/messages-service-dbus.h +++ b/src/messages-service-dbus.h @@ -58,6 +58,7 @@ GType message_service_dbus_get_type (void); MessageServiceDbus * message_service_dbus_new (void); void message_service_dbus_set_attention (MessageServiceDbus * self, gboolean attention); void message_service_dbus_set_icon (MessageServiceDbus * self, gboolean hidden); +GDBusConnection * message_service_dbus_get_connection (MessageServiceDbus *msd); G_END_DECLS diff --git a/src/messages-service.c b/src/messages-service.c index 15ddc22..7be2274 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -35,7 +35,6 @@ with this program. If not, see . static IndicatorService * service = NULL; static GHashTable *applications; -static GDBusConnection *bus; static GSimpleActionGroup *actions; static GActionMuxer *action_muxer; static GMenu *menu; @@ -266,11 +265,14 @@ register_application (MessageServiceDbus *msd, { AppSection *section; gchar **applications; + GDBusConnection *bus; section = add_application (desktop_id); if (!section) return; + bus = message_service_dbus_get_connection (msd); + app_section_set_object_path (section, bus, sender, menu_path); /* remember this application in the settings key */ @@ -344,10 +346,41 @@ create_status_section () return G_MENU_MODEL (menu); } +static void +got_bus (GObject *object, + GAsyncResult * res, + gpointer user_data) +{ + GDBusConnection *bus; + GError *error = NULL; + + bus = g_bus_get_finish (res, &error); + if (!bus) { + g_warning ("unable to connect to the session bus: %s", error->message); + g_error_free (error); + return; + } + + g_dbus_connection_export_action_group (bus, INDICATOR_MESSAGES_DBUS_OBJECT, + G_ACTION_GROUP (action_muxer), &error); + if (error) { + g_warning ("unable to export action group on dbus: %s", error->message); + g_error_free (error); + return; + } + + g_dbus_connection_export_menu_model (bus, INDICATOR_MESSAGES_DBUS_OBJECT, + G_MENU_MODEL (menu), &error); + if (error) { + g_warning ("unable to export menu on dbus: %s", error->message); + g_error_free (error); + return; + } +} + int main (int argc, char ** argv) { - GError *error = NULL; GActionEntry entries[] = { { "status", radio_item_activate, "s", "'offline'", change_status }, { "clear", clear_action_activate } @@ -370,25 +403,13 @@ main (int argc, char ** argv) /* Bring up the service DBus interface */ dbus_interface = message_service_dbus_new(); - bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); - if (!bus) { - g_warning ("unable to connect to the session bus: %s", error->message); - g_error_free (error); - return 1; - } + g_bus_get (G_BUS_TYPE_SESSION, NULL, got_bus, NULL); actions = g_simple_action_group_new (); g_simple_action_group_add_entries (actions, entries, G_N_ELEMENTS (entries), dbus_interface); action_muxer = g_action_muxer_new (); g_action_muxer_insert (action_muxer, NULL, G_ACTION_GROUP (actions)); - g_dbus_connection_export_action_group (bus, INDICATOR_MESSAGES_DBUS_OBJECT, - G_ACTION_GROUP (action_muxer), &error); - if (error) { - g_warning ("unable to export action group on dbus: %s", error->message); - g_error_free (error); - return 1; - } g_signal_connect (dbus_interface, MESSAGE_SERVICE_DBUS_SIGNAL_ATTENTION_CHANGED, G_CALLBACK(clear_action_handler), @@ -404,14 +425,6 @@ main (int argc, char ** argv) g_menu_append_section (menu, _("Status"), status_items); g_menu_append (menu, _("Clear"), "clear"); - g_dbus_connection_export_menu_model (bus, INDICATOR_MESSAGES_DBUS_OBJECT, - G_MENU_MODEL (menu), &error); - if (error) { - g_warning ("unable to export menu on dbus: %s", error->message); - g_error_free (error); - return 1; - } - settings = g_settings_new ("com.canonical.indicator.messages"); applications = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); -- cgit v1.2.3 From f4c01bf86c886d8b534e14f05f813222d825f37c Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 25 Jun 2012 23:20:46 +0200 Subject: messages-service.c: get rid of some global variables --- src/messages-service.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/messages-service.c b/src/messages-service.c index 7be2274..f7f76c2 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -32,16 +32,12 @@ with this program. If not, see . #include "messages-service-dbus.h" #include "gactionmuxer.h" -static IndicatorService * service = NULL; static GHashTable *applications; static GSimpleActionGroup *actions; static GActionMuxer *action_muxer; static GMenu *menu; static GSettings *settings; -static GMainLoop * mainloop = NULL; - -static MessageServiceDbus * dbus_interface = NULL; static gchar * @@ -201,9 +197,10 @@ build_launchers (gpointer data) static void service_shutdown (IndicatorService * service, gpointer user_data) { + GMainLoop *mainloop = user_data; + g_warning("Shutting down service!"); g_main_loop_quit(mainloop); - return; } static void @@ -381,6 +378,9 @@ got_bus (GObject *object, int main (int argc, char ** argv) { + GMainLoop * mainloop = NULL; + IndicatorService * service = NULL; + MessageServiceDbus * dbus_interface = NULL; GActionEntry entries[] = { { "status", radio_item_activate, "s", "'offline'", change_status }, { "clear", clear_action_activate } @@ -390,9 +390,11 @@ main (int argc, char ** argv) /* Glib init */ g_type_init(); + mainloop = g_main_loop_new (NULL, FALSE); + /* 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); + g_signal_connect(service, INDICATOR_SERVICE_SIGNAL_SHUTDOWN, G_CALLBACK(service_shutdown), mainloop); /* Setting up i18n and gettext. Apparently, we need all of these. */ @@ -431,8 +433,6 @@ main (int argc, char ** argv) g_idle_add(build_launchers, NULL); - /* Let's run a mainloop */ - mainloop = g_main_loop_new(NULL, FALSE); g_main_loop_run(mainloop); /* Clean up */ -- cgit v1.2.3 From 82c080337fc3f420043dab2784f598472c7cfda0 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 25 Jun 2012 23:22:27 +0200 Subject: messages-service.c: fix memory leak --- src/messages-service.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/messages-service.c b/src/messages-service.c index f7f76c2..33ad237 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -373,6 +373,8 @@ got_bus (GObject *object, g_error_free (error); return; } + + g_object_unref (bus); } int -- cgit v1.2.3 From 106146172620ce24dc34575a3ad5237251a80407 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Tue, 26 Jun 2012 00:18:18 +0200 Subject: messages-service.c: move gsettings strv handling into gsettingsstrv.[ch] --- src/Makefile.am | 4 +- src/gsettingsstrv.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++ src/gsettingsstrv.h | 33 +++++++++++++++ src/messages-service.c | 51 ++---------------------- 4 files changed, 145 insertions(+), 49 deletions(-) create mode 100644 src/gsettingsstrv.c create mode 100644 src/gsettingsstrv.h diff --git a/src/Makefile.am b/src/Makefile.am index 95a6258..79fdee6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -46,7 +46,9 @@ indicator_messages_service_SOURCES = \ app-section.h \ dbus-data.h \ gactionmuxer.c \ - gactionmuxer.h + gactionmuxer.h \ + gsettingsstrv.c \ + gsettingsstrv.h indicator_messages_service_CFLAGS = \ $(APPLET_CFLAGS) \ diff --git a/src/gsettingsstrv.c b/src/gsettingsstrv.c new file mode 100644 index 0000000..cf889fa --- /dev/null +++ b/src/gsettingsstrv.c @@ -0,0 +1,106 @@ +/* + * Copyright 2012 Canonical Ltd. + * + * 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 . + * + * Authors: + * Lars Uebernickel + */ + +#include "gsettingsstrv.h" + +/** + * g_settings_strv_append_unique: + * @settings: a #GSettings object + * @key: the key at which @settings contains a string array + * @item: the string to append + * + * Appends @item to the string array at @key if that string array doesn't + * contain @item yet. + * + * Returns: TRUE if @item was added to the list, FALSE if it already existed. + */ +gboolean +g_settings_strv_append_unique (GSettings *settings, + const gchar *key, + const gchar *item) +{ + gchar **strv; + gchar **it; + gboolean add = TRUE; + + g_return_val_if_fail (G_IS_SETTINGS (settings), FALSE); + g_return_val_if_fail (key != NULL, FALSE); + g_return_val_if_fail (item != NULL, FALSE); + + strv = g_settings_get_strv (settings, key); + + for (it = strv; *it; it++) + { + if (g_str_equal (*it, item)) + { + add = FALSE; + break; + } + } + + if (add) + { + GVariantBuilder builder; + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("as")); + + for (it = strv; *it; it++) + g_variant_builder_add (&builder, "s", *it); + g_variant_builder_add (&builder, "s", item); + + g_settings_set_value (settings, key, g_variant_builder_end (&builder)); + } + + g_strfreev (strv); + return add; +} + +/** + * g_settings_strv_remove: + * @settings: a #GSettings object + * @key: the key at which @settings contains a string array + * @item: the string to remove + * + * Removes all occurences of @item in @key. + */ +void +g_settings_strv_remove (GSettings *settings, + const gchar *key, + const gchar *item) +{ + gchar **strv; + gchar **it; + GVariantBuilder builder; + + g_return_if_fail (G_IS_SETTINGS (settings)); + g_return_if_fail (key != NULL); + g_return_if_fail (item != NULL); + + strv = g_settings_get_strv (settings, key); + + g_variant_builder_init (&builder, (GVariantType *)"as"); + for (it = strv; *it; it++) + { + if (!g_str_equal (*it, item)) + g_variant_builder_add (&builder, "s", *it); + } + g_settings_set_value (settings, key, g_variant_builder_end (&builder)); + + g_strfreev (strv); +} diff --git a/src/gsettingsstrv.h b/src/gsettingsstrv.h new file mode 100644 index 0000000..accebda --- /dev/null +++ b/src/gsettingsstrv.h @@ -0,0 +1,33 @@ +/* + * Copyright 2012 Canonical Ltd. + * + * 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 . + * + * Authors: + * Lars Uebernickel + */ + +#ifndef __G_SETTINGS_STRV_H__ +#define __G_SETTINGS_STRV_H__ + +#include + +gboolean g_settings_strv_append_unique (GSettings *settings, + const gchar *key, + const gchar *item); + +void g_settings_strv_remove (GSettings *settings, + const gchar *key, + const gchar *item); + +#endif diff --git a/src/messages-service.c b/src/messages-service.c index 33ad237..f07ea68 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -31,6 +31,7 @@ with this program. If not, see . #include "dbus-data.h" #include "messages-service-dbus.h" #include "gactionmuxer.h" +#include "gsettingsstrv.h" static GHashTable *applications; @@ -237,22 +238,6 @@ clear_action_handler (MessageServiceDbus *msd, g_simple_action_set_enabled (action, attention); } -static gint -g_strv_find (gchar **str_array, - const gchar *key) -{ - gchar **it; - - g_return_val_if_fail (str_array != NULL, -1); - - for (it = str_array; *it; it++) { - if (!g_strcmp0 (key, *it)) - return it - str_array; - } - - return -1; -} - static void register_application (MessageServiceDbus *msd, const gchar *sender, @@ -261,7 +246,6 @@ register_application (MessageServiceDbus *msd, gpointer user_data) { AppSection *section; - gchar **applications; GDBusConnection *bus; section = add_application (desktop_id); @@ -272,22 +256,7 @@ register_application (MessageServiceDbus *msd, app_section_set_object_path (section, bus, sender, menu_path); - /* remember this application in the settings key */ - applications = g_settings_get_strv (settings, "applications"); - if (g_strv_find (applications, desktop_id) < 0) { - GVariantBuilder builder; - gchar **app; - - g_variant_builder_init (&builder, (GVariantType *)"as"); - for (app = applications; *app; app++) - g_variant_builder_add (&builder, "s", *app); - g_variant_builder_add (&builder, "s", desktop_id); - - g_settings_set_value (settings, "applications", - g_variant_builder_end (&builder)); - } - - g_strfreev (applications); + g_settings_strv_append_unique (settings, "applications", desktop_id); } static void @@ -295,22 +264,8 @@ unregister_application (MessageServiceDbus *msd, const gchar *desktop_id, gpointer user_data) { - gchar **applications = g_settings_get_strv (settings, "applications"); - gchar **app; - GVariantBuilder builder; - - g_variant_builder_init (&builder, (GVariantType *)"as"); - for (app = applications; *app; app++) { - if (g_strcmp0 (desktop_id, *app)) - g_variant_builder_add (&builder, "s", *app); - } - - g_settings_set_value (settings, "applications", - g_variant_builder_end (&builder)); - remove_application (desktop_id); - - g_strfreev (applications); + g_settings_strv_remove (settings, "applications", desktop_id); } static void -- cgit v1.2.3 From be44bb8644730b598fdc1990ab81c1f067dc2353 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Tue, 26 Jun 2012 00:46:00 +0200 Subject: messages-service: move gmenu utility functions into gmenuutils.[ch] As a neat side-effect, this fixes a memory leak in app-section.c. --- src/Makefile.am | 4 ++- src/app-section.c | 21 ++++---------- src/gmenuutils.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/gmenuutils.h | 38 ++++++++++++++++++++++++ src/messages-service.c | 46 ++++------------------------- 5 files changed, 131 insertions(+), 57 deletions(-) create mode 100644 src/gmenuutils.c create mode 100644 src/gmenuutils.h diff --git a/src/Makefile.am b/src/Makefile.am index 79fdee6..e9f88e6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -48,7 +48,9 @@ indicator_messages_service_SOURCES = \ gactionmuxer.c \ gactionmuxer.h \ gsettingsstrv.c \ - gsettingsstrv.h + gsettingsstrv.h \ + gmenuutils.c \ + gmenuutils.h indicator_messages_service_CFLAGS = \ $(APPLET_CFLAGS) \ diff --git a/src/app-section.c b/src/app-section.c index 7bbbbbb..1662a9f 100644 --- a/src/app-section.c +++ b/src/app-section.c @@ -30,6 +30,7 @@ with this program. If not, see . #include #include "app-section.h" #include "dbus-data.h" +#include "gmenuutils.h" struct _AppSectionPrivate { @@ -207,25 +208,12 @@ nick_activate_cb (GSimpleAction *action, } } -static void -g_menu_item_set_icon (GMenuItem *item, - GIcon *icon) -{ - gchar *iconstr; - - iconstr = g_icon_to_string (icon); - g_menu_item_set_attribute (item, INDICATOR_MENU_ATTRIBUTE_ICON_NAME, "s", iconstr); - - g_free (iconstr); -} - static void app_section_set_app_info (AppSection *self, GDesktopAppInfo *appinfo) { AppSectionPrivate *priv = self->priv; GSimpleAction *launch; - GMenuItem *item; g_return_if_fail (priv->appinfo == NULL); @@ -240,9 +228,10 @@ app_section_set_app_info (AppSection *self, g_signal_connect (launch, "activate", G_CALLBACK (activate_cb), self); g_simple_action_group_insert (priv->static_shortcuts, G_ACTION (launch)); - item = g_menu_item_new (g_app_info_get_name (G_APP_INFO (priv->appinfo)), "launch"); - g_menu_item_set_icon (item, g_app_info_get_icon (G_APP_INFO (priv->appinfo))); - g_menu_append_item (priv->menu, item); + g_menu_append_with_icon (priv->menu, + g_app_info_get_name (G_APP_INFO (priv->appinfo)), + g_app_info_get_icon (G_APP_INFO (priv->appinfo)), + "launch"); /* Start to build static shortcuts */ priv->ids = indicator_desktop_shortcuts_new(g_desktop_app_info_get_filename (priv->appinfo), "Messaging Menu"); diff --git a/src/gmenuutils.c b/src/gmenuutils.c new file mode 100644 index 0000000..056e75f --- /dev/null +++ b/src/gmenuutils.c @@ -0,0 +1,79 @@ +/* + * Copyright 2012 Canonical Ltd. + * + * 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 . + * + * Authors: + * Lars Uebernickel + */ + +#include "gmenuutils.h" +#include "dbus-data.h" + +/* g_menu_find_section: + * @menu: a #GMenu + * @section: the section to be found in @menu + * + * @Returns the index of the first menu item that is linked to #section, or -1 + * if there's no such item. + */ +int +g_menu_find_section (GMenu *menu, + GMenuModel *section) +{ + GMenuModel *model = G_MENU_MODEL (menu); + int n_items; + int i; + + g_return_val_if_fail (G_IS_MENU_MODEL (section), -1); + + n_items = g_menu_model_get_n_items (model); + for (i = 0; i < n_items; i++) + { + if (section == g_menu_model_get_item_link (model, i, G_MENU_LINK_SECTION)) + return i; + } + + return -1; +} + + +void +g_menu_append_with_icon (GMenu *menu, + const gchar *label, + GIcon *icon, + const gchar *detailed_action) +{ + gchar *iconstr; + + iconstr = g_icon_to_string (icon); + g_menu_append_with_icon_name (menu, label, iconstr, detailed_action); + + g_free (iconstr); +} + +void +g_menu_append_with_icon_name (GMenu *menu, + const gchar *label, + const gchar *icon_name, + const gchar *detailed_action) +{ + GMenuItem *item; + + item = g_menu_item_new (label, detailed_action); + g_menu_item_set_attribute (item, INDICATOR_MENU_ATTRIBUTE_ICON_NAME, "s", icon_name); + + g_menu_append_item (menu, item); + + g_object_unref (item); +} diff --git a/src/gmenuutils.h b/src/gmenuutils.h new file mode 100644 index 0000000..e00ac55 --- /dev/null +++ b/src/gmenuutils.h @@ -0,0 +1,38 @@ +/* + * Copyright 2012 Canonical Ltd. + * + * 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 . + * + * Authors: + * Lars Uebernickel + */ + +#ifndef __G_MENU_UTILS_H__ +#define __G_MENU_UTILS_H__ + +#include + +int g_menu_find_section (GMenu *menu, + GMenuModel *section); + +void g_menu_append_with_icon (GMenu *menu, + const gchar *label, + GIcon *icon, + const gchar *detailed_action); + +void g_menu_append_with_icon_name (GMenu *menu, + const gchar *label, + const gchar *icon_name, + const gchar *detailed_action); + +#endif diff --git a/src/messages-service.c b/src/messages-service.c index f07ea68..8a08423 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -32,6 +32,7 @@ with this program. If not, see . #include "messages-service-dbus.h" #include "gactionmuxer.h" #include "gsettingsstrv.h" +#include "gmenuutils.h" static GHashTable *applications; @@ -110,26 +111,6 @@ add_application (const gchar *desktop_id) return section; } -/* g_menu_model_find_section: - * - * @Returns the index of the first menu item that is linked to #section, or -1 - * if there's no such item. - */ -static int -g_menu_find_section (GMenu *menu, - GMenuModel *section) -{ - int n_items = g_menu_model_get_n_items (G_MENU_MODEL (menu)); - int i; - - for (i = 0; i < n_items; i++) { - if (section == g_menu_model_get_item_link (G_MENU_MODEL (menu), i, G_MENU_LINK_SECTION)) - return i; - } - - return -1; -} - static void remove_application (const char *desktop_id) { @@ -268,32 +249,17 @@ unregister_application (MessageServiceDbus *msd, g_settings_strv_remove (settings, "applications", desktop_id); } -static void -g_menu_append_with_icon (GMenu *menu, - const gchar *label, - const gchar *icon_name, - const gchar *detailed_action) -{ - GMenuItem *item; - - item = g_menu_item_new (label, detailed_action); - g_menu_item_set_attribute (item, INDICATOR_MENU_ATTRIBUTE_ICON_NAME, "s", icon_name); - - g_menu_append_item (menu, item); - g_object_unref (item); -} - GMenuModel * create_status_section () { GMenu *menu; menu = g_menu_new (); - g_menu_append_with_icon (menu, _("Available"), "user-available", "status::available"); - g_menu_append_with_icon (menu, _("Away"), "user-away", "status::away"); - g_menu_append_with_icon (menu, _("Busy"), "user-busy", "status::busy"); - g_menu_append_with_icon (menu, _("Invisible"), "user-invisible", "status::invisible"); - g_menu_append_with_icon (menu, _("Offline"), "user-offline", "status::offline"); + g_menu_append_with_icon_name (menu, _("Available"), "user-available", "status::available"); + g_menu_append_with_icon_name (menu, _("Away"), "user-away", "status::away"); + g_menu_append_with_icon_name (menu, _("Busy"), "user-busy", "status::busy"); + g_menu_append_with_icon_name (menu, _("Invisible"), "user-invisible", "status::invisible"); + g_menu_append_with_icon_name (menu, _("Offline"), "user-offline", "status::offline"); return G_MENU_MODEL (menu); } -- cgit v1.2.3 From 4dc6e54dd0a5ebba4eb4e26d09ecfde8c9a9580b Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Tue, 26 Jun 2012 00:49:14 +0200 Subject: app-section.c: get rid of unnecessary local item --- src/app-section.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/app-section.c b/src/app-section.c index 1662a9f..472fb6c 100644 --- a/src/app-section.c +++ b/src/app-section.c @@ -240,7 +240,6 @@ app_section_set_app_info (AppSection *self, for (i = 0; nicks[i] != NULL; i++) { gchar *name; GSimpleAction *action; - GMenuItem *item; name = indicator_desktop_shortcuts_nick_get_name(priv->ids, nicks[i]); @@ -248,10 +247,8 @@ app_section_set_app_info (AppSection *self, g_signal_connect(action, "activate", G_CALLBACK (nick_activate_cb), self); g_simple_action_group_insert (priv->static_shortcuts, G_ACTION (action)); - item = g_menu_item_new (name, nicks[i]); - g_menu_append_item (priv->menu, item); + g_menu_append (priv->menu, name, nicks[i]); - g_object_unref (item); g_free(name); } -- cgit v1.2.3 From 1caa3be43ec40c7fb1bbb37a585555fe2526dc57 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Wed, 27 Jun 2012 15:33:13 +0200 Subject: Remove dependency on menu-factory libindicator now has GMenuModel support (unreleased), so indicator-messages doesn't need to create gtk menus anymore. --- configure.ac | 4 +--- src/indicator-messages.c | 24 +++++++++++++----------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/configure.ac b/configure.ac index 11c9bd8..5d6b190 100644 --- a/configure.ac +++ b/configure.ac @@ -43,14 +43,12 @@ GIO_UNIX_REQUIRED_VERSION=2.18 PANEL_REQUIRED_VERSION=2.0.0 INDICATOR_REQUIRED_VERSION=0.3.19 GLIB_REQUIRED_VERSION=2.31.20 -MENU_FACTORY_REQUIRED_VERSION=0.0 PKG_CHECK_MODULES(APPLET, gtk+-3.0 >= $GTK_REQUIRED_VERSION gio-unix-2.0 >= $GIO_UNIX_REQUIRED_VERSION indicator3-0.4 >= $INDICATOR_REQUIRED_VERSION glib-2.0 >= $GLIB_REQUIRED_VERSION - gmodule-2.0 >= $GLIB_REQUIRED_VERSION - menu-factory-gtk >= $MENU_FACTORY_REQUIRED_VERSION) + gmodule-2.0 >= $GLIB_REQUIRED_VERSION) PKG_CHECK_MODULES(GIO, gio-unix-2.0 >= $GIO_UNIX_REQUIRED_VERSION) diff --git a/src/indicator-messages.c b/src/indicator-messages.c index b6707f5..eb0b1fb 100644 --- a/src/indicator-messages.c +++ b/src/indicator-messages.c @@ -34,8 +34,6 @@ with this program. If not, see . #include #include -#include - #include "dbus-data.h" #include "gen-messages-service.xml.h" @@ -81,7 +79,8 @@ static void indicator_messages_init (IndicatorMessages *self); static void indicator_messages_dispose (GObject *object); static void indicator_messages_finalize (GObject *object); static GtkImage * get_icon (IndicatorObject * io); -static GtkMenu * get_menu (IndicatorObject * io); +static GMenuModel * get_menu_model (IndicatorObject * io); +static GActionGroup * get_actions (IndicatorObject * io); static void indicator_messages_middle_click (IndicatorObject * io, IndicatorObjectEntry * entry, guint time, gpointer data); @@ -126,7 +125,8 @@ indicator_messages_class_init (IndicatorMessagesClass *klass) IndicatorObjectClass * io_class = INDICATOR_OBJECT_CLASS(klass); io_class->get_image = get_icon; - io_class->get_menu = get_menu; + io_class->get_menu_model = get_menu_model; + io_class->get_actions = get_actions; io_class->get_accessible_desc = get_accessible_desc; io_class->get_name_hint = get_name_hint; io_class->secondary_activate = indicator_messages_middle_click; @@ -416,16 +416,18 @@ get_icon (IndicatorObject * io) } /* Builds the menu for the indicator */ -static GtkMenu * -get_menu (IndicatorObject * io) +static GMenuModel * +get_menu_model (IndicatorObject * io) { IndicatorMessages *self = INDICATOR_MESSAGES (io); - GtkMenu *menu; - - menu = menu_factory_gtk_new_menu (self->menu, self->actions); - gtk_widget_show_all (GTK_WIDGET (menu)); + return self->menu; +} - return menu; +static GActionGroup * +get_actions (IndicatorObject *io) +{ + IndicatorMessages *self = INDICATOR_MESSAGES (io); + return self->actions; } /* Returns the accessible description of the indicator */ -- cgit v1.2.3 From 93db8c38f2252cb4d506d90721446c0ad524ca3b Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Wed, 27 Jun 2012 17:25:34 +0200 Subject: Add draws-attention flag to source actions AppSections watch those flags for associated sources and mux them into a draws-attention property for the whole section. --- libmessaging-menu/messaging-menu.c | 45 +++++++++-- src/app-section.c | 151 ++++++++++++++++++++++++++++++++++++- src/app-section.h | 1 + src/messages-service.c | 43 +++++++---- 4 files changed, 217 insertions(+), 23 deletions(-) diff --git a/libmessaging-menu/messaging-menu.c b/libmessaging-menu/messaging-menu.c index d848651..eff3b4f 100644 --- a/libmessaging-menu/messaging-menu.c +++ b/libmessaging-menu/messaging-menu.c @@ -463,7 +463,7 @@ messaging_menu_app_insert_source_with_count (MessagingMenuApp *app, guint count) { messaging_menu_app_insert_source_action (app, position, id, icon, label, - g_variant_new ("(uxs)", count, 0, "")); + g_variant_new ("(uxsb)", count, 0, "", FALSE)); } /** @@ -517,7 +517,7 @@ messaging_menu_app_insert_source_with_time (MessagingMenuApp *app, gint64 time) { messaging_menu_app_insert_source_action (app, position, id, icon, label, - g_variant_new ("(uxs)", 0, time, "")); + g_variant_new ("(uxsb)", 0, time, "", FALSE)); } /** @@ -573,7 +573,7 @@ messaging_menu_app_insert_source_with_string (MessagingMenuApp *app, const gchar *str) { messaging_menu_app_insert_source_action (app, position, id, icon, label, - g_variant_new ("(uxs)", 0, 0, str)); + g_variant_new ("(uxsb)", 0, 0, str, FALSE)); } /** @@ -673,7 +673,7 @@ void messaging_menu_app_set_source_count (MessagingMenuApp *app, guint count) { messaging_menu_app_set_source_action (app, source_id, - g_variant_new ("(uxs)", count, 0, "")); + g_variant_new ("(uxsb)", count, 0, "", FALSE)); } /** @@ -693,7 +693,7 @@ messaging_menu_app_set_source_time (MessagingMenuApp *app, gint64 time) { messaging_menu_app_set_source_action (app, source_id, - g_variant_new ("(uxs)", 0, time, "")); + g_variant_new ("(uxsb)", 0, time, "", FALSE)); } /** @@ -713,7 +713,36 @@ messaging_menu_app_set_source_string (MessagingMenuApp *app, const gchar *str) { messaging_menu_app_set_source_action (app, source_id, - g_variant_new ("(uxs)", 0, 0, str)); + g_variant_new ("(uxsb)", 0, 0, str, FALSE)); +} + +static void +messaging_menu_app_set_attention (MessagingMenuApp *app, + const gchar *source_id, + gboolean attention) +{ + GAction *action; + GVariant *state; + guint32 count; + gint64 time; + const gchar *str =""; + + g_return_if_fail (MESSAGING_MENU_IS_APP (app)); + g_return_if_fail (source_id != NULL); + + action = g_simple_action_group_lookup (app->source_actions, source_id); + if (action == NULL) + { + g_warning ("a source with id '%s' doesn't exist", source_id); + return; + } + + state = g_action_get_state (action); + g_variant_get (state, "(ux&sb)", &count, &time, &str, NULL); + g_variant_unref (state); + + g_simple_action_set_state (G_SIMPLE_ACTION (action), + g_variant_new ("(uxsb)", count, time, str, attention)); } /** @@ -731,7 +760,7 @@ void messaging_menu_app_draw_attention (MessagingMenuApp *app, const gchar *source_id) { - g_warning ("%s: not yet implemented", G_STRFUNC); + messaging_menu_app_set_attention (app, source_id, TRUE); } /** @@ -748,5 +777,5 @@ void messaging_menu_app_remove_attention (MessagingMenuApp *app, const gchar *source_id) { - g_warning ("%s: not yet implemented", G_STRFUNC); + messaging_menu_app_set_attention (app, source_id, FALSE); } diff --git a/src/app-section.c b/src/app-section.c index 472fb6c..35a842f 100644 --- a/src/app-section.c +++ b/src/app-section.c @@ -45,6 +45,8 @@ struct _AppSectionPrivate GMenuModel *remote_menu; GActionGroup *actions; + gboolean draws_attention; + guint name_watch_id; }; @@ -52,6 +54,7 @@ enum { PROP_0, PROP_APPINFO, PROP_ACTIONS, + PROP_DRAWS_ATTENTION, NUM_PROPERTIES }; @@ -74,6 +77,18 @@ static void activate_cb (GSimpleAction *action, gpointer userdata); static void app_section_set_app_info (AppSection *self, GDesktopAppInfo *appinfo); +static gboolean any_action_draws_attention (GActionGroup *group, + const gchar *ignored_action); +static void action_added (GActionGroup *group, + const gchar *action_name, + gpointer user_data); +static void action_state_changed (GActionGroup *group, + const gchar *action_name, + GVariant *value, + gpointer user_data); +static void action_removed (GActionGroup *group, + const gchar *action_name, + gpointer user_data); /* GObject Boilerplate */ G_DEFINE_TYPE (AppSection, app_section, G_TYPE_OBJECT); @@ -101,6 +116,12 @@ app_section_class_init (AppSectionClass *klass) G_TYPE_ACTION_GROUP, G_PARAM_READABLE); + properties[PROP_DRAWS_ATTENTION] = g_param_spec_boolean ("draws-attention", + "Draws attention", + "Whether the section currently draws attention", + FALSE, + G_PARAM_READABLE); + g_object_class_install_properties (object_class, NUM_PROPERTIES, properties); } @@ -120,6 +141,8 @@ app_section_init (AppSection *self) priv->menu = g_menu_new (); priv->static_shortcuts = g_simple_action_group_new (); + priv->draws_attention = FALSE; + return; } @@ -137,6 +160,10 @@ app_section_get_property (GObject *object, g_value_set_object (value, app_section_get_app_info (self)); break; + case PROP_DRAWS_ATTENTION: + g_value_set_boolean (value, app_section_get_draws_attention (self)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } @@ -174,7 +201,15 @@ app_section_dispose (GObject *object) priv->name_watch_id = 0; } - g_clear_object (&priv->actions); + if (priv->actions) { + g_object_disconnect (priv->actions, + "any_signal::action-added", action_added, self, + "any_signal::action-state-changed", action_state_changed, self, + "any_signal::action-removed", action_removed, self, + NULL); + g_clear_object (&priv->actions); + } + g_clear_object (&priv->remote_menu); if (priv->ids != NULL) { @@ -334,6 +369,13 @@ app_section_get_app_info (AppSection *self) return G_APP_INFO (priv->appinfo); } +gboolean +app_section_get_draws_attention (AppSection *self) +{ + AppSectionPrivate * priv = self->priv; + return priv->draws_attention; +} + static void application_vanished (GDBusConnection *bus, const gchar *name, @@ -367,6 +409,14 @@ app_section_set_object_path (AppSection *self, app_section_unset_object_path (self); priv->actions = G_ACTION_GROUP (g_dbus_action_group_get (bus, bus_name, object_path)); + + priv->draws_attention = any_action_draws_attention (priv->actions, NULL); + g_object_connect (priv->actions, + "signal::action-added", action_added, self, + "signal::action-state-changed", action_state_changed, self, + "signal::action-removed", action_removed, self, + NULL); + priv->remote_menu = G_MENU_MODEL (g_dbus_menu_model_get (bus, bus_name, object_path)); g_menu_append_section (priv->menu, NULL, priv->remote_menu); @@ -376,6 +426,7 @@ app_section_set_object_path (AppSection *self, self, NULL); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACTIONS]); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]); g_object_thaw_notify (G_OBJECT (self)); } @@ -396,7 +447,15 @@ app_section_unset_object_path (AppSection *self) g_bus_unwatch_name (priv->name_watch_id); priv->name_watch_id = 0; } - g_clear_object (&priv->actions); + + if (priv->actions) { + g_object_disconnect (priv->actions, + "any_signal::action-added", action_added, self, + "any_signal::action-state-changed", action_state_changed, self, + "any_signal::action-removed", action_removed, self, + NULL); + g_clear_object (&priv->actions); + } if (priv->remote_menu) { /* the last menu item points is linked to the app's menumodel */ @@ -405,6 +464,94 @@ app_section_unset_object_path (AppSection *self) g_clear_object (&priv->remote_menu); } + priv->draws_attention = FALSE; + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACTIONS]); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]); } +static gboolean +action_draws_attention (GVariant *state) +{ + gboolean attention; + + if (state && g_variant_is_of_type (state, G_VARIANT_TYPE ("(uxsb)"))) + g_variant_get_child (state, 3, "b", &attention); + else + attention = FALSE; + + return attention; +} + +static gboolean +any_action_draws_attention (GActionGroup *group, + const gchar *ignored_action) +{ + gchar **actions; + gchar **it; + gboolean attention = FALSE; + + actions = g_action_group_list_actions (group); + + for (it = actions; *it && !attention; it++) { + GVariant *state; + + if (ignored_action && g_str_equal (ignored_action, *it)) + continue; + + state = g_action_group_get_action_state (group, *it); + if (state) { + attention = action_draws_attention (state); + g_variant_unref (state); + } + } + + g_strfreev (actions); + return attention; +} + +static void +action_added (GActionGroup *group, + const gchar *action_name, + gpointer user_data) +{ + AppSection *self = user_data; + GVariant *state; + + state = g_action_group_get_action_state (group, action_name); + if (state) { + self->priv->draws_attention |= action_draws_attention (state); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]); + g_variant_unref (state); + } +} + +static void +action_state_changed (GActionGroup *group, + const gchar *action_name, + GVariant *value, + gpointer user_data) +{ + AppSection *self = user_data; + + self->priv->draws_attention = any_action_draws_attention (group, NULL); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]); +} + +static void +action_removed (GActionGroup *group, + const gchar *action_name, + gpointer user_data) +{ + AppSection *self = user_data; + GVariant *state; + + state = g_action_group_get_action_state (group, action_name); + if (!state) + return; + + self->priv->draws_attention = any_action_draws_attention (group, action_name); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]); + + g_variant_unref (state); +} diff --git a/src/app-section.h b/src/app-section.h index 36e091d..935f7a2 100644 --- a/src/app-section.h +++ b/src/app-section.h @@ -56,6 +56,7 @@ const gchar * app_section_get_desktop (AppSection * appitem); GActionGroup * app_section_get_actions (AppSection *self); GMenuModel * app_section_get_menu (AppSection *appitem); GAppInfo * app_section_get_app_info (AppSection *appitem); +gboolean app_section_get_draws_attention (AppSection *appitem); void app_section_set_object_path (AppSection *self, GDBusConnection *bus, const gchar *bus_name, diff --git a/src/messages-service.c b/src/messages-service.c index 8a08423..209abe5 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -73,6 +73,31 @@ actions_changed (GObject *object, g_free (id); } + +static gboolean +app_section_draws_attention (gpointer key, + gpointer value, + gpointer user_data) +{ + AppSection *section = value; + return app_section_get_draws_attention (section); +} + +static void +draws_attention_changed (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + GSimpleAction *clear; + gboolean attention; + + clear = G_SIMPLE_ACTION (g_simple_action_group_lookup (actions, "clear")); + g_return_if_fail (clear != NULL); + + attention = g_hash_table_find (applications, app_section_draws_attention, NULL) != NULL; + g_simple_action_set_enabled (clear, attention); +} + static AppSection * add_application (const gchar *desktop_id) { @@ -98,6 +123,8 @@ add_application (const gchar *desktop_id) g_action_muxer_insert (action_muxer, id, app_section_get_actions (section)); g_signal_connect (section, "notify::actions", G_CALLBACK (actions_changed), NULL); + g_signal_connect (section, "notify::draws-attention", + G_CALLBACK (draws_attention_changed), NULL); /* TODO insert it at the right position (alphabetically by application name) */ menuitem = g_menu_item_new_section (NULL, app_section_get_menu (section)); @@ -132,6 +159,9 @@ remove_application (const char *desktop_id) if (pos >= 0) g_menu_remove (menu, pos); g_action_muxer_remove (action_muxer, id); + + g_signal_handlers_disconnect_by_func (section, actions_changed, NULL); + g_signal_handlers_disconnect_by_func (section, draws_attention_changed, NULL); } else { g_warning ("could not remove '%s', it's not registered", desktop_id); @@ -210,15 +240,6 @@ change_status (GSimpleAction *action, g_message ("changing status to %s", g_variant_get_string (value, NULL)); } -static void -clear_action_handler (MessageServiceDbus *msd, - gboolean attention, - gpointer user_data) -{ - GSimpleAction *action = user_data; - g_simple_action_set_enabled (action, attention); -} - static void register_application (MessageServiceDbus *msd, const gchar *sender, @@ -336,10 +357,6 @@ main (int argc, char ** argv) action_muxer = g_action_muxer_new (); g_action_muxer_insert (action_muxer, NULL, G_ACTION_GROUP (actions)); - g_signal_connect (dbus_interface, MESSAGE_SERVICE_DBUS_SIGNAL_ATTENTION_CHANGED, - G_CALLBACK(clear_action_handler), - g_action_map_lookup_action (G_ACTION_MAP (actions), "clear")); - g_signal_connect (dbus_interface, MESSAGE_SERVICE_DBUS_SIGNAL_REGISTER_APPLICATION, G_CALLBACK (register_application), NULL); g_signal_connect (dbus_interface, MESSAGE_SERVICE_DBUS_SIGNAL_UNREGISTER_APPLICATION, -- cgit v1.2.3 From 58bb62e4b6f88e2f6688afe2e94ac0d954eacadf Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Wed, 27 Jun 2012 17:56:32 +0200 Subject: Make "Clear" work again --- src/app-section.c | 39 +++++++++++++++++++++++++++++++++++++++ src/app-section.h | 1 + src/messages-service.c | 14 +++++++++++--- 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/src/app-section.c b/src/app-section.c index 35a842f..e7a2e1d 100644 --- a/src/app-section.c +++ b/src/app-section.c @@ -89,6 +89,7 @@ static void action_state_changed (GActionGroup *group, static void action_removed (GActionGroup *group, const gchar *action_name, gpointer user_data); +static gboolean action_draws_attention (GVariant *state); /* GObject Boilerplate */ G_DEFINE_TYPE (AppSection, app_section, G_TYPE_OBJECT); @@ -376,6 +377,44 @@ app_section_get_draws_attention (AppSection *self) return priv->draws_attention; } +void +app_section_clear_draws_attention (AppSection *self) +{ + AppSectionPrivate * priv = self->priv; + gchar **action_names; + gchar **it; + + if (priv->actions == NULL) + return; + + action_names = g_action_group_list_actions (priv->actions); + + for (it = action_names; *it; it++) { + GVariant *state; + + state = g_action_group_get_action_state (priv->actions, *it); + if (!state) + continue; + + /* clear draws-attention while preserving other state */ + if (action_draws_attention (state)) { + guint32 count; + gint64 time; + const gchar *str; + GVariant *new_state; + + g_variant_get (state, "(ux&sb)", &count, &time, &str, NULL); + + new_state = g_variant_new ("(uxsb)", count, time, str, FALSE); + g_action_group_change_action_state (priv->actions, *it, new_state); + } + + g_variant_unref (state); + } + + g_strfreev (action_names); +} + static void application_vanished (GDBusConnection *bus, const gchar *name, diff --git a/src/app-section.h b/src/app-section.h index 935f7a2..9b2c99d 100644 --- a/src/app-section.h +++ b/src/app-section.h @@ -57,6 +57,7 @@ GActionGroup * app_section_get_actions (AppSection *self); GMenuModel * app_section_get_menu (AppSection *appitem); GAppInfo * app_section_get_app_info (AppSection *appitem); gboolean app_section_get_draws_attention (AppSection *appitem); +void app_section_clear_draws_attention (AppSection *appitem); void app_section_set_object_path (AppSection *self, GDBusConnection *bus, const gchar *bus_name, diff --git a/src/messages-service.c b/src/messages-service.c index 209abe5..2fa36b2 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -215,13 +215,21 @@ service_shutdown (IndicatorService * service, gpointer user_data) g_main_loop_quit(mainloop); } +static void +app_section_remove_attention (gpointer key, + gpointer value, + gpointer user_data) +{ + AppSection *section = value; + app_section_clear_draws_attention (section); +} + static void clear_action_activate (GSimpleAction *simple, GVariant *param, gpointer user_data) { - MessageServiceDbus *msg_service = user_data; - message_service_dbus_set_attention(msg_service, FALSE); + g_hash_table_foreach (applications, app_section_remove_attention, NULL); } static void @@ -352,7 +360,7 @@ main (int argc, char ** argv) g_bus_get (G_BUS_TYPE_SESSION, NULL, got_bus, NULL); actions = g_simple_action_group_new (); - g_simple_action_group_add_entries (actions, entries, G_N_ELEMENTS (entries), dbus_interface); + g_simple_action_group_add_entries (actions, entries, G_N_ELEMENTS (entries), NULL); action_muxer = g_action_muxer_new (); g_action_muxer_insert (action_muxer, NULL, G_ACTION_GROUP (actions)); -- cgit v1.2.3 From eec8624cd87d14d083fc2c81dec85e79e93e494b Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Wed, 27 Jun 2012 18:08:42 +0200 Subject: Disable "Clear" initially --- src/messages-service.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/messages-service.c b/src/messages-service.c index 2fa36b2..f7bcc2a 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -278,6 +278,30 @@ unregister_application (MessageServiceDbus *msd, g_settings_strv_remove (settings, "applications", desktop_id); } +GSimpleActionGroup * +create_action_group () +{ + GSimpleActionGroup *actions; + GSimpleAction *clear; + GSimpleAction *status; + + actions = g_simple_action_group_new (); + + status = g_simple_action_new_stateful ("status", G_VARIANT_TYPE ("s"), + g_variant_new ("s", "offline")); + g_signal_connect (status, "activate", G_CALLBACK (radio_item_activate), NULL); + g_signal_connect (status, "change-state", G_CALLBACK (change_status), NULL); + + clear = g_simple_action_new ("clear", NULL); + g_simple_action_set_enabled (clear, FALSE); + g_signal_connect (clear, "activate", G_CALLBACK (clear_action_activate), NULL); + + g_simple_action_group_insert (actions, G_ACTION (status)); + g_simple_action_group_insert (actions, G_ACTION (clear)); + + return actions; +} + GMenuModel * create_status_section () { @@ -333,10 +357,6 @@ main (int argc, char ** argv) GMainLoop * mainloop = NULL; IndicatorService * service = NULL; MessageServiceDbus * dbus_interface = NULL; - GActionEntry entries[] = { - { "status", radio_item_activate, "s", "'offline'", change_status }, - { "clear", clear_action_activate } - }; GMenuModel *status_items; /* Glib init */ @@ -359,8 +379,7 @@ main (int argc, char ** argv) g_bus_get (G_BUS_TYPE_SESSION, NULL, got_bus, NULL); - actions = g_simple_action_group_new (); - g_simple_action_group_add_entries (actions, entries, G_N_ELEMENTS (entries), NULL); + actions = create_action_group (); action_muxer = g_action_muxer_new (); g_action_muxer_insert (action_muxer, NULL, G_ACTION_GROUP (actions)); -- cgit v1.2.3 From 9ebfba3cde97027e4db9e220886760b802b8a213 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Wed, 27 Jun 2012 18:21:55 +0200 Subject: Set status action when requested --- src/messages-service.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/messages-service.c b/src/messages-service.c index f7bcc2a..e892aef 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -245,6 +245,18 @@ change_status (GSimpleAction *action, GVariant *value, gpointer user_data) { + const gchar *status; + + g_variant_get (value, "&s", &status); + + g_return_if_fail (g_str_equal (status, "available") || + g_str_equal (status, "away")|| + g_str_equal (status, "busy") || + g_str_equal (status, "invisible") || + g_str_equal (status, "offline")); + + g_simple_action_set_state (action, value); + g_message ("changing status to %s", g_variant_get_string (value, NULL)); } -- cgit v1.2.3 From 579f3cbd04bed13dae44dc87e83cae3092a90d49 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Wed, 27 Jun 2012 20:50:22 +0200 Subject: Add toplevel menu The toplevel menu represents the indicator itself. It has one item with a submenu, which is the indicator's popup menu. The action that is set on the toplevel will never be activated, but its state is used to indicate "draws-attention". --- src/messages-service.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/messages-service.c b/src/messages-service.c index e892aef..4bd7e0c 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -38,6 +38,7 @@ static GHashTable *applications; static GSimpleActionGroup *actions; static GActionMuxer *action_muxer; +static GMenu *toplevel_menu; static GMenu *menu; static GSettings *settings; @@ -88,13 +89,17 @@ draws_attention_changed (GObject *object, GParamSpec *pspec, gpointer user_data) { + GSimpleAction *messages; GSimpleAction *clear; gboolean attention; + messages = G_SIMPLE_ACTION (g_simple_action_group_lookup (actions, "messages")); clear = G_SIMPLE_ACTION (g_simple_action_group_lookup (actions, "clear")); - g_return_if_fail (clear != NULL); + g_return_if_fail (messages != NULL && clear != NULL); attention = g_hash_table_find (applications, app_section_draws_attention, NULL) != NULL; + + g_simple_action_set_state (messages, g_variant_new_boolean (attention)); g_simple_action_set_enabled (clear, attention); } @@ -294,11 +299,16 @@ GSimpleActionGroup * create_action_group () { GSimpleActionGroup *actions; + GSimpleAction *messages; GSimpleAction *clear; GSimpleAction *status; actions = g_simple_action_group_new (); + /* state of the messages action mirrors "draws-attention" */ + messages = g_simple_action_new_stateful ("messages", G_VARIANT_TYPE ("b"), + g_variant_new_boolean (FALSE)); + status = g_simple_action_new_stateful ("status", G_VARIANT_TYPE ("s"), g_variant_new ("s", "offline")); g_signal_connect (status, "activate", G_CALLBACK (radio_item_activate), NULL); @@ -308,6 +318,7 @@ create_action_group () g_simple_action_set_enabled (clear, FALSE); g_signal_connect (clear, "activate", G_CALLBACK (clear_action_activate), NULL); + g_simple_action_group_insert (actions, G_ACTION (messages)); g_simple_action_group_insert (actions, G_ACTION (status)); g_simple_action_group_insert (actions, G_ACTION (clear)); @@ -353,7 +364,7 @@ got_bus (GObject *object, } g_dbus_connection_export_menu_model (bus, INDICATOR_MESSAGES_DBUS_OBJECT, - G_MENU_MODEL (menu), &error); + G_MENU_MODEL (toplevel_menu), &error); if (error) { g_warning ("unable to export menu on dbus: %s", error->message); g_error_free (error); @@ -370,6 +381,7 @@ main (int argc, char ** argv) IndicatorService * service = NULL; MessageServiceDbus * dbus_interface = NULL; GMenuModel *status_items; + GMenuItem *header; /* Glib init */ g_type_init(); @@ -406,6 +418,13 @@ main (int argc, char ** argv) g_menu_append_section (menu, _("Status"), status_items); g_menu_append (menu, _("Clear"), "clear"); + toplevel_menu = g_menu_new (); + header = g_menu_item_new (NULL, "messages"); + g_menu_item_set_submenu (header, G_MENU_MODEL (menu)); + g_menu_item_set_attribute (header, INDICATOR_MENU_ATTRIBUTE_ICON_NAME, "s", "indicator-messages"); + g_menu_append_item (toplevel_menu, header); + g_object_unref (header); + settings = g_settings_new ("com.canonical.indicator.messages"); applications = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); -- cgit v1.2.3 From 315c058bcc7c152615cf35f11c0f29d8ee9ec01b Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Wed, 27 Jun 2012 21:08:03 +0200 Subject: indicator-messages.c: remove messages-service proxy It wasn't used anymore, all menu-related things are communicated via gmenu now. Regression: accessible description --- src/indicator-messages.c | 267 ----------------------------------------------- 1 file changed, 267 deletions(-) diff --git a/src/indicator-messages.c b/src/indicator-messages.c index eb0b1fb..70efd52 100644 --- a/src/indicator-messages.c +++ b/src/indicator-messages.c @@ -49,7 +49,6 @@ typedef struct _IndicatorMessagesClass IndicatorMessagesClass; struct _IndicatorMessagesClass { IndicatorObjectClass parent_class; - void (*update_a11y_desc) (IndicatorServiceManager * service, gpointer * user_data); }; struct _IndicatorMessages { @@ -66,10 +65,6 @@ INDICATOR_SET_VERSION INDICATOR_SET_TYPE(INDICATOR_MESSAGES_TYPE) /* Globals */ -static GtkWidget * main_image = NULL; -static GDBusProxy * icon_proxy = NULL; -static GDBusNodeInfo * bus_node_info = NULL; -static GDBusInterfaceInfo * bus_interface_info = NULL; static const gchar * accessible_desc = NULL; static IndicatorObject * indicator = NULL; @@ -78,41 +73,13 @@ static void indicator_messages_class_init (IndicatorMessagesClass *klass); static void indicator_messages_init (IndicatorMessages *self); static void indicator_messages_dispose (GObject *object); static void indicator_messages_finalize (GObject *object); -static GtkImage * get_icon (IndicatorObject * io); static GMenuModel * get_menu_model (IndicatorObject * io); static GActionGroup * get_actions (IndicatorObject * io); -static void indicator_messages_middle_click (IndicatorObject * io, - IndicatorObjectEntry * entry, - guint time, gpointer data); static const gchar * get_accessible_desc (IndicatorObject * io); static const gchar * get_name_hint (IndicatorObject * io); -static void connection_change (IndicatorServiceManager * sm, - gboolean connected, - gpointer user_data); G_DEFINE_TYPE (IndicatorMessages, indicator_messages, INDICATOR_OBJECT_TYPE); -static void -update_a11y_desc (void) -{ - g_return_if_fail(IS_INDICATOR_MESSAGES(indicator)); - - GList *entries = indicator_object_get_entries(indicator); - IndicatorObjectEntry * entry = (IndicatorObjectEntry *)entries->data; - - entry->accessible_desc = get_accessible_desc(indicator); - - g_signal_emit(G_OBJECT(indicator), - INDICATOR_OBJECT_SIGNAL_ACCESSIBLE_DESC_UPDATE_ID, - 0, - entry, - TRUE); - - g_list_free(entries); - - return; -} - /* Initialize the one-timers */ static void indicator_messages_class_init (IndicatorMessagesClass *klass) @@ -124,32 +91,10 @@ indicator_messages_class_init (IndicatorMessagesClass *klass) IndicatorObjectClass * io_class = INDICATOR_OBJECT_CLASS(klass); - io_class->get_image = get_icon; io_class->get_menu_model = get_menu_model; io_class->get_actions = get_actions; io_class->get_accessible_desc = get_accessible_desc; io_class->get_name_hint = get_name_hint; - io_class->secondary_activate = indicator_messages_middle_click; - - if (bus_node_info == NULL) { - GError * error = NULL; - - bus_node_info = g_dbus_node_info_new_for_xml(_messages_service, &error); - if (error != NULL) { - g_error("Unable to parse Messaging Menu Interface description: %s", error->message); - g_error_free(error); - } - } - - if (bus_interface_info == NULL) { - bus_interface_info = g_dbus_node_info_lookup_interface(bus_node_info, INDICATOR_MESSAGES_DBUS_SERVICE_INTERFACE); - - if (bus_interface_info == NULL) { - g_error("Unable to find interface '" INDICATOR_MESSAGES_DBUS_SERVICE_INTERFACE "'"); - } - } - - return; } /* Build up our per-instance variables */ @@ -164,7 +109,6 @@ indicator_messages_init (IndicatorMessages *self) /* Complex stuff */ self->service = indicator_service_manager_new_version(INDICATOR_MESSAGES_DBUS_NAME, 1); - g_signal_connect(self->service, INDICATOR_SERVICE_MANAGER_SIGNAL_CONNECTION_CHANGE, G_CALLBACK(connection_change), self); bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); if (!bus) { @@ -218,186 +162,6 @@ indicator_messages_finalize (GObject *object) /* Functions */ -/* Signal off of the proxy */ -static void -proxy_signal (GDBusProxy * proxy, const gchar * sender, const gchar * signal, GVariant * params, gpointer user_data) -{ - gboolean prop = g_variant_get_boolean(g_variant_get_child_value(params, 0)); - - if (g_strcmp0("AttentionChanged", signal) == 0) { - if (prop) { - indicator_image_helper_update(GTK_IMAGE(main_image), "indicator-messages-new"); - accessible_desc = _("New Messages"); - } else { - indicator_image_helper_update(GTK_IMAGE(main_image), "indicator-messages"); - accessible_desc = _("Messages"); - } - } else if (g_strcmp0("IconChanged", signal) == 0) { - if (prop) { - gtk_widget_hide(main_image); - } else { - gtk_widget_show(main_image); - } - } else { - g_warning("Unknown signal %s", signal); - } - - update_a11y_desc(); - - return; -} - -/* Callback from getting the attention status from the service. */ -static void -attention_cb (GObject * object, GAsyncResult * ares, gpointer user_data) -{ - GError * error = NULL; - GVariant * res = g_dbus_proxy_call_finish(G_DBUS_PROXY(object), ares, &error); - - if (error != NULL) { - g_warning("Unable to get attention status: %s", error->message); - g_error_free(error); - return; - } - - gboolean prop = g_variant_get_boolean(g_variant_get_child_value(res, 0)); - - if (prop) { - indicator_image_helper_update(GTK_IMAGE(main_image), "indicator-messages-new"); - accessible_desc = _("New Messages"); - } else { - indicator_image_helper_update(GTK_IMAGE(main_image), "indicator-messages"); - accessible_desc = _("Messages"); - } - - update_a11y_desc(); - - return; -} - -/* Change from getting the icon visibility from the service */ -static void -icon_cb (GObject * object, GAsyncResult * ares, gpointer user_data) -{ - GError * error = NULL; - GVariant * res = g_dbus_proxy_call_finish(G_DBUS_PROXY(object), ares, &error); - - if (error != NULL) { - g_warning("Unable to get icon visibility: %s", error->message); - g_error_free(error); - return; - } - - gboolean prop = g_variant_get_boolean(g_variant_get_child_value(res, 0)); - - if (prop) { - gtk_widget_hide(main_image); - } else { - gtk_widget_show(main_image); - } - - return; -} - -static guint connection_drop_timeout = 0; - -/* Resets the icon to not having messages if we can't get a good - answer on it from the service. */ -static gboolean -connection_drop_cb (gpointer user_data) -{ - if (main_image != NULL) { - indicator_image_helper_update(GTK_IMAGE(main_image), "indicator-messages"); - } - connection_drop_timeout = 0; - return FALSE; -} - -/* Proxy is setup now.. whoo! */ -static void -proxy_ready_cb (GObject * obj, GAsyncResult * res, gpointer user_data) -{ - GError * error = NULL; - GDBusProxy * proxy = g_dbus_proxy_new_for_bus_finish(res, &error); - - if (error != NULL) { - g_warning("Unable to get proxy of service: %s", error->message); - g_error_free(error); - return; - } - - icon_proxy = proxy; - - g_signal_connect(G_OBJECT(proxy), "g-signal", G_CALLBACK(proxy_signal), user_data); - - g_dbus_proxy_call(icon_proxy, - "AttentionRequested", - NULL, /* params */ - G_DBUS_CALL_FLAGS_NONE, - -1, /* timeout */ - NULL, /* cancel */ - attention_cb, - user_data); - g_dbus_proxy_call(icon_proxy, - "IconShown", - NULL, /* params */ - G_DBUS_CALL_FLAGS_NONE, - -1, /* timeout */ - NULL, /* cancel */ - icon_cb, - user_data); - - return; -} - -/* Sets up all the icon information in the proxy. */ -static void -connection_change (IndicatorServiceManager * sm, gboolean connected, gpointer user_data) -{ - if (connection_drop_timeout != 0) { - g_source_remove(connection_drop_timeout); - connection_drop_timeout = 0; - } - - if (!connected) { - /* Ensure that we're not saying there are messages - when we don't have a connection. */ - connection_drop_timeout = g_timeout_add(400, connection_drop_cb, NULL); - return; - } - - if (icon_proxy == NULL) { - g_dbus_proxy_new_for_bus(G_BUS_TYPE_SESSION, - G_DBUS_PROXY_FLAGS_NONE, - bus_interface_info, - INDICATOR_MESSAGES_DBUS_NAME, - INDICATOR_MESSAGES_DBUS_SERVICE_OBJECT, - INDICATOR_MESSAGES_DBUS_SERVICE_INTERFACE, - NULL, /* cancel */ - proxy_ready_cb, - sm); - } else { - g_dbus_proxy_call(icon_proxy, - "AttentionRequested", - NULL, /* params */ - G_DBUS_CALL_FLAGS_NONE, - -1, /* timeout */ - NULL, /* cancel */ - attention_cb, - sm); - g_dbus_proxy_call(icon_proxy, - "IconShown", - NULL, /* params */ - G_DBUS_CALL_FLAGS_NONE, - -1, /* timeout */ - NULL, /* cancel */ - icon_cb, - sm); - } - - return; -} - typedef struct _indicator_item_t indicator_item_t; struct _indicator_item_t { GtkWidget * icon; @@ -405,16 +169,6 @@ struct _indicator_item_t { GtkWidget * right; }; -/* Builds the main image icon using the libindicator helper. */ -static GtkImage * -get_icon (IndicatorObject * io) -{ - main_image = GTK_WIDGET(indicator_image_helper("indicator-messages")); - gtk_widget_show(main_image); - - return GTK_IMAGE(main_image); -} - /* Builds the menu for the indicator */ static GMenuModel * get_menu_model (IndicatorObject * io) @@ -443,24 +197,3 @@ get_name_hint (IndicatorObject *io) { return PACKAGE; } - -/* Hide the notifications on middle-click over the indicator-messages */ -static void -indicator_messages_middle_click (IndicatorObject * io, IndicatorObjectEntry * entry, - guint time, gpointer data) -{ - if (icon_proxy == NULL) { - return; - } - - g_dbus_proxy_call(icon_proxy, - "ClearAttention", - NULL, /* params */ - G_DBUS_CALL_FLAGS_NONE, - -1, /* timeout */ - NULL, /* cancel */ - NULL, - NULL); - - return; -} -- cgit v1.2.3 From 193886f467b636a91d546656017de3fd0fa62677 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Wed, 27 Jun 2012 21:42:23 +0200 Subject: Use gdbus-codegen also for the server side messages service --- .bzrignore | 4 +- src/Makefile.am | 30 ++- src/indicator-messages.c | 1 - src/messages-service-dbus.c | 511 -------------------------------------------- src/messages-service-dbus.h | 65 ------ src/messages-service.c | 36 +++- test/Makefile.am | 5 +- 7 files changed, 43 insertions(+), 609 deletions(-) delete mode 100644 src/messages-service-dbus.c delete mode 100644 src/messages-service-dbus.h diff --git a/.bzrignore b/.bzrignore index 431e715..b3415fa 100644 --- a/.bzrignore +++ b/.bzrignore @@ -32,8 +32,8 @@ stamp-* /po/POTFILES /data/indicator-messages.service /src/indicator-messages-service -/src/gen-messages-service.xml.c -/src/gen-messages-service.xml.h +/src/indicator-messages-service.c +/src/indicator-messages-service.h /src/status-provider-mc5-marshal.c /src/status-provider-mc5-marshal.h /src/status-provider-pidgin-marshal.c diff --git a/src/Makefile.am b/src/Makefile.am index e9f88e6..1bc5b59 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -15,8 +15,8 @@ messaginglibdir = $(INDICATORDIR) messaginglib_LTLIBRARIES = libmessaging.la libmessaging_la_SOURCES = \ indicator-messages.c \ - gen-messages-service.xml.h \ - gen-messages-service.xml.c \ + indicator-messages-service.c \ + indicator-messages-service.h dbus-data.h libmessaging_la_CFLAGS = \ $(APPLET_CFLAGS) \ @@ -38,10 +38,8 @@ libmessaging_la_LDFLAGS = \ indicator_messages_service_SOURCES = \ messages-service.c \ - messages-service-dbus.c \ - messages-service-dbus.h \ - gen-messages-service.xml.h \ - gen-messages-service.xml.c \ + indicator-messages-service.c \ + indicator-messages-service.h \ app-section.c \ app-section.h \ dbus-data.h \ @@ -68,19 +66,17 @@ indicator_messages_service_LDADD = \ indicator_messages_service_LDFLAGS = \ $(COVERAGE_LDFLAGS) -gen-%.xml.h: %.xml - @echo "Building $@ from $<" - @echo "extern const char * _$(subst -,_,$(subst .,_,$(basename $(notdir $<))));" > $@ - -gen-%.xml.c: %.xml - @echo "Building $@ from $<" - echo "const char * _$(subst -,_,$(subst .,_,$(basename $(notdir $<)))) = " > $@ - @sed -e "s:\":\\\\\":g" -e s:^:\": -e s:\$$:\\\\n\": $< >> $@ - @echo ";" >> $@ +indicator-messages-service.c: $(top_srcdir)/src/messages-service.xml + $(AM_V_GEN) gdbus-codegen \ + --interface-prefix com.canonical.indicator.messages. \ + --generate-c-code indicator-messages-service \ + --c-namespace IndicatorMessages \ + $^ +indicator-messages-service.h: indicator-messages-service.c BUILT_SOURCES += \ - gen-messages-service.xml.h \ - gen-messages-service.xml.c + indicator-messages-service.c \ + indicator-messages-service.h EXTRA_DIST += \ messages-service.xml diff --git a/src/indicator-messages.c b/src/indicator-messages.c index 70efd52..6278461 100644 --- a/src/indicator-messages.c +++ b/src/indicator-messages.c @@ -35,7 +35,6 @@ with this program. If not, see . #include #include "dbus-data.h" -#include "gen-messages-service.xml.h" #define INDICATOR_MESSAGES_TYPE (indicator_messages_get_type ()) #define INDICATOR_MESSAGES(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), INDICATOR_MESSAGES_TYPE, IndicatorMessages)) diff --git a/src/messages-service-dbus.c b/src/messages-service-dbus.c deleted file mode 100644 index 211b1f5..0000000 --- a/src/messages-service-dbus.c +++ /dev/null @@ -1,511 +0,0 @@ -/* -An indicator to show information that is in messaging applications -that the user is using. - -Copyright 2009 Canonical Ltd. - -Authors: - Ted Gould - -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 . -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include "messages-service-dbus.h" -#include "dbus-data.h" -#include "gen-messages-service.xml.h" - -enum { - ATTENTION_CHANGED, - ICON_CHANGED, - REGISTER_APPLICATION, - UNREGISTER_APPLICATION, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -typedef struct _MessageServiceDbusPrivate MessageServiceDbusPrivate; - -struct _MessageServiceDbusPrivate -{ - GDBusConnection * connection; - GCancellable * accounts_cancel; - GDBusProxy * accounts_user; - gboolean dot; - gboolean hidden; -}; - -#define MESSAGE_SERVICE_DBUS_GET_PRIVATE(o) \ -(G_TYPE_INSTANCE_GET_PRIVATE ((o), MESSAGE_SERVICE_DBUS_TYPE, MessageServiceDbusPrivate)) - -static void message_service_dbus_class_init (MessageServiceDbusClass *klass); -static void message_service_dbus_init (MessageServiceDbus *self); -static void message_service_dbus_dispose (GObject *object); -static void message_service_dbus_finalize (GObject *object); -static void bus_method_call (GDBusConnection * connection, - const gchar * sender, - const gchar * path, - const gchar * interface, - const gchar * method, - GVariant * params, - GDBusMethodInvocation * invocation, - gpointer user_data); - -static GDBusNodeInfo * bus_node_info = NULL; -static GDBusInterfaceInfo * bus_interface_info = NULL; -static const GDBusInterfaceVTable bus_interface_table = { - method_call: bus_method_call, - get_property: NULL, /* No properties */ - set_property: NULL /* No properties */ -}; - -G_DEFINE_TYPE (MessageServiceDbus, message_service_dbus, G_TYPE_OBJECT); - - -static void -message_service_dbus_class_init (MessageServiceDbusClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (MessageServiceDbusPrivate)); - - object_class->dispose = message_service_dbus_dispose; - object_class->finalize = message_service_dbus_finalize; - - signals[ATTENTION_CHANGED] = g_signal_new(MESSAGE_SERVICE_DBUS_SIGNAL_ATTENTION_CHANGED, - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (MessageServiceDbusClass, attention_changed), - NULL, NULL, - g_cclosure_marshal_VOID__BOOLEAN, - G_TYPE_NONE, 1, G_TYPE_BOOLEAN); - - signals[ICON_CHANGED] = g_signal_new(MESSAGE_SERVICE_DBUS_SIGNAL_ICON_CHANGED, - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (MessageServiceDbusClass, icon_changed), - NULL, NULL, - g_cclosure_marshal_VOID__BOOLEAN, - G_TYPE_NONE, 1, G_TYPE_BOOLEAN); - - signals[REGISTER_APPLICATION] = g_signal_new(MESSAGE_SERVICE_DBUS_SIGNAL_REGISTER_APPLICATION, - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_generic, - G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); - - signals[UNREGISTER_APPLICATION] = g_signal_new(MESSAGE_SERVICE_DBUS_SIGNAL_UNREGISTER_APPLICATION, - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, 1, G_TYPE_STRING); - - if (bus_node_info == NULL) { - GError * error = NULL; - - bus_node_info = g_dbus_node_info_new_for_xml(_messages_service, &error); - if (error != NULL) { - g_error("Unable to parse Messaging Menu Interface description: %s", error->message); - g_error_free(error); - } - } - - if (bus_interface_info == NULL) { - bus_interface_info = g_dbus_node_info_lookup_interface(bus_node_info, INDICATOR_MESSAGES_DBUS_SERVICE_INTERFACE); - - if (bus_interface_info == NULL) { - g_error("Unable to find interface '" INDICATOR_MESSAGES_DBUS_SERVICE_INTERFACE "'"); - } - } - - return; -} - -static void -connection_cb (GObject * object, GAsyncResult * res, gpointer user_data) -{ - GError * error = NULL; - GDBusConnection * connection = g_bus_get_finish(res, &error); - - if (error != NULL) { - g_error("Unable to connect to the session bus: %s", error->message); - g_error_free(error); - return; - } - - MessageServiceDbusPrivate * priv = MESSAGE_SERVICE_DBUS_GET_PRIVATE(user_data); - priv->connection = connection; - - g_dbus_connection_register_object(connection, - INDICATOR_MESSAGES_DBUS_SERVICE_OBJECT, - bus_interface_info, - &bus_interface_table, - user_data, - NULL, /* destroy */ - &error); - - if (error != NULL) { - g_error("Unable to register on session bus: %s", error->message); - g_error_free(error); - return; - } - - g_debug("Service on session bus"); - - return; -} - -static void -accounts_notify_cb (GObject *source_object, GAsyncResult *res, - gpointer user_data) -{ - GError * error = NULL; - GVariant * answer = g_dbus_proxy_call_finish(G_DBUS_PROXY(source_object), res, &error); - - if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - g_error_free(error); - return; /* Must exit before accessing freed memory */ - } - - MessageServiceDbusPrivate * priv = MESSAGE_SERVICE_DBUS_GET_PRIVATE(user_data); - - if (priv->accounts_cancel != NULL) { - g_object_unref(priv->accounts_cancel); - priv->accounts_cancel = NULL; - } - - if (error != NULL) { - g_warning("Unable to get notify accounts service of message status: %s", error->message); - g_error_free(error); - return; - } - - g_variant_unref (answer); -} - -static void -accounts_notify (MessageServiceDbus *self) -{ - MessageServiceDbusPrivate * priv = MESSAGE_SERVICE_DBUS_GET_PRIVATE(self); - - if (priv->accounts_user == NULL) - return; /* We're not able to talk to accounts service */ - - if (priv->accounts_cancel != NULL) { - /* Cancel old notify before starting new one */ - g_cancellable_cancel(priv->accounts_cancel); - g_object_unref(priv->accounts_cancel); - priv->accounts_cancel = NULL; - } - - priv->accounts_cancel = g_cancellable_new(); - g_dbus_proxy_call(priv->accounts_user, - "SetXHasMessages", - g_variant_new ("(b)", priv->dot), - G_DBUS_CALL_FLAGS_NONE, - -1, /* timeout */ - priv->accounts_cancel, - accounts_notify_cb, - self); -} - -static void -get_accounts_user_proxy_cb (GObject *source_object, GAsyncResult *res, - gpointer user_data) -{ - GError * error = NULL; - GDBusProxy * proxy = g_dbus_proxy_new_for_bus_finish(res, &error); - - if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - g_error_free(error); - return; /* Must exit before accessing freed memory */ - } - - MessageServiceDbusPrivate * priv = MESSAGE_SERVICE_DBUS_GET_PRIVATE(user_data); - - if (priv->accounts_cancel != NULL) { - g_object_unref(priv->accounts_cancel); - priv->accounts_cancel = NULL; - } - - if (error != NULL) { - g_warning("Unable to get proxy of accountsservice: %s", error->message); - g_error_free(error); - return; - } - - priv->accounts_user = proxy; - accounts_notify (MESSAGE_SERVICE_DBUS (user_data)); -} - -static void -get_accounts_user_find_user_cb (GObject *source_object, GAsyncResult *res, - gpointer user_data) -{ - GError * error = NULL; - GVariant * answer = g_dbus_proxy_call_finish(G_DBUS_PROXY(source_object), res, &error); - - /* We're done with main accounts proxy now */ - g_object_unref (source_object); - - if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - g_error_free(error); - return; /* Must exit before accessing freed memory */ - } - - MessageServiceDbusPrivate * priv = MESSAGE_SERVICE_DBUS_GET_PRIVATE(user_data); - - if (priv->accounts_cancel != NULL) { - g_object_unref(priv->accounts_cancel); - priv->accounts_cancel = NULL; - } - - if (error != NULL) { - g_warning("Unable to get object name of user from accountsservice: %s", error->message); - g_error_free(error); - return; - } - - if (!g_variant_is_of_type (answer, G_VARIANT_TYPE ("(o)"))) { - g_warning("Unexpected type from FindUserByName: %s", g_variant_get_type_string (answer)); - g_variant_unref(answer); - return; - } - - const gchar *path; - g_variant_get(answer, "(&o)", &path); - - priv->accounts_cancel = g_cancellable_new(); - g_dbus_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_NONE, - NULL, - "org.freedesktop.Accounts", - path, - "org.freedesktop.Accounts.User", - priv->accounts_cancel, - get_accounts_user_proxy_cb, - user_data); - - g_variant_unref (answer); -} - -static void -get_accounts_proxy_cb (GObject *source_object, GAsyncResult *res, - gpointer user_data) -{ - GError * error = NULL; - GDBusProxy * proxy = g_dbus_proxy_new_for_bus_finish(res, &error); - - if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - g_error_free(error); - return; /* Must exit before accessing freed memory */ - } - - MessageServiceDbusPrivate * priv = MESSAGE_SERVICE_DBUS_GET_PRIVATE(user_data); - - if (priv->accounts_cancel != NULL) { - g_object_unref(priv->accounts_cancel); - priv->accounts_cancel = NULL; - } - - if (error != NULL) { - g_warning("Unable to get proxy of accountsservice: %s", error->message); - g_error_free(error); - return; - } - - priv->accounts_cancel = g_cancellable_new(); - g_dbus_proxy_call(proxy, - "FindUserByName", - g_variant_new ("(s)", g_get_user_name ()), - G_DBUS_CALL_FLAGS_NONE, - -1, /* timeout */ - priv->accounts_cancel, - get_accounts_user_find_user_cb, - user_data); -} - -static void -get_accounts_proxy (MessageServiceDbus *self) -{ - MessageServiceDbusPrivate * priv = MESSAGE_SERVICE_DBUS_GET_PRIVATE(self); - - g_return_if_fail(priv->accounts_cancel == NULL); - - priv->accounts_cancel = g_cancellable_new(); - g_dbus_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_NONE, - NULL, - "org.freedesktop.Accounts", - "/org/freedesktop/Accounts", - "org.freedesktop.Accounts", - priv->accounts_cancel, - get_accounts_proxy_cb, - self); -} - -static void -message_service_dbus_init (MessageServiceDbus *self) -{ - g_bus_get(G_BUS_TYPE_SESSION, NULL, connection_cb, self); - get_accounts_proxy (self); - - MessageServiceDbusPrivate * priv = MESSAGE_SERVICE_DBUS_GET_PRIVATE(self); - - priv->dot = FALSE; - priv->hidden = FALSE; - - return; -} - -static void -message_service_dbus_dispose (GObject *object) -{ - MessageServiceDbusPrivate * priv = MESSAGE_SERVICE_DBUS_GET_PRIVATE(object); - - if (priv->connection != NULL) { - g_object_unref(priv->connection); - priv->connection = NULL; - } - - if (priv->accounts_cancel != NULL) { - g_cancellable_cancel(priv->accounts_cancel); - g_object_unref(priv->accounts_cancel); - priv->accounts_cancel = NULL; - } - - if (priv->accounts_user != NULL) { - g_object_unref(priv->accounts_user); - priv->accounts_user = NULL; - } - - G_OBJECT_CLASS (message_service_dbus_parent_class)->dispose (object); - return; -} - -static void -message_service_dbus_finalize (GObject *object) -{ - - - G_OBJECT_CLASS (message_service_dbus_parent_class)->finalize (object); - return; -} - -MessageServiceDbus * -message_service_dbus_new (void) -{ - return MESSAGE_SERVICE_DBUS(g_object_new(MESSAGE_SERVICE_DBUS_TYPE, NULL)); -} - -/* Method request off of DBus */ -static void -bus_method_call (GDBusConnection * connection, const gchar * sender, const gchar * path, const gchar * interface, const gchar * method, GVariant * params, GDBusMethodInvocation * invocation, gpointer user_data) -{ - MessageServiceDbus * ms = MESSAGE_SERVICE_DBUS(user_data); - if (ms == NULL) { return; } - - MessageServiceDbusPrivate * priv = MESSAGE_SERVICE_DBUS_GET_PRIVATE(ms); - - if (g_strcmp0("AttentionRequested", method) == 0) { - g_dbus_method_invocation_return_value(invocation, g_variant_new("(b)", priv->dot)); - return; - } else if (g_strcmp0("IconShown", method) == 0) { - g_dbus_method_invocation_return_value(invocation, g_variant_new("(b)", priv->hidden)); - return; - } else if (g_strcmp0("ClearAttention", method) == 0) { - message_service_dbus_set_attention(ms, FALSE); - g_dbus_method_invocation_return_value(invocation, NULL); - return; - } else if (g_strcmp0("RegisterApplication", method) == 0) { - const gchar *desktop_id, *object_path; - g_variant_get(params, "(&s&o)", &desktop_id, &object_path); - g_signal_emit(ms, signals[REGISTER_APPLICATION], 0, sender, desktop_id, object_path); - g_dbus_method_invocation_return_value(invocation, NULL); - } else if (g_strcmp0("UnregisterApplication", method) == 0) { - const gchar *desktop_id; - g_variant_get(params, "(&s)", &desktop_id); - g_signal_emit(ms, signals[UNREGISTER_APPLICATION], 0, desktop_id); - g_dbus_method_invocation_return_value(invocation, NULL); - } else { - g_warning("Unknown function call '%s'", method); - } - - return; -} - -void -message_service_dbus_set_attention (MessageServiceDbus * self, gboolean attention) -{ - MessageServiceDbusPrivate * priv = MESSAGE_SERVICE_DBUS_GET_PRIVATE(self); - /* Do signal */ - if (attention != priv->dot) { - priv->dot = attention; - g_signal_emit(G_OBJECT(self), signals[ATTENTION_CHANGED], 0, priv->dot, TRUE); - - if (priv->connection != NULL) { - g_dbus_connection_emit_signal(priv->connection, - NULL, - INDICATOR_MESSAGES_DBUS_SERVICE_OBJECT, - INDICATOR_MESSAGES_DBUS_SERVICE_INTERFACE, - "AttentionChanged", - g_variant_new("(b)", priv->dot), - NULL); - } - - accounts_notify (self); - } - return; -} - -void -message_service_dbus_set_icon (MessageServiceDbus * self, gboolean hidden) -{ - MessageServiceDbusPrivate * priv = MESSAGE_SERVICE_DBUS_GET_PRIVATE(self); - /* Do signal */ - if (hidden != priv->hidden) { - priv->hidden = hidden; - g_signal_emit(G_OBJECT(self), signals[ICON_CHANGED], 0, priv->hidden, TRUE); - - if (priv->connection != NULL) { - g_dbus_connection_emit_signal(priv->connection, - NULL, - INDICATOR_MESSAGES_DBUS_SERVICE_OBJECT, - INDICATOR_MESSAGES_DBUS_SERVICE_INTERFACE, - "IconChanged", - g_variant_new("(b)", priv->hidden), - NULL); - } - } - return; -} - -GDBusConnection * -message_service_dbus_get_connection (MessageServiceDbus *msd) -{ - MessageServiceDbusPrivate * priv; - - g_return_val_if_fail (IS_MESSAGE_SERVICE_DBUS (msd), NULL); - - priv = MESSAGE_SERVICE_DBUS_GET_PRIVATE(msd); - return priv->connection; -} diff --git a/src/messages-service-dbus.h b/src/messages-service-dbus.h deleted file mode 100644 index 63564b6..0000000 --- a/src/messages-service-dbus.h +++ /dev/null @@ -1,65 +0,0 @@ -/* -An indicator to show information that is in messaging applications -that the user is using. - -Copyright 2009 Canonical Ltd. - -Authors: - Ted Gould - -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 . -*/ - -#ifndef __MESSAGE_SERVICE_DBUS_H__ -#define __MESSAGE_SERVICE_DBUS_H__ - -#include -#include - -G_BEGIN_DECLS - -#define MESSAGE_SERVICE_DBUS_TYPE (message_service_dbus_get_type ()) -#define MESSAGE_SERVICE_DBUS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MESSAGE_SERVICE_DBUS_TYPE, MessageServiceDbus)) -#define MESSAGE_SERVICE_DBUS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MESSAGE_SERVICE_DBUS_TYPE, MessageServiceDbusClass)) -#define IS_MESSAGE_SERVICE_DBUS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MESSAGE_SERVICE_DBUS_TYPE)) -#define IS_MESSAGE_SERVICE_DBUS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MESSAGE_SERVICE_DBUS_TYPE)) -#define MESSAGE_SERVICE_DBUS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MESSAGE_SERVICE_DBUS_TYPE, MessageServiceDbusClass)) - -#define MESSAGE_SERVICE_DBUS_SIGNAL_ATTENTION_CHANGED "attention-changed" -#define MESSAGE_SERVICE_DBUS_SIGNAL_ICON_CHANGED "icon-changed" -#define MESSAGE_SERVICE_DBUS_SIGNAL_REGISTER_APPLICATION "register-application" -#define MESSAGE_SERVICE_DBUS_SIGNAL_UNREGISTER_APPLICATION "unregister-application" - -typedef struct _MessageServiceDbus MessageServiceDbus; -typedef struct _MessageServiceDbusClass MessageServiceDbusClass; - -struct _MessageServiceDbusClass { - GObjectClass parent_class; - - void (*attention_changed) (gboolean dot); - void (*icon_changed) (gboolean hidden); -}; - -struct _MessageServiceDbus { - GObject parent; -}; - -GType message_service_dbus_get_type (void); -MessageServiceDbus * message_service_dbus_new (void); -void message_service_dbus_set_attention (MessageServiceDbus * self, gboolean attention); -void message_service_dbus_set_icon (MessageServiceDbus * self, gboolean hidden); -GDBusConnection * message_service_dbus_get_connection (MessageServiceDbus *msd); - -G_END_DECLS - -#endif diff --git a/src/messages-service.c b/src/messages-service.c index 4bd7e0c..ec36335 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -29,13 +29,14 @@ with this program. If not, see . #include "app-section.h" #include "dbus-data.h" -#include "messages-service-dbus.h" #include "gactionmuxer.h" #include "gsettingsstrv.h" #include "gmenuutils.h" +#include "indicator-messages-service.h" static GHashTable *applications; +IndicatorMessagesService *messages_service; static GSimpleActionGroup *actions; static GActionMuxer *action_muxer; static GMenu *toplevel_menu; @@ -266,33 +267,39 @@ change_status (GSimpleAction *action, } static void -register_application (MessageServiceDbus *msd, - const gchar *sender, +register_application (IndicatorMessagesService *service, + GDBusMethodInvocation *invocation, const gchar *desktop_id, const gchar *menu_path, gpointer user_data) { AppSection *section; GDBusConnection *bus; + const gchar *sender; section = add_application (desktop_id); if (!section) return; - bus = message_service_dbus_get_connection (msd); + bus = g_dbus_interface_skeleton_get_connection (G_DBUS_INTERFACE_SKELETON (service)); + sender = g_dbus_method_invocation_get_sender (invocation); app_section_set_object_path (section, bus, sender, menu_path); - g_settings_strv_append_unique (settings, "applications", desktop_id); + + indicator_messages_service_complete_register_application (service, invocation); } static void -unregister_application (MessageServiceDbus *msd, +unregister_application (IndicatorMessagesService *service, + GDBusMethodInvocation *invocation, const gchar *desktop_id, gpointer user_data) { remove_application (desktop_id); g_settings_strv_remove (settings, "applications", desktop_id); + + indicator_messages_service_complete_unregister_application (service, invocation); } GSimpleActionGroup * @@ -371,6 +378,15 @@ got_bus (GObject *object, return; } + g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (messages_service), + bus, INDICATOR_MESSAGES_DBUS_SERVICE_OBJECT, + &error); + if (error) { + g_warning ("unable to export messages service on dbus: %s", error->message); + g_error_free (error); + return; + } + g_object_unref (bus); } @@ -379,7 +395,6 @@ main (int argc, char ** argv) { GMainLoop * mainloop = NULL; IndicatorService * service = NULL; - MessageServiceDbus * dbus_interface = NULL; GMenuModel *status_items; GMenuItem *header; @@ -399,7 +414,7 @@ main (int argc, char ** argv) textdomain (GETTEXT_PACKAGE); /* Bring up the service DBus interface */ - dbus_interface = message_service_dbus_new(); + messages_service = indicator_messages_service_skeleton_new (); g_bus_get (G_BUS_TYPE_SESSION, NULL, got_bus, NULL); @@ -408,9 +423,9 @@ main (int argc, char ** argv) action_muxer = g_action_muxer_new (); g_action_muxer_insert (action_muxer, NULL, G_ACTION_GROUP (actions)); - g_signal_connect (dbus_interface, MESSAGE_SERVICE_DBUS_SIGNAL_REGISTER_APPLICATION, + g_signal_connect (messages_service, "handle-register-application", G_CALLBACK (register_application), NULL); - g_signal_connect (dbus_interface, MESSAGE_SERVICE_DBUS_SIGNAL_UNREGISTER_APPLICATION, + g_signal_connect (messages_service, "handle-unregister-application", G_CALLBACK (unregister_application), NULL); menu = g_menu_new (); @@ -434,6 +449,7 @@ main (int argc, char ** argv) g_main_loop_run(mainloop); /* Clean up */ + g_object_unref (messages_service); g_object_unref (status_items); g_object_unref (settings); g_hash_table_unref (applications); diff --git a/test/Makefile.am b/test/Makefile.am index d0ea499..ebf2da2 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -38,9 +38,8 @@ noinst_LTLIBRARIES = \ libindicator-messages-service.la libindicator_messages_service_la_SOURCES = \ - $(top_srcdir)/src/messages-service-dbus.c \ - $(top_srcdir)/src/gen-messages-service.xml.c \ - $(top_srcdir)/src/gen-messages-service.xml.h \ + $(top_srcdir)/src/indicator-messages-service.c \ + $(top_srcdir)/src/indicator-messages-service.h \ $(top_srcdir)/src/app-section.c \ $(top_srcdir)/src/app-section.h \ $(top_srcdir)/src/gactionmuxer.c \ -- cgit v1.2.3 From d1492d66b1bdb7e70a342454c4fde781f448b83e Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Wed, 27 Jun 2012 21:47:17 +0200 Subject: messages-service.xml: remove unused methods and signals --- src/messages-service.xml | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/messages-service.xml b/src/messages-service.xml index a560187..450d1fa 100644 --- a/src/messages-service.xml +++ b/src/messages-service.xml @@ -2,14 +2,6 @@ - - - - - - - - @@ -18,13 +10,5 @@ - - - - - - - - -- cgit v1.2.3 From cc6cbf767baba6ab2b5f2ec32f0d9ff2a7f94cfa Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Wed, 27 Jun 2012 22:44:30 +0200 Subject: Sync chat status from and to clients --- libmessaging-menu/messaging-menu.c | 74 +++++++++++++++++++++++++++++++++++++- libmessaging-menu/messaging-menu.h | 2 +- src/messages-service.c | 50 ++++++++++++++++++++++---- src/messages-service.xml | 9 +++++ 4 files changed, 126 insertions(+), 9 deletions(-) diff --git a/libmessaging-menu/messaging-menu.c b/libmessaging-menu/messaging-menu.c index eff3b4f..7ee455a 100644 --- a/libmessaging-menu/messaging-menu.c +++ b/libmessaging-menu/messaging-menu.c @@ -52,12 +52,19 @@ enum { enum { ACTIVATE_SOURCE, + STATUS_CHANGED, N_SIGNALS }; static GParamSpec *properties[N_PROPERTIES]; static guint signals[N_SIGNALS]; +static const gchar *status_ids[] = { "available", "away", "busy", "invisible", "offline" }; + +static void global_status_changed (IndicatorMessagesService *service, + const gchar *status_str, + gpointer user_data); + static void messaging_menu_app_set_property (GObject *object, guint prop_id, @@ -100,6 +107,14 @@ messaging_menu_app_dispose (GObject *object) app->cancellable = NULL; } + if (app->messages_service) + { + g_signal_handlers_disconnect_by_func (app->messages_service, + global_status_changed, + app); + g_clear_object (&app->messages_service); + } + g_clear_object (&app->appinfo); g_clear_object (&app->source_actions); g_clear_object (&app->menu); @@ -134,6 +149,14 @@ messaging_menu_app_class_init (MessagingMenuAppClass *class) NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); + + signals[STATUS_CHANGED] = g_signal_new ("status-changed", + MESSAGING_MENU_TYPE_APP, + G_SIGNAL_RUN_FIRST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, 1, G_TYPE_INT); } static void @@ -152,11 +175,15 @@ created_messages_service (GObject *source_object, return; } + g_signal_connect (app->messages_service, "status-changed", + G_CALLBACK (global_status_changed), app); + /* sync current status */ if (app->registered == TRUE) messaging_menu_app_register (app); else if (app->registered == FALSE) messaging_menu_app_unregister (app); + messaging_menu_app_set_status (app, app->status); } static void @@ -316,7 +343,52 @@ void messaging_menu_app_set_status (MessagingMenuApp *app, MessagingMenuStatus status) { - g_warning ("%s: not yet implemented", G_STRFUNC); + g_return_if_fail (MESSAGING_MENU_IS_APP (app)); + g_return_if_fail (status >= MESSAGING_MENU_STATUS_AVAILABLE && + status <= MESSAGING_MENU_STATUS_OFFLINE); + + app->status = status; + + /* state will be synced right after connecting to the service */ + if (!app->messages_service) + return; + + indicator_messages_service_call_set_status (app->messages_service, + status_ids [status], + app->cancellable, + NULL, NULL); +} + +static int +status_from_string (const gchar *s) +{ + int i; + + if (!s) + return -1; + + for (i = 0; i <= MESSAGING_MENU_STATUS_OFFLINE; i++) + { + if (g_str_equal (s, status_ids[i])) + return i; + } + + return -1; +} + +static void +global_status_changed (IndicatorMessagesService *service, + const gchar *status_str, + gpointer user_data) +{ + MessagingMenuApp *app = user_data; + int status; + + status = status_from_string (status_str); + g_return_if_fail (status >= 0); + + app->status = (MessagingMenuStatus)status; + g_signal_emit (app, signals[STATUS_CHANGED], 0, app->status); } static void diff --git a/libmessaging-menu/messaging-menu.h b/libmessaging-menu/messaging-menu.h index 7ce2981..e767099 100644 --- a/libmessaging-menu/messaging-menu.h +++ b/libmessaging-menu/messaging-menu.h @@ -33,7 +33,7 @@ typedef enum { MESSAGING_MENU_STATUS_AVAILABLE, MESSAGING_MENU_STATUS_AWAY, MESSAGING_MENU_STATUS_BUSY, - MESSAGING_MENU_STATUS_HIDDEN, + MESSAGING_MENU_STATUS_INVISIBLE, MESSAGING_MENU_STATUS_OFFLINE } MessagingMenuStatus; diff --git a/src/messages-service.c b/src/messages-service.c index ec36335..a12847f 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -246,10 +246,26 @@ radio_item_activate (GSimpleAction *action, g_action_change_state (G_ACTION (action), parameter); } +static gboolean +g_action_state_equal (GAction *action, + GVariant *value) +{ + GVariant *state; + gboolean eq; + + state = g_action_get_state (action); + g_return_val_if_fail (state != NULL, FALSE); + + eq = g_variant_equal (state, value); + + g_variant_unref (state); + return eq; +} + static void -change_status (GSimpleAction *action, - GVariant *value, - gpointer user_data) +change_status_action (GSimpleAction *action, + GVariant *value, + gpointer user_data) { const gchar *status; @@ -261,9 +277,11 @@ change_status (GSimpleAction *action, g_str_equal (status, "invisible") || g_str_equal (status, "offline")); - g_simple_action_set_state (action, value); - - g_message ("changing status to %s", g_variant_get_string (value, NULL)); + if (!g_action_state_equal (G_ACTION (action), value)) { + g_message ("%s", status); + g_simple_action_set_state (action, value); + indicator_messages_service_emit_status_changed (messages_service, status); + } } static void @@ -302,6 +320,22 @@ unregister_application (IndicatorMessagesService *service, indicator_messages_service_complete_unregister_application (service, invocation); } +static void +set_status (IndicatorMessagesService *service, + GDBusMethodInvocation *invocation, + const gchar *status_str, + gpointer user_data) +{ + GAction *status; + + status = g_simple_action_group_lookup (actions, "status"); + g_return_if_fail (status != NULL); + + g_action_change_state (status, g_variant_new_string (status_str)); + + indicator_messages_service_complete_set_status (service, invocation); +} + GSimpleActionGroup * create_action_group () { @@ -319,7 +353,7 @@ create_action_group () status = g_simple_action_new_stateful ("status", G_VARIANT_TYPE ("s"), g_variant_new ("s", "offline")); g_signal_connect (status, "activate", G_CALLBACK (radio_item_activate), NULL); - g_signal_connect (status, "change-state", G_CALLBACK (change_status), NULL); + g_signal_connect (status, "change-state", G_CALLBACK (change_status_action), NULL); clear = g_simple_action_new ("clear", NULL); g_simple_action_set_enabled (clear, FALSE); @@ -427,6 +461,8 @@ main (int argc, char ** argv) G_CALLBACK (register_application), NULL); g_signal_connect (messages_service, "handle-unregister-application", G_CALLBACK (unregister_application), NULL); + g_signal_connect (messages_service, "handle-set-status", + G_CALLBACK (set_status), NULL); menu = g_menu_new (); status_items = create_status_section (); diff --git a/src/messages-service.xml b/src/messages-service.xml index 450d1fa..edd47c7 100644 --- a/src/messages-service.xml +++ b/src/messages-service.xml @@ -6,9 +6,18 @@ + + + + + + + + + -- cgit v1.2.3 From 6c93ee8e97bca993273c9dcfbebd3e52d0ac6c83 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Wed, 27 Jun 2012 22:47:11 +0200 Subject: Remove header from status section --- src/messages-service.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/messages-service.c b/src/messages-service.c index a12847f..53d6509 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -466,7 +466,7 @@ main (int argc, char ** argv) menu = g_menu_new (); status_items = create_status_section (); - g_menu_append_section (menu, _("Status"), status_items); + g_menu_append_section (menu, NULL, status_items); g_menu_append (menu, _("Clear"), "clear"); toplevel_menu = g_menu_new (); -- cgit v1.2.3 From 37acacae18286dbfeceacc74db8e5ff02ae8f8b2 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Wed, 27 Jun 2012 23:55:52 +0200 Subject: Only show chat section when necessary The chat section is only shown when an application that is registered to use it is running. Applications are registered if their desktop file contains: X-MessagingMenu-UsesChatStatus: true --- src/app-section.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/app-section.h | 1 + src/messages-service.c | 39 +++++++++++++++++++++++--- 3 files changed, 110 insertions(+), 4 deletions(-) diff --git a/src/app-section.c b/src/app-section.c index e7a2e1d..fb3d8f9 100644 --- a/src/app-section.c +++ b/src/app-section.c @@ -46,6 +46,7 @@ struct _AppSectionPrivate GActionGroup *actions; gboolean draws_attention; + gboolean uses_chat_status; guint name_watch_id; }; @@ -55,6 +56,7 @@ enum { PROP_APPINFO, PROP_ACTIONS, PROP_DRAWS_ATTENTION, + PROP_USES_CHAT_STATUS, NUM_PROPERTIES }; @@ -123,6 +125,12 @@ app_section_class_init (AppSectionClass *klass) FALSE, G_PARAM_READABLE); + properties[PROP_USES_CHAT_STATUS] = g_param_spec_boolean ("uses-chat-status", + "Uses chat status", + "Whether the section uses the global chat status", + FALSE, + G_PARAM_READABLE); + g_object_class_install_properties (object_class, NUM_PROPERTIES, properties); } @@ -165,6 +173,10 @@ app_section_get_property (GObject *object, g_value_set_boolean (value, app_section_get_draws_attention (self)); break; + case PROP_USES_CHAT_STATUS: + g_value_set_boolean (value, app_section_get_uses_chat_status (self)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } @@ -244,12 +256,59 @@ nick_activate_cb (GSimpleAction *action, } } +static void +keyfile_loaded (GObject *source_object, + GAsyncResult *result, + gpointer user_data) +{ + AppSection *self = user_data; + gchar *contents; + gsize length; + GKeyFile *keyfile; + GError *error = NULL; + + if (!g_file_load_contents_finish (G_FILE (source_object), result, + &contents, &length, NULL, &error)) { + g_warning ("could not read key file: %s", error->message); + g_error_free (error); + return; + } + + keyfile = g_key_file_new (); + if (!g_key_file_load_from_data (keyfile, contents, length, 0, &error)) { + g_warning ("could not read key file: %s", error->message); + g_error_free (error); + goto out; + } + + self->priv->uses_chat_status = g_key_file_get_boolean (keyfile, + G_KEY_FILE_DESKTOP_GROUP, + "X-MessagingMenu-UsesChatStatus", + &error); + if (error) { + if (error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND) { + g_warning ("could not read X-MessagingMenu-UsesChatSection: %s", + error->message); + } + g_error_free (error); + goto out; + } + + if (self->priv->uses_chat_status) + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_USES_CHAT_STATUS]); + +out: + g_key_file_free (keyfile); + g_free (contents); +} + static void app_section_set_app_info (AppSection *self, GDesktopAppInfo *appinfo) { AppSectionPrivate *priv = self->priv; GSimpleAction *launch; + GFile *keyfile; g_return_if_fail (priv->appinfo == NULL); @@ -288,6 +347,10 @@ app_section_set_app_info (AppSection *self, g_free(name); } + keyfile = g_file_new_for_path (g_desktop_app_info_get_filename (priv->appinfo)); + g_file_load_contents_async (keyfile, NULL, keyfile_loaded, self); + g_object_unref (keyfile); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_APPINFO]); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACTIONS]); @@ -466,6 +529,7 @@ app_section_set_object_path (AppSection *self, g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACTIONS]); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_USES_CHAT_STATUS]); g_object_thaw_notify (G_OBJECT (self)); } @@ -507,6 +571,7 @@ app_section_unset_object_path (AppSection *self) g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACTIONS]); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_USES_CHAT_STATUS]); } static gboolean @@ -594,3 +659,12 @@ action_removed (GActionGroup *group, g_variant_unref (state); } + +gboolean +app_section_get_uses_chat_status (AppSection *self) +{ + AppSectionPrivate * priv = self->priv; + + /* chat status is only useful when the app is running */ + return priv->uses_chat_status && priv->actions; +} diff --git a/src/app-section.h b/src/app-section.h index 9b2c99d..c351ada 100644 --- a/src/app-section.h +++ b/src/app-section.h @@ -63,6 +63,7 @@ void app_section_set_object_path (AppSection *self, const gchar *bus_name, const gchar *object_path); void app_section_unset_object_path (AppSection *self); +gboolean app_section_get_uses_chat_status (AppSection *self); G_END_DECLS diff --git a/src/messages-service.c b/src/messages-service.c index 53d6509..6e88087 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -41,6 +41,7 @@ static GSimpleActionGroup *actions; static GActionMuxer *action_muxer; static GMenu *toplevel_menu; static GMenu *menu; +static GMenuModel *chat_section; static GSettings *settings; @@ -104,6 +105,36 @@ draws_attention_changed (GObject *object, g_simple_action_set_enabled (clear, attention); } +static gboolean +app_section_uses_chat (gpointer key, + gpointer value, + gpointer user_data) +{ + AppSection *section = value; + return app_section_get_uses_chat_status (section); +} + +static void +uses_chat_status_changed (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + gboolean show_chat; + GMenuModel *first_section; + + show_chat = g_hash_table_find (applications, app_section_uses_chat, NULL) != NULL; + + first_section = g_menu_model_get_item_link (G_MENU_MODEL (menu), 0, G_MENU_LINK_SECTION); + if (first_section == chat_section) { + if (!show_chat) + g_menu_remove (menu, 0); + } + else { + if (show_chat) + g_menu_insert_section (menu, 0, NULL, chat_section); + } +} + static AppSection * add_application (const gchar *desktop_id) { @@ -131,6 +162,8 @@ add_application (const gchar *desktop_id) G_CALLBACK (actions_changed), NULL); g_signal_connect (section, "notify::draws-attention", G_CALLBACK (draws_attention_changed), NULL); + g_signal_connect (section, "notify::uses-chat-status", + G_CALLBACK (uses_chat_status_changed), NULL); /* TODO insert it at the right position (alphabetically by application name) */ menuitem = g_menu_item_new_section (NULL, app_section_get_menu (section)); @@ -429,7 +462,6 @@ main (int argc, char ** argv) { GMainLoop * mainloop = NULL; IndicatorService * service = NULL; - GMenuModel *status_items; GMenuItem *header; /* Glib init */ @@ -465,8 +497,7 @@ main (int argc, char ** argv) G_CALLBACK (set_status), NULL); menu = g_menu_new (); - status_items = create_status_section (); - g_menu_append_section (menu, NULL, status_items); + chat_section = create_status_section (); g_menu_append (menu, _("Clear"), "clear"); toplevel_menu = g_menu_new (); @@ -486,7 +517,7 @@ main (int argc, char ** argv) /* Clean up */ g_object_unref (messages_service); - g_object_unref (status_items); + g_object_unref (chat_section); g_object_unref (settings); g_hash_table_unref (applications); return 0; -- cgit v1.2.3 From 8f2b343fc59a927961ee90f588f207d22c54924d Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Thu, 28 Jun 2012 16:07:17 +0200 Subject: libmessaging-menu: use the (newly added) GTupleAction instead of GSimpleAction GTupleAction is a bit simpler to handle when the action state contains a tuple of things that are independently modified most the time. It might be useful for other indicators as well. This implicitly also fixes the bug that libmessaging-menu did not preserve the other values in the action state when updating count, time, or string. --- libmessaging-menu/Makefile.am | 2 + libmessaging-menu/gtupleaction.c | 353 +++++++++++++++++++++++++++++++++++++ libmessaging-menu/gtupleaction.h | 40 +++++ libmessaging-menu/messaging-menu.c | 71 +++----- 4 files changed, 422 insertions(+), 44 deletions(-) create mode 100644 libmessaging-menu/gtupleaction.c create mode 100644 libmessaging-menu/gtupleaction.h diff --git a/libmessaging-menu/Makefile.am b/libmessaging-menu/Makefile.am index a0da51e..becaded 100644 --- a/libmessaging-menu/Makefile.am +++ b/libmessaging-menu/Makefile.am @@ -5,6 +5,8 @@ libmessaging_menu_ladir = $(includedir)/messaging-menu libmessaging_menu_la_SOURCES = \ messaging-menu.c \ + gtupleaction.c \ + gtupleaction.h \ $(BUILT_SOURCES) libmessaging_menu_la_HEADERS = \ diff --git a/libmessaging-menu/gtupleaction.c b/libmessaging-menu/gtupleaction.c new file mode 100644 index 0000000..f9e6fd7 --- /dev/null +++ b/libmessaging-menu/gtupleaction.c @@ -0,0 +1,353 @@ +/* + * Copyright 2012 Canonical Ltd. + * + * 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 . + * + * Authors: + * Lars Uebernickel + */ + +#include "gtupleaction.h" + +typedef GObjectClass GTupleActionClass; + +struct _GTupleAction +{ + GObject parent; + + gchar *name; + GVariantType *type; + gboolean enabled; + + gsize n_children; + GVariant **children; +}; + +static void action_interface_init (GActionInterface *iface); + +G_DEFINE_TYPE_WITH_CODE (GTupleAction, g_tuple_action, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_ACTION, action_interface_init)); + +enum +{ + PROP_0, + PROP_NAME, + PROP_PARAMETER_TYPE, + PROP_ENABLED, + PROP_STATE_TYPE, + PROP_STATE, + N_PROPERTIES +}; + +enum +{ + SIGNAL_ACTIVATE, + N_SIGNALS +}; + +static GParamSpec *properties[N_PROPERTIES]; +static guint signal_ids[N_SIGNALS]; + +static const gchar * +g_tuple_action_get_name (GAction *action) +{ + GTupleAction *tuple = G_TUPLE_ACTION (action); + + return tuple->name; +} + +static const GVariantType * +g_tuple_action_get_parameter_type (GAction *action) +{ + return NULL; +} + +static const GVariantType * +g_tuple_action_get_state_type (GAction *action) +{ + GTupleAction *tuple = G_TUPLE_ACTION (action); + + return tuple->type; +} + +static GVariant * +g_tuple_action_get_state_hint (GAction *action) +{ + return NULL; +} + +static gboolean +g_tuple_action_get_enabled (GAction *action) +{ + GTupleAction *tuple = G_TUPLE_ACTION (action); + + return tuple->enabled; +} + +static GVariant * +g_tuple_action_get_state (GAction *action) +{ + GTupleAction *tuple = G_TUPLE_ACTION (action); + GVariant *result; + + result = g_variant_new_tuple (tuple->children, tuple->n_children); + return g_variant_ref_sink (result); +} + +static void +g_tuple_action_set_state (GTupleAction *tuple, + GVariant *state) +{ + int i; + + g_return_if_fail (g_variant_type_is_tuple (g_variant_get_type (state))); + + if (tuple->type == NULL) + { + tuple->type = g_variant_type_copy (g_variant_get_type (state)); + tuple->n_children = g_variant_n_children (state); + tuple->children = g_new0 (GVariant *, tuple->n_children); + } + + for (i = 0; i < tuple->n_children; i++) + { + if (tuple->children[i]) + g_variant_unref (tuple->children[i]); + tuple->children[i] = g_variant_get_child_value (state, i); + } + + g_object_notify_by_pspec (G_OBJECT (tuple), properties[PROP_STATE]); +} + +static void +g_tuple_action_change_state (GAction *action, + GVariant *value) +{ + GTupleAction *tuple = G_TUPLE_ACTION (action); + + g_return_if_fail (value != NULL); + g_return_if_fail (g_variant_is_of_type (value, tuple->type)); + + g_variant_ref_sink (value); + + /* TODO add a change-state signal similar to GSimpleAction */ + g_tuple_action_set_state (tuple, value); + + g_variant_unref (value); +} + +static void +g_tuple_action_activate (GAction *action, + GVariant *parameter) +{ + GTupleAction *tuple = G_TUPLE_ACTION (action); + + g_return_if_fail (parameter == NULL); + + if (tuple->enabled) + g_signal_emit (tuple, signal_ids[SIGNAL_ACTIVATE], 0, NULL); +} + +static void +g_tuple_action_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GAction *action = G_ACTION (object); + + switch (prop_id) + { + case PROP_NAME: + g_value_set_string (value, g_tuple_action_get_name (action)); + break; + + case PROP_PARAMETER_TYPE: + g_value_set_boxed (value, g_tuple_action_get_parameter_type (action)); + break; + + case PROP_ENABLED: + g_value_set_boolean (value, g_tuple_action_get_enabled (action)); + break; + + case PROP_STATE_TYPE: + g_value_set_boxed (value, g_tuple_action_get_state_type (action)); + break; + + case PROP_STATE: + g_value_take_variant (value, g_tuple_action_get_state (action)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +g_tuple_action_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GTupleAction *tuple = G_TUPLE_ACTION (object); + + switch (prop_id) + { + case PROP_NAME: + tuple->name = g_value_dup_string (value); + g_object_notify_by_pspec (object, properties[PROP_NAME]); + break; + + case PROP_ENABLED: + tuple->enabled = g_value_get_boolean (value); + g_object_notify_by_pspec (object, properties[PROP_ENABLED]); + break; + + case PROP_STATE: + g_tuple_action_set_state (tuple, g_value_get_variant (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +g_tuple_action_finalize (GObject *object) +{ + GTupleAction *tuple = G_TUPLE_ACTION (object); + int i; + + g_free (tuple->name); + g_variant_type_free (tuple->type); + + for (i = 0; i < tuple->n_children; i++) + g_variant_unref (tuple->children[i]); + + g_free (tuple->children); + + G_OBJECT_CLASS (g_tuple_action_parent_class)->finalize (object); +} + +static void +action_interface_init (GActionInterface *iface) +{ + iface->get_name = g_tuple_action_get_name; + iface->get_parameter_type = g_tuple_action_get_parameter_type; + iface->get_state_type = g_tuple_action_get_state_type; + iface->get_state_hint = g_tuple_action_get_state_hint; + iface->get_enabled = g_tuple_action_get_enabled; + iface->get_state = g_tuple_action_get_state; + iface->change_state = g_tuple_action_change_state; + iface->activate = g_tuple_action_activate; +} + +static void +g_tuple_action_class_init (GTupleActionClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->get_property = g_tuple_action_get_property; + object_class->set_property = g_tuple_action_set_property; + object_class->finalize = g_tuple_action_finalize; + + properties[PROP_NAME] = g_param_spec_string ("name", + "Name", + "The name of the action", + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + + properties[PROP_PARAMETER_TYPE] = g_param_spec_boxed ("parameter-type", + "Parameter Type", + "The variant type passed to activate", + G_TYPE_VARIANT_TYPE, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); + + properties[PROP_ENABLED] = g_param_spec_boolean ("enabled", + "Enabled", + "Whether the action can be activated", + TRUE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + + properties[PROP_STATE_TYPE] = g_param_spec_boxed ("state-type", + "State Type", + "The variant type of the state, must be a tuple", + G_TYPE_VARIANT_TYPE, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); + + properties[PROP_STATE] = g_param_spec_variant ("state", + "State", + "The state of the action", + G_VARIANT_TYPE_TUPLE, + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, N_PROPERTIES, properties); + + signal_ids[SIGNAL_ACTIVATE] = g_signal_new ("activate", + G_TYPE_TUPLE_ACTION, + G_SIGNAL_RUN_LAST | G_SIGNAL_MUST_COLLECT, + 0, NULL, NULL, + g_cclosure_marshal_VOID__VARIANT, + G_TYPE_NONE, 1, + G_TYPE_VARIANT); +} + +static void +g_tuple_action_init (GTupleAction *action) +{ +} + +GTupleAction * +g_tuple_action_new (const gchar *name, + GVariant *initial_state) +{ + const GVariantType *type; + + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (initial_state != NULL, NULL); + + type = g_variant_get_type (initial_state); + g_return_val_if_fail (g_variant_type_is_tuple (type), NULL); + + return g_object_new (G_TYPE_TUPLE_ACTION, + "name", name, + "state", initial_state, + NULL); +} + +void +g_tuple_action_set_child (GTupleAction *action, + gsize index, + GVariant *value) +{ + const GVariantType *type; + + g_return_if_fail (G_IS_TUPLE_ACTION (action)); + g_return_if_fail (index < action->n_children); + g_return_if_fail (value != NULL); + + type = g_variant_get_type (value); + g_return_if_fail (g_variant_is_of_type (value, type)); + + g_variant_unref (action->children[index]); + action->children[index] = g_variant_ref_sink (value); + + g_object_notify_by_pspec (G_OBJECT (action), properties[PROP_STATE]); +} diff --git a/libmessaging-menu/gtupleaction.h b/libmessaging-menu/gtupleaction.h new file mode 100644 index 0000000..c447d71 --- /dev/null +++ b/libmessaging-menu/gtupleaction.h @@ -0,0 +1,40 @@ +/* + * Copyright 2012 Canonical Ltd. + * + * 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 . + * + * Authors: + * Lars Uebernickel + */ + +#ifndef __g_tuple_action_h__ +#define __g_tuple_action_h__ + +#include + +#define G_TYPE_TUPLE_ACTION (g_tuple_action_get_type ()) +#define G_TUPLE_ACTION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_TUPLE_ACTION, GTupleAction)) +#define G_IS_TUPLE_ACTION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_TUPLE_ACTION)) + +typedef struct _GTupleAction GTupleAction; + +GType g_tuple_action_get_type (void) G_GNUC_CONST; + +GTupleAction * g_tuple_action_new (const gchar *name, + GVariant *initial_state); + +void g_tuple_action_set_child (GTupleAction *action, + gsize index, + GVariant *value); + +#endif diff --git a/libmessaging-menu/messaging-menu.c b/libmessaging-menu/messaging-menu.c index 7ee455a..22e4793 100644 --- a/libmessaging-menu/messaging-menu.c +++ b/libmessaging-menu/messaging-menu.c @@ -19,6 +19,7 @@ #include "messaging-menu.h" #include "indicator-messages-service.h" +#include "gtupleaction.h" #include @@ -44,6 +45,14 @@ struct _MessagingMenuApp G_DEFINE_TYPE (MessagingMenuApp, messaging_menu_app, G_TYPE_OBJECT); +enum +{ + INDEX_COUNT, + INDEX_TIME, + INDEX_STRING, + INDEX_DRAWS_ATTENTION +}; + enum { PROP_0, PROP_DESKTOP_ID, @@ -392,9 +401,9 @@ global_status_changed (IndicatorMessagesService *service, } static void -source_action_activated (GSimpleAction *action, - GVariant *parameter, - gpointer user_data) +source_action_activated (GTupleAction *action, + GVariant *parameter, + gpointer user_data) { MessagingMenuApp *app = user_data; const gchar *name = g_action_get_name (G_ACTION (action)); @@ -411,7 +420,7 @@ messaging_menu_app_insert_source_action (MessagingMenuApp *app, const gchar *label, GVariant *state) { - GSimpleAction *action; + GTupleAction *action; GMenuItem *menuitem; g_return_if_fail (MESSAGING_MENU_IS_APP (app)); @@ -423,7 +432,7 @@ messaging_menu_app_insert_source_action (MessagingMenuApp *app, return; } - action = g_simple_action_new_stateful (id, NULL, state); + action = g_tuple_action_new (id, state); g_signal_connect (action, "activate", G_CALLBACK (source_action_activated), app); g_simple_action_group_insert (app->source_actions, G_ACTION (action)); @@ -443,7 +452,8 @@ messaging_menu_app_insert_source_action (MessagingMenuApp *app, static void messaging_menu_app_set_source_action (MessagingMenuApp *app, const gchar *source_id, - GVariant *state) + gsize index, + GVariant *child) { GAction *action; @@ -457,7 +467,7 @@ messaging_menu_app_set_source_action (MessagingMenuApp *app, return; } - g_simple_action_set_state (G_SIMPLE_ACTION (action), state); + g_tuple_action_set_child (G_TUPLE_ACTION (action), index, child); } /** @@ -744,8 +754,8 @@ void messaging_menu_app_set_source_count (MessagingMenuApp *app, const gchar *source_id, guint count) { - messaging_menu_app_set_source_action (app, source_id, - g_variant_new ("(uxsb)", count, 0, "", FALSE)); + messaging_menu_app_set_source_action (app, source_id, INDEX_COUNT, + g_variant_new_uint32 (count)); } /** @@ -764,8 +774,8 @@ messaging_menu_app_set_source_time (MessagingMenuApp *app, const gchar *source_id, gint64 time) { - messaging_menu_app_set_source_action (app, source_id, - g_variant_new ("(uxsb)", 0, time, "", FALSE)); + messaging_menu_app_set_source_action (app, source_id, INDEX_TIME, + g_variant_new_int64 (time)); } /** @@ -784,37 +794,8 @@ messaging_menu_app_set_source_string (MessagingMenuApp *app, const gchar *source_id, const gchar *str) { - messaging_menu_app_set_source_action (app, source_id, - g_variant_new ("(uxsb)", 0, 0, str, FALSE)); -} - -static void -messaging_menu_app_set_attention (MessagingMenuApp *app, - const gchar *source_id, - gboolean attention) -{ - GAction *action; - GVariant *state; - guint32 count; - gint64 time; - const gchar *str =""; - - g_return_if_fail (MESSAGING_MENU_IS_APP (app)); - g_return_if_fail (source_id != NULL); - - action = g_simple_action_group_lookup (app->source_actions, source_id); - if (action == NULL) - { - g_warning ("a source with id '%s' doesn't exist", source_id); - return; - } - - state = g_action_get_state (action); - g_variant_get (state, "(ux&sb)", &count, &time, &str, NULL); - g_variant_unref (state); - - g_simple_action_set_state (G_SIMPLE_ACTION (action), - g_variant_new ("(uxsb)", count, time, str, attention)); + messaging_menu_app_set_source_action (app, source_id, INDEX_STRING, + g_variant_new_string (str)); } /** @@ -832,7 +813,8 @@ void messaging_menu_app_draw_attention (MessagingMenuApp *app, const gchar *source_id) { - messaging_menu_app_set_attention (app, source_id, TRUE); + messaging_menu_app_set_source_action (app, source_id, INDEX_DRAWS_ATTENTION, + g_variant_new_boolean (TRUE)); } /** @@ -849,5 +831,6 @@ void messaging_menu_app_remove_attention (MessagingMenuApp *app, const gchar *source_id) { - messaging_menu_app_set_attention (app, source_id, FALSE); + messaging_menu_app_set_source_action (app, source_id, INDEX_DRAWS_ATTENTION, + g_variant_new_boolean (FALSE)); } -- cgit v1.2.3 From 4c1f8ad57ce2f1865359d343c04dcfb1bedf2109 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Fri, 29 Jun 2012 19:56:56 +0200 Subject: X-MessagingMenu-UsesChatStatus --> X-MessagingMenu-UsesChatSection --- src/app-section.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app-section.c b/src/app-section.c index fb3d8f9..c5b0731 100644 --- a/src/app-section.c +++ b/src/app-section.c @@ -283,7 +283,7 @@ keyfile_loaded (GObject *source_object, self->priv->uses_chat_status = g_key_file_get_boolean (keyfile, G_KEY_FILE_DESKTOP_GROUP, - "X-MessagingMenu-UsesChatStatus", + "X-MessagingMenu-UsesChatSection", &error); if (error) { if (error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND) { -- cgit v1.2.3 From 3765e902d82758612288bada6dc0f887e124175f Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 30 Jul 2012 16:36:18 +0200 Subject: configure.ac: pass package name to AC_INIT GOBJECT_INTROSPECTION_CHECK depends on it (it needs $PACKAGE_NAME). --- configure.ac | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 5d6b190..d02dffa 100644 --- a/configure.ac +++ b/configure.ac @@ -1,10 +1,10 @@ -AC_INIT(src/indicator-messages.c) +AC_INIT(indicator-messages, 0.6.0) AC_PREREQ(2.53) AM_CONFIG_HEADER(config.h) -AM_INIT_AUTOMAKE(indicator-messages, 0.6.0) +AM_INIT_AUTOMAKE() AM_MAINTAINER_MODE @@ -191,4 +191,5 @@ Messaging Indicator Configuration: Indicator Dir: $INDICATORDIR gtest: $enable_tests gcov: $use_gcov + introspecion: $enable_introspection ]) -- cgit v1.2.3 From e5c3665070ddd5a968082a618123dcd0b70d1059 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 30 Jul 2012 16:38:12 +0200 Subject: Add introspection support --- Makefile.am | 2 +- configure.ac | 7 ++++++- libmessaging-menu/Makefile.am | 25 +++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index 9bd3903..ef08e41 100644 --- a/Makefile.am +++ b/Makefile.am @@ -17,7 +17,7 @@ endif -DISTCHECK_CONFIGURE_FLAGS = --enable-localinstall --enable-deprecations +DISTCHECK_CONFIGURE_FLAGS = --enable-localinstall --enable-deprecations --enable-introspection dist-hook: @if test -d "$(top_srcdir)/.bzr"; \ diff --git a/configure.ac b/configure.ac index d02dffa..dc56181 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ AC_INIT(indicator-messages, 0.6.0) -AC_PREREQ(2.53) +AC_PREREQ(2.62) AM_CONFIG_HEADER(config.h) AM_INIT_AUTOMAKE() @@ -43,6 +43,7 @@ GIO_UNIX_REQUIRED_VERSION=2.18 PANEL_REQUIRED_VERSION=2.0.0 INDICATOR_REQUIRED_VERSION=0.3.19 GLIB_REQUIRED_VERSION=2.31.20 +INTROSPECTION_REQUIRED_VERSION=1.32.0 PKG_CHECK_MODULES(APPLET, gtk+-3.0 >= $GTK_REQUIRED_VERSION gio-unix-2.0 >= $GIO_UNIX_REQUIRED_VERSION @@ -57,6 +58,10 @@ AC_SUBST(APPLET_LIBS) GLIB_GSETTINGS +GTK_DOC_CHECK([1.18], []) + +GOBJECT_INTROSPECTION_CHECK([$INTROSPECTION_REQUIRED_VERSION]) + ########################### # gcov coverage reporting ########################### diff --git a/libmessaging-menu/Makefile.am b/libmessaging-menu/Makefile.am index becaded..3799723 100644 --- a/libmessaging-menu/Makefile.am +++ b/libmessaging-menu/Makefile.am @@ -35,3 +35,28 @@ indicator-messages-service.h: indicator-messages-service.c pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = messaging-menu.pc + +-include $(INTROSPECTION_MAKEFILE) + +INTROSPECTION_GIRS = +INTROSPECTION_SCANNER_ARGS = --add-include-path=$(srcdir) +INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir) + +if HAVE_INTROSPECTION + +MessagingMenu-1.0.gir: libmessaging-menu.la +MessagingMenu_1_0_gir_NAMESPACE = MessagingMenu +MessagingMenu_1_0_gir_INCLUDES = GObject-2.0 Gio-2.0 +MessagingMenu_1_0_gir_CFLAGS = $(INCLUDES) $(GIO_CFLAGS) +MessagingMenu_1_0_gir_LIBS = libmessaging-menu.la +MessagingMenu_1_0_gir_FILES = $(libmessaging_menu_la_SOURCES) $(libmessaging_menu_la_HEADERS) +INTROSPECTION_GIRS += MessagingMenu-1.0.gir + +girdir = $(datadir)/gir-1.0 +gir_DATA = $(INTROSPECTION_GIRS) + +typelibdir = $(libdir)/girepository-1.0 +typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib) + +CLEANFILES +=$(gir_DATA) $(typelib_DATA) +endif -- cgit v1.2.3 From 2b1abaeccb3b07f609ceee8bd34f60eea78d9bbc Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Thu, 16 Aug 2012 19:59:39 +0200 Subject: Use the old libindicator API indicator-messages is the only indicator that communicates with its service through GMenuModel. This patch keeps the GMenuModel stuff, but creates the GtkMenu in the plugin instead of relying on unity-panel-service. --- src/indicator-messages.c | 103 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 90 insertions(+), 13 deletions(-) diff --git a/src/indicator-messages.c b/src/indicator-messages.c index 6278461..17e8677 100644 --- a/src/indicator-messages.c +++ b/src/indicator-messages.c @@ -54,7 +54,9 @@ struct _IndicatorMessages { IndicatorObject parent; IndicatorServiceManager * service; GActionGroup *actions; + GMenu *menu_wrapper; GMenuModel *menu; + GtkWidget *image; }; GType indicator_messages_get_type (void); @@ -72,10 +74,17 @@ static void indicator_messages_class_init (IndicatorMessagesClass *klass); static void indicator_messages_init (IndicatorMessages *self); static void indicator_messages_dispose (GObject *object); static void indicator_messages_finalize (GObject *object); -static GMenuModel * get_menu_model (IndicatorObject * io); -static GActionGroup * get_actions (IndicatorObject * io); +static GtkImage * get_image (IndicatorObject * io); +static GtkMenu * get_menu (IndicatorObject * io); static const gchar * get_accessible_desc (IndicatorObject * io); static const gchar * get_name_hint (IndicatorObject * io); +static void update_icon (IndicatorMessages * self); +static void update_menu (IndicatorMessages *self); +static void menu_items_changed (GMenuModel *menu, + gint position, + gint removed, + gint added, + gpointer user_data); G_DEFINE_TYPE (IndicatorMessages, indicator_messages, INDICATOR_OBJECT_TYPE); @@ -90,8 +99,8 @@ indicator_messages_class_init (IndicatorMessagesClass *klass) IndicatorObjectClass * io_class = INDICATOR_OBJECT_CLASS(klass); - io_class->get_menu_model = get_menu_model; - io_class->get_actions = get_actions; + io_class->get_image = get_image; + io_class->get_menu = get_menu; io_class->get_accessible_desc = get_accessible_desc; io_class->get_name_hint = get_name_hint; } @@ -124,6 +133,15 @@ indicator_messages_init (IndicatorMessages *self) INDICATOR_MESSAGES_DBUS_NAME, INDICATOR_MESSAGES_DBUS_OBJECT)); + g_signal_connect (self->menu, "items-changed", G_CALLBACK (menu_items_changed), self); + + self->image = g_object_ref_sink (gtk_image_new ()); + gtk_widget_show (self->image); + update_icon (self); + + self->menu_wrapper = g_menu_new (); + update_menu (self); + indicator = INDICATOR_OBJECT(self); g_object_unref (bus); @@ -141,8 +159,10 @@ indicator_messages_dispose (GObject *object) self->service = NULL; } + g_clear_object (&self->menu_wrapper); g_clear_object (&self->actions); g_clear_object (&self->menu); + g_clear_object (&self->image); G_OBJECT_CLASS (indicator_messages_parent_class)->dispose (object); return; @@ -168,31 +188,88 @@ struct _indicator_item_t { GtkWidget * right; }; -/* Builds the menu for the indicator */ -static GMenuModel * -get_menu_model (IndicatorObject * io) +static GtkImage * +get_image (IndicatorObject * io) { IndicatorMessages *self = INDICATOR_MESSAGES (io); - return self->menu; + + return GTK_IMAGE (self->image); } -static GActionGroup * -get_actions (IndicatorObject *io) +static GtkMenu * +get_menu (IndicatorObject * io) { IndicatorMessages *self = INDICATOR_MESSAGES (io); - return self->actions; + GtkWidget *menu; + + menu = gtk_menu_new_from_model (G_MENU_MODEL (self->menu_wrapper)); + gtk_widget_insert_action_group (menu, get_name_hint (io), self->actions); + + return GTK_MENU (menu); } -/* Returns the accessible description of the indicator */ static const gchar * get_accessible_desc (IndicatorObject * io) { return accessible_desc; } -/* Returns the name hint of the indicator */ static const gchar * get_name_hint (IndicatorObject *io) { return PACKAGE; } + +static void +update_icon (IndicatorMessages * self) +{ + const gchar *icon_name; + + if (g_menu_model_get_n_items (self->menu) == 0) + return; + + g_menu_model_get_item_attribute (self->menu, 0, INDICATOR_MENU_ATTRIBUTE_ICON_NAME, + "&s", &icon_name); + + gtk_image_set_from_icon_name (GTK_IMAGE (self->image), icon_name, GTK_ICON_SIZE_MENU); +} + +static void +update_menu (IndicatorMessages *self) +{ + GMenuModel *popup; + GMenuItem *item; + + if (g_menu_model_get_n_items (self->menu) == 0) + return; + + popup = g_menu_model_get_item_link (self->menu, 0, G_MENU_LINK_SUBMENU); + if (popup == NULL) + return; + + if (g_menu_model_get_n_items (G_MENU_MODEL (self->menu_wrapper)) == 1) + g_menu_remove (self->menu_wrapper, 0); + + item = g_menu_item_new_section (NULL, popup); + g_menu_item_set_attribute (item, "action-namespace", + "s", get_name_hint (INDICATOR_OBJECT (self))); + g_menu_append_item (self->menu_wrapper, item); + + g_object_unref (item); + g_object_unref (popup); +} + +static void +menu_items_changed (GMenuModel *menu, + gint position, + gint removed, + gint added, + gpointer user_data) +{ + IndicatorMessages *self = user_data; + + if (position == 0) { + update_icon (self); + update_menu (self); + } +} -- cgit v1.2.3 From ceebc0610fc101f25f64e4c45d08a1bee4fdfdd0 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Thu, 16 Aug 2012 20:02:51 +0200 Subject: panel plugin: remove unused global variables and struct --- src/indicator-messages.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/indicator-messages.c b/src/indicator-messages.c index 17e8677..8755a02 100644 --- a/src/indicator-messages.c +++ b/src/indicator-messages.c @@ -65,10 +65,6 @@ GType indicator_messages_get_type (void); INDICATOR_SET_VERSION INDICATOR_SET_TYPE(INDICATOR_MESSAGES_TYPE) -/* Globals */ -static const gchar * accessible_desc = NULL; -static IndicatorObject * indicator = NULL; - /* Prototypes */ static void indicator_messages_class_init (IndicatorMessagesClass *klass); static void indicator_messages_init (IndicatorMessages *self); @@ -142,8 +138,6 @@ indicator_messages_init (IndicatorMessages *self) self->menu_wrapper = g_menu_new (); update_menu (self); - indicator = INDICATOR_OBJECT(self); - g_object_unref (bus); } @@ -181,13 +175,6 @@ indicator_messages_finalize (GObject *object) /* Functions */ -typedef struct _indicator_item_t indicator_item_t; -struct _indicator_item_t { - GtkWidget * icon; - GtkWidget * label; - GtkWidget * right; -}; - static GtkImage * get_image (IndicatorObject * io) { @@ -211,7 +198,7 @@ get_menu (IndicatorObject * io) static const gchar * get_accessible_desc (IndicatorObject * io) { - return accessible_desc; + return NULL; } static const gchar * -- cgit v1.2.3 From 2c2d155860b16329d6f2c697b64cbe6f2ad639e2 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Thu, 16 Aug 2012 20:35:07 +0200 Subject: Set accessible description (statically to "Messages" for now) --- src/dbus-data.h | 1 + src/indicator-messages.c | 32 +++++++++++++++++++++++++++----- src/messages-service.c | 1 + 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/dbus-data.h b/src/dbus-data.h index bf82cf0..d5a309f 100644 --- a/src/dbus-data.h +++ b/src/dbus-data.h @@ -24,5 +24,6 @@ #define INDICATOR_MENU_ATTRIBUTE_VISIBLE "indicator-visible" #define INDICATOR_MENU_ATTRIBUTE_ENABLED "indicator-enabled" #define INDICATOR_MENU_ATTRIBUTE_ICON_NAME "indicator-icon-name" +#define INDICATOR_MENU_ATTRIBUTE_ACCESSIBLE_DESCRIPTION "indicator-accessible-description" #endif /* __DBUS_DATA_H__ */ diff --git a/src/indicator-messages.c b/src/indicator-messages.c index 8755a02..14833fd 100644 --- a/src/indicator-messages.c +++ b/src/indicator-messages.c @@ -57,6 +57,7 @@ struct _IndicatorMessages { GMenu *menu_wrapper; GMenuModel *menu; GtkWidget *image; + gchar *accessible_desc; }; GType indicator_messages_get_type (void); @@ -74,7 +75,7 @@ static GtkImage * get_image (IndicatorObject * io); static GtkMenu * get_menu (IndicatorObject * io); static const gchar * get_accessible_desc (IndicatorObject * io); static const gchar * get_name_hint (IndicatorObject * io); -static void update_icon (IndicatorMessages * self); +static void update_root_item (IndicatorMessages * self); static void update_menu (IndicatorMessages *self); static void menu_items_changed (GMenuModel *menu, gint position, @@ -133,7 +134,7 @@ indicator_messages_init (IndicatorMessages *self) self->image = g_object_ref_sink (gtk_image_new ()); gtk_widget_show (self->image); - update_icon (self); + update_root_item (self); self->menu_wrapper = g_menu_new (); update_menu (self); @@ -166,6 +167,9 @@ indicator_messages_dispose (GObject *object) static void indicator_messages_finalize (GObject *object) { + IndicatorMessages *self = INDICATOR_MESSAGES (object); + + g_free (self->accessible_desc); G_OBJECT_CLASS (indicator_messages_parent_class)->finalize (object); return; @@ -198,7 +202,8 @@ get_menu (IndicatorObject * io) static const gchar * get_accessible_desc (IndicatorObject * io) { - return NULL; + IndicatorMessages *self = INDICATOR_MESSAGES (io); + return self->accessible_desc; } static const gchar * @@ -208,7 +213,18 @@ get_name_hint (IndicatorObject *io) } static void -update_icon (IndicatorMessages * self) +indicator_messages_accessible_desc_updated (IndicatorMessages *self) +{ + GList *entries; + + entries = indicator_object_get_entries (INDICATOR_OBJECT (self)); + g_return_if_fail (entries != NULL); + + g_signal_emit_by_name (self, INDICATOR_OBJECT_SIGNAL_ACCESSIBLE_DESC_UPDATE, entries->data); +} + +static void +update_root_item (IndicatorMessages * self) { const gchar *icon_name; @@ -218,6 +234,12 @@ update_icon (IndicatorMessages * self) g_menu_model_get_item_attribute (self->menu, 0, INDICATOR_MENU_ATTRIBUTE_ICON_NAME, "&s", &icon_name); + g_free (self->accessible_desc); + + g_menu_model_get_item_attribute (self->menu, 0, INDICATOR_MENU_ATTRIBUTE_ACCESSIBLE_DESCRIPTION, + "s", &self->accessible_desc); + indicator_messages_accessible_desc_updated (self); + gtk_image_set_from_icon_name (GTK_IMAGE (self->image), icon_name, GTK_ICON_SIZE_MENU); } @@ -256,7 +278,7 @@ menu_items_changed (GMenuModel *menu, IndicatorMessages *self = user_data; if (position == 0) { - update_icon (self); + update_root_item (self); update_menu (self); } } diff --git a/src/messages-service.c b/src/messages-service.c index 6e88087..4b32006 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -504,6 +504,7 @@ main (int argc, char ** argv) header = g_menu_item_new (NULL, "messages"); g_menu_item_set_submenu (header, G_MENU_MODEL (menu)); g_menu_item_set_attribute (header, INDICATOR_MENU_ATTRIBUTE_ICON_NAME, "s", "indicator-messages"); + g_menu_item_set_attribute (header, INDICATOR_MENU_ATTRIBUTE_ACCESSIBLE_DESCRIPTION, "s", _("Messages")); g_menu_append_item (toplevel_menu, header); g_object_unref (header); -- cgit v1.2.3 From b15076d82a5a982f937b184da5adc904e303cbef Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Thu, 16 Aug 2012 20:38:08 +0200 Subject: Remove unused #defines --- src/dbus-data.h | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/src/dbus-data.h b/src/dbus-data.h index d5a309f..3c72b81 100644 --- a/src/dbus-data.h +++ b/src/dbus-data.h @@ -8,22 +8,7 @@ #define INDICATOR_MESSAGES_DBUS_SERVICE_OBJECT "/com/canonical/indicator/messages/service" #define INDICATOR_MESSAGES_DBUS_SERVICE_INTERFACE "com.canonical.indicator.messages.service" -#define APPLICATION_MENUITEM_TYPE "application-item" -#define APPLICATION_MENUITEM_PROP_NAME "label" -#define APPLICATION_MENUITEM_PROP_ICON "icon-name" -#define APPLICATION_MENUITEM_PROP_RUNNING "app-running" - -#define INDICATOR_MENUITEM_TYPE "indicator-item" -#define INDICATOR_MENUITEM_PROP_LABEL "indicator-label" -#define INDICATOR_MENUITEM_PROP_ICON "indicator-icon" -#define INDICATOR_MENUITEM_PROP_RIGHT "right-side-text" -#define INDICATOR_MENUITEM_PROP_RIGHT_IS_LOZENGE "right-is-lozenge" - -#define MAX_NUMBER_OF_INDICATORS 7 - -#define INDICATOR_MENU_ATTRIBUTE_VISIBLE "indicator-visible" -#define INDICATOR_MENU_ATTRIBUTE_ENABLED "indicator-enabled" -#define INDICATOR_MENU_ATTRIBUTE_ICON_NAME "indicator-icon-name" +#define INDICATOR_MENU_ATTRIBUTE_ICON_NAME "indicator-icon-name" #define INDICATOR_MENU_ATTRIBUTE_ACCESSIBLE_DESCRIPTION "indicator-accessible-description" #endif /* __DBUS_DATA_H__ */ -- cgit v1.2.3 From 8be3201de7ac246e759f74bfe35e53f742908800 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Fri, 17 Aug 2012 10:25:18 +0200 Subject: messages-service: disconnect all signals when removing a section --- src/messages-service.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/messages-service.c b/src/messages-service.c index 4b32006..a7355d0 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -201,6 +201,7 @@ remove_application (const char *desktop_id) g_signal_handlers_disconnect_by_func (section, actions_changed, NULL); g_signal_handlers_disconnect_by_func (section, draws_attention_changed, NULL); + g_signal_handlers_disconnect_by_func (section, uses_chat_status_changed, NULL); } else { g_warning ("could not remove '%s', it's not registered", desktop_id); -- cgit v1.2.3 From 75ae6cbac0dc1d2c423d27a4d9f460a87139f0fe Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Sun, 19 Aug 2012 15:41:23 -0500 Subject: add lars as co-author of app-section --- src/app-section.c | 3 ++- src/app-section.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/app-section.c b/src/app-section.c index c5b0731..f6cf15f 100644 --- a/src/app-section.c +++ b/src/app-section.c @@ -2,9 +2,10 @@ An indicator to show information that is in messaging applications that the user is using. -Copyright 2009 Canonical Ltd. +Copyright 2012 Canonical Ltd. Authors: + Lars Uebernickel Ted Gould This program is free software: you can redistribute it and/or modify it diff --git a/src/app-section.h b/src/app-section.h index c351ada..711fdc9 100644 --- a/src/app-section.h +++ b/src/app-section.h @@ -2,9 +2,10 @@ An indicator to show information that is in messaging applications that the user is using. -Copyright 2009 Canonical Ltd. +Copyright 2012 Canonical Ltd. Authors: + Lars Uebernickel Ted Gould This program is free software: you can redistribute it and/or modify it -- cgit v1.2.3 From 302ec8cd11ba3ec3a2d23d78bdd41974e92f63f6 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Sun, 19 Aug 2012 15:42:48 -0500 Subject: in app-section.c's dispose(), use g_clear_object() for priv.ids and priv.keyfile --- src/app-section.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/app-section.c b/src/app-section.c index f6cf15f..179be59 100644 --- a/src/app-section.c +++ b/src/app-section.c @@ -225,16 +225,8 @@ app_section_dispose (GObject *object) } g_clear_object (&priv->remote_menu); - - if (priv->ids != NULL) { - g_object_unref(priv->ids); - priv->ids = NULL; - } - - if (priv->appinfo != NULL) { - g_object_unref(priv->appinfo); - priv->appinfo = NULL; - } + g_clear_object (&priv->ids); + g_clear_object (&priv->appinfo); G_OBJECT_CLASS (app_section_parent_class)->dispose (object); } -- cgit v1.2.3 From ade3b76a6d41bf95b82e6c19b09c7142c79bf31e Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Sun, 19 Aug 2012 15:49:24 -0500 Subject: add sanity checks to args passed in the public API --- src/app-section.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/app-section.c b/src/app-section.c index 179be59..0b6a4b1 100644 --- a/src/app-section.c +++ b/src/app-section.c @@ -252,7 +252,7 @@ nick_activate_cb (GSimpleAction *action, static void keyfile_loaded (GObject *source_object, GAsyncResult *result, - gpointer user_data) + gpointer user_data) { AppSection *self = user_data; gchar *contents; @@ -408,6 +408,7 @@ app_section_get_desktop (AppSection * self) GActionGroup * app_section_get_actions (AppSection *self) { + g_return_val_if_fail(IS_APP_SECTION(self), NULL); AppSectionPrivate * priv = self->priv; return priv->actions ? priv->actions : G_ACTION_GROUP (priv->static_shortcuts); } @@ -415,6 +416,7 @@ app_section_get_actions (AppSection *self) GMenuModel * app_section_get_menu (AppSection *self) { + g_return_val_if_fail(IS_APP_SECTION(self), NULL); AppSectionPrivate * priv = self->priv; return G_MENU_MODEL (priv->menu); } @@ -422,6 +424,7 @@ app_section_get_menu (AppSection *self) GAppInfo * app_section_get_app_info (AppSection *self) { + g_return_val_if_fail(IS_APP_SECTION(self), NULL); AppSectionPrivate * priv = self->priv; return G_APP_INFO (priv->appinfo); } @@ -429,6 +432,7 @@ app_section_get_app_info (AppSection *self) gboolean app_section_get_draws_attention (AppSection *self) { + g_return_val_if_fail(IS_APP_SECTION(self), FALSE); AppSectionPrivate * priv = self->priv; return priv->draws_attention; } @@ -436,6 +440,7 @@ app_section_get_draws_attention (AppSection *self) void app_section_clear_draws_attention (AppSection *self) { + g_return_if_fail (IS_APP_SECTION(self)); AppSectionPrivate * priv = self->priv; gchar **action_names; gchar **it; @@ -498,6 +503,7 @@ app_section_set_object_path (AppSection *self, const gchar *bus_name, const gchar *object_path) { + g_return_if_fail (IS_APP_SECTION(self)); AppSectionPrivate *priv = self->priv; g_object_freeze_notify (G_OBJECT (self)); @@ -537,6 +543,7 @@ app_section_set_object_path (AppSection *self, void app_section_unset_object_path (AppSection *self) { + g_return_if_fail (IS_APP_SECTION(self)); AppSectionPrivate *priv = self->priv; if (priv->name_watch_id) { @@ -656,6 +663,7 @@ action_removed (GActionGroup *group, gboolean app_section_get_uses_chat_status (AppSection *self) { + g_return_val_if_fail (IS_APP_SECTION(self), FALSE); AppSectionPrivate * priv = self->priv; /* chat status is only useful when the app is running */ -- cgit v1.2.3 From 5b852d2f1fd35640ce94982c8078ce1603ed12a2 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Sun, 19 Aug 2012 16:24:42 -0500 Subject: in indicator-messages's dispose(), use g_clear_object() --- src/indicator-messages.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/indicator-messages.c b/src/indicator-messages.c index 14833fd..12109ca 100644 --- a/src/indicator-messages.c +++ b/src/indicator-messages.c @@ -149,11 +149,7 @@ indicator_messages_dispose (GObject *object) IndicatorMessages * self = INDICATOR_MESSAGES(object); g_return_if_fail(self != NULL); - if (self->service != NULL) { - g_object_unref(self->service); - self->service = NULL; - } - + g_clear_object (&self->service); g_clear_object (&self->menu_wrapper); g_clear_object (&self->actions); g_clear_object (&self->menu); -- cgit v1.2.3 From 666abf25d2fe9c71577040b2ef9cdba825c77668 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Sun, 19 Aug 2012 19:22:09 -0500 Subject: in indicator-messages' indicator_messages_accessible_desc_updated(), don't leak the entries GList --- src/indicator-messages.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/indicator-messages.c b/src/indicator-messages.c index 12109ca..162fd4d 100644 --- a/src/indicator-messages.c +++ b/src/indicator-messages.c @@ -217,6 +217,8 @@ indicator_messages_accessible_desc_updated (IndicatorMessages *self) g_return_if_fail (entries != NULL); g_signal_emit_by_name (self, INDICATOR_OBJECT_SIGNAL_ACCESSIBLE_DESC_UPDATE, entries->data); + + g_list_free (entries); } static void -- cgit v1.2.3 From d62fb5bcbc663b4f511f25963c06ec3d51eccdb8 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Sun, 19 Aug 2012 19:37:37 -0500 Subject: when removing an application in messages-service, disconnect the notify::uses-chat-status handler --- src/messages-service.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/messages-service.c b/src/messages-service.c index 4b32006..a7355d0 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -201,6 +201,7 @@ remove_application (const char *desktop_id) g_signal_handlers_disconnect_by_func (section, actions_changed, NULL); g_signal_handlers_disconnect_by_func (section, draws_attention_changed, NULL); + g_signal_handlers_disconnect_by_func (section, uses_chat_status_changed, NULL); } else { g_warning ("could not remove '%s', it's not registered", desktop_id); -- cgit v1.2.3 From d34fb7000e9b508b05c653b47bb60f35989c34f9 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Sun, 19 Aug 2012 23:34:49 -0500 Subject: in messages-service.c, make the functions create_action_group() and create_status_section() static --- src/messages-service.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/messages-service.c b/src/messages-service.c index a7355d0..ccd2eba 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -370,8 +370,8 @@ set_status (IndicatorMessagesService *service, indicator_messages_service_complete_set_status (service, invocation); } -GSimpleActionGroup * -create_action_group () +static GSimpleActionGroup * +create_action_group (void) { GSimpleActionGroup *actions; GSimpleAction *messages; @@ -400,8 +400,8 @@ create_action_group () return actions; } -GMenuModel * -create_status_section () +static GMenuModel * +create_status_section (void) { GMenu *menu; -- cgit v1.2.3 From 004314963a36bb48473ae58eccc9f5532225ab9b Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 20 Aug 2012 21:32:33 +0200 Subject: Use a custom menu item for application items This introduces ImAppMenuItem: a menu item which shows a small triangle next to an application's name if the associated app is running. The running state is communicated to the menu by giving the "launch" action a boolean state. This depends on a patch to gtk which creates custom menu items from gtk_menu_new_from_model when the x-canonical-type attribute is set on a menu item in the model. --- src/Makefile.am | 2 + src/app-section.c | 34 +++++- src/im-app-menu-item.c | 305 +++++++++++++++++++++++++++++++++++++++++++++++ src/im-app-menu-item.h | 54 +++++++++ src/indicator-messages.c | 6 + 5 files changed, 396 insertions(+), 5 deletions(-) create mode 100644 src/im-app-menu-item.c create mode 100644 src/im-app-menu-item.h diff --git a/src/Makefile.am b/src/Makefile.am index 1bc5b59..37009b7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -15,6 +15,8 @@ messaginglibdir = $(INDICATORDIR) messaginglib_LTLIBRARIES = libmessaging.la libmessaging_la_SOURCES = \ indicator-messages.c \ + im-app-menu-item.c \ + im-app-menu-item.h \ indicator-messages-service.c \ indicator-messages-service.h dbus-data.h diff --git a/src/app-section.c b/src/app-section.c index c5b0731..1627d40 100644 --- a/src/app-section.c +++ b/src/app-section.c @@ -77,6 +77,9 @@ static void app_section_dispose (GObject *object); static void activate_cb (GSimpleAction *action, GVariant *param, gpointer userdata); +static void launch_action_change_state (GSimpleAction *action, + GVariant *value, + gpointer user_data); static void app_section_set_app_info (AppSection *self, GDesktopAppInfo *appinfo); static gboolean any_action_draws_attention (GActionGroup *group, @@ -309,6 +312,8 @@ app_section_set_app_info (AppSection *self, AppSectionPrivate *priv = self->priv; GSimpleAction *launch; GFile *keyfile; + GMenuItem *item; + gchar *iconname; g_return_if_fail (priv->appinfo == NULL); @@ -319,14 +324,19 @@ app_section_set_app_info (AppSection *self, priv->appinfo = g_object_ref (appinfo); - launch = g_simple_action_new ("launch", NULL); + launch = g_simple_action_new_stateful ("launch", NULL, g_variant_new_boolean (FALSE)); g_signal_connect (launch, "activate", G_CALLBACK (activate_cb), self); + g_signal_connect (launch, "change-state", G_CALLBACK (launch_action_change_state), self); g_simple_action_group_insert (priv->static_shortcuts, G_ACTION (launch)); - g_menu_append_with_icon (priv->menu, - g_app_info_get_name (G_APP_INFO (priv->appinfo)), - g_app_info_get_icon (G_APP_INFO (priv->appinfo)), - "launch"); + item = g_menu_item_new (g_app_info_get_name (G_APP_INFO (priv->appinfo)), "launch"); + g_menu_item_set_attribute (item, "x-canonical-type", "s", "ImAppMenuItem"); + iconname = g_icon_to_string (g_app_info_get_icon (G_APP_INFO (priv->appinfo))); + g_menu_item_set_attribute (item, INDICATOR_MENU_ATTRIBUTE_ICON_NAME, "s", iconname); + g_free (iconname); + + g_menu_append_item (priv->menu, item); + g_object_unref (item); /* Start to build static shortcuts */ priv->ids = indicator_desktop_shortcuts_new(g_desktop_app_info_get_filename (priv->appinfo), "Messaging Menu"); @@ -380,6 +390,14 @@ activate_cb (GSimpleAction *action, } } +static void +launch_action_change_state (GSimpleAction *action, + GVariant *value, + gpointer user_data) +{ + g_simple_action_set_state (action, value); +} + guint app_section_get_count (AppSection * self) { @@ -531,6 +549,9 @@ app_section_set_object_path (AppSection *self, g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_USES_CHAT_STATUS]); g_object_thaw_notify (G_OBJECT (self)); + + g_action_group_change_action_state (G_ACTION_GROUP (priv->static_shortcuts), + "launch", g_variant_new_boolean (TRUE)); } /* @@ -572,6 +593,9 @@ app_section_unset_object_path (AppSection *self) g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACTIONS]); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]); g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_USES_CHAT_STATUS]); + + g_action_group_change_action_state (G_ACTION_GROUP (priv->static_shortcuts), + "launch", g_variant_new_boolean (FALSE)); } static gboolean diff --git a/src/im-app-menu-item.c b/src/im-app-menu-item.c new file mode 100644 index 0000000..f4430be --- /dev/null +++ b/src/im-app-menu-item.c @@ -0,0 +1,305 @@ +/* + * Copyright 2012 Canonical Ltd. + * + * 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 . + * + * Authors: + * Lars Uebernickel + */ + +#include "im-app-menu-item.h" + +struct _ImAppMenuItemPrivate +{ + GActionGroup *action_group; + gchar *action; + gboolean is_running; +}; + +enum +{ + PROP_0, + PROP_MENU_ITEM, + PROP_ACTION_GROUP, + NUM_PROPERTIES +}; + +static GParamSpec *properties[NUM_PROPERTIES]; + +G_DEFINE_TYPE (ImAppMenuItem, im_app_menu_item, GTK_TYPE_MENU_ITEM); + +static void +im_app_menu_item_set_action_name (ImAppMenuItem *self, + const gchar *action_name) +{ + ImAppMenuItemPrivate *priv = self->priv; + gboolean enabled = FALSE; + GVariant *state; + + if (priv->action != NULL) + g_free (priv->action); + + priv->action = g_strdup (action_name); + + priv->is_running = FALSE; + + if (priv->action_group != NULL && priv->action != NULL && + g_action_group_query_action (priv->action_group, priv->action, + &enabled, NULL, NULL, NULL, &state)) + { + if (state && g_variant_is_of_type (state, G_VARIANT_TYPE ("b"))) + priv->is_running = g_variant_get_boolean (state); + else + enabled = FALSE; + + if (state) + g_variant_unref (state); + } + + gtk_widget_set_sensitive (GTK_WIDGET (self), enabled); + gtk_widget_queue_draw (GTK_WIDGET (self)); +} + +static void +im_app_menu_item_action_added (GActionGroup *action_group, + gchar *action_name, + gpointer user_data) +{ + ImAppMenuItem *self = user_data; + + if (g_strcmp0 (self->priv->action, action_name) == 0) + im_app_menu_item_set_action_name (self, action_name); +} + +static void +im_app_menu_item_action_removed (GActionGroup *action_group, + gchar *action_name, + gpointer user_data) +{ + ImAppMenuItem *self = user_data; + + if (g_strcmp0 (self->priv->action, action_name) == 0) + { + gtk_widget_set_sensitive (GTK_WIDGET (self), FALSE); + self->priv->is_running = FALSE; + gtk_widget_queue_draw (GTK_WIDGET (self)); + } +} + +static void +im_app_menu_item_action_enabled_changed (GActionGroup *action_group, + gchar *action_name, + gboolean enabled, + gpointer user_data) +{ + ImAppMenuItem *self = user_data; + + if (g_strcmp0 (self->priv->action, action_name) == 0) + gtk_widget_set_sensitive (GTK_WIDGET (self), enabled); +} + +static void +im_app_menu_item_action_state_changed (GActionGroup *action_group, + gchar *action_name, + GVariant *value, + gpointer user_data) +{ + ImAppMenuItem *self = user_data; + + if (g_strcmp0 (self->priv->action, action_name) == 0) + { + g_return_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("b"))); + + self->priv->is_running = g_variant_get_boolean (value); + gtk_widget_queue_draw (GTK_WIDGET (self)); + } +} + +static void +im_app_menu_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + ImAppMenuItem *self = IM_APP_MENU_ITEM (object); + + switch (property_id) + { + case PROP_MENU_ITEM: + im_app_menu_item_set_menu_item (self, G_MENU_ITEM (g_value_get_object (value))); + break; + + case PROP_ACTION_GROUP: + im_app_menu_item_set_action_group (self, G_ACTION_GROUP (g_value_get_object (value))); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +im_app_menu_item_dispose (GObject *object) +{ + ImAppMenuItem *self = IM_APP_MENU_ITEM (object); + + if (self->priv->action_group) + im_app_menu_item_set_action_group (self, NULL); + + G_OBJECT_CLASS (im_app_menu_item_parent_class)->dispose (object); +} + +static void +im_app_menu_item_finalize (GObject *object) +{ + ImAppMenuItemPrivate *priv = IM_APP_MENU_ITEM (object)->priv; + + g_free (priv->action); + + G_OBJECT_CLASS (im_app_menu_item_parent_class)->finalize (object); +} + +static gboolean +im_app_menu_item_draw (GtkWidget *widget, + cairo_t *cr) +{ + ImAppMenuItemPrivate *priv = IM_APP_MENU_ITEM (widget)->priv; + + GTK_WIDGET_CLASS (im_app_menu_item_parent_class)->draw (widget, cr); + + if (priv->is_running) + { + const int arrow_width = 5; + const double half_arrow_height = 4.5; + GtkAllocation alloc; + GdkRGBA color; + double center; + + gtk_widget_get_allocation (widget, &alloc); + + gtk_style_context_get_color (gtk_widget_get_style_context (widget), + gtk_widget_get_state_flags (widget), + &color); + gdk_cairo_set_source_rgba (cr, &color); + + center = alloc.height / 2 + 0.5; + + cairo_move_to (cr, 0, center - half_arrow_height); + cairo_line_to (cr, 0, center + half_arrow_height); + cairo_line_to (cr, arrow_width, center); + cairo_close_path (cr); + + cairo_fill (cr); + } + + return FALSE; +} + +static void +im_app_menu_item_activate (GtkMenuItem *item) +{ + ImAppMenuItemPrivate *priv = IM_APP_MENU_ITEM (item)->priv; + + if (priv->action && priv->action_group) + g_action_group_activate_action (priv->action_group, priv->action, NULL); +} + +static void +im_app_menu_item_class_init (ImAppMenuItemClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + GtkMenuItemClass *menu_item_class = GTK_MENU_ITEM_CLASS (klass); + + g_type_class_add_private (klass, sizeof (ImAppMenuItemPrivate)); + + object_class->set_property = im_app_menu_set_property; + object_class->dispose = im_app_menu_item_dispose; + object_class->finalize = im_app_menu_item_finalize; + + widget_class->draw = im_app_menu_item_draw; + + menu_item_class->activate = im_app_menu_item_activate; + + properties[PROP_MENU_ITEM] = g_param_spec_object ("menu-item", + "Menu item", + "The model GMenuItem for this menu item", + G_TYPE_MENU_ITEM, + G_PARAM_WRITABLE | + G_PARAM_STATIC_STRINGS); + + properties[PROP_ACTION_GROUP] = g_param_spec_object ("action-group", + "Action group", + "The action group associated with this menu item", + G_TYPE_ACTION_GROUP, + G_PARAM_WRITABLE | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, NUM_PROPERTIES, properties); +} + +static void +im_app_menu_item_init (ImAppMenuItem *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + IM_TYPE_APP_MENU_ITEM, + ImAppMenuItemPrivate); +} + +void +im_app_menu_item_set_menu_item (ImAppMenuItem *self, + GMenuItem *menuitem) +{ + gchar *label; + gchar *action = NULL; + + g_menu_item_get_attribute (menuitem, "label", "s", &label); + gtk_menu_item_set_label (GTK_MENU_ITEM (self), label ? label : ""); + + g_menu_item_get_attribute (menuitem, "action", "s", &action); + im_app_menu_item_set_action_name (self, action); + + g_free (label); + g_free (action); +} + +void +im_app_menu_item_set_action_group (ImAppMenuItem *self, + GActionGroup *action_group) +{ + ImAppMenuItemPrivate *priv = self->priv; + + if (priv->action_group != NULL) + { + g_signal_handlers_disconnect_by_func (priv->action_group, im_app_menu_item_action_added, self); + g_signal_handlers_disconnect_by_func (priv->action_group, im_app_menu_item_action_removed, self); + g_signal_handlers_disconnect_by_func (priv->action_group, im_app_menu_item_action_enabled_changed, self); + g_signal_handlers_disconnect_by_func (priv->action_group, im_app_menu_item_action_state_changed, self); + + g_clear_object (&priv->action_group); + } + + if (action_group != NULL) + { + priv->action_group = g_object_ref (action_group); + + g_signal_connect (priv->action_group, "action-added", + G_CALLBACK (im_app_menu_item_action_added), self); + g_signal_connect (priv->action_group, "action-removed", + G_CALLBACK (im_app_menu_item_action_removed), self); + g_signal_connect (priv->action_group, "action-enabled-changed", + G_CALLBACK (im_app_menu_item_action_enabled_changed), self); + g_signal_connect (priv->action_group, "action-state-changed", + G_CALLBACK (im_app_menu_item_action_state_changed), self); + } +} diff --git a/src/im-app-menu-item.h b/src/im-app-menu-item.h new file mode 100644 index 0000000..519de8d --- /dev/null +++ b/src/im-app-menu-item.h @@ -0,0 +1,54 @@ +/* + * Copyright 2012 Canonical Ltd. + * + * 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 . + * + * Authors: + * Lars Uebernickel + */ + +#ifndef __IM_APP_MENU_ITEM_H__ +#define __IM_APP_MENU_ITEM_H__ + +#include + +#define IM_TYPE_APP_MENU_ITEM (im_app_menu_item_get_type ()) +#define IM_APP_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IM_TYPE_APP_MENU_ITEM, ImAppMenuItem)) +#define IM_APP_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), IM_TYPE_APP_MENU_ITEM, ImAppMenuItemClass)) +#define IS_IM_APP_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IM_TYPE_APP_MENU_ITEM)) +#define IS_IM_APP_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), IM_TYPE_APP_MENU_ITEM)) +#define IM_APP_MENU_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), IM_TYPE_APP_MENU_ITEM, ImAppMenuItemClass)) + +typedef struct _ImAppMenuItem ImAppMenuItem; +typedef struct _ImAppMenuItemClass ImAppMenuItemClass; +typedef struct _ImAppMenuItemPrivate ImAppMenuItemPrivate; + +struct _ImAppMenuItemClass +{ + GtkMenuItemClass parent_class; +}; + +struct _ImAppMenuItem +{ + GtkMenuItem parent; + ImAppMenuItemPrivate *priv; +}; + +GType im_app_menu_item_get_type (void); + +void im_app_menu_item_set_menu_item (ImAppMenuItem *item, + GMenuItem *menuitem); +void im_app_menu_item_set_action_group (ImAppMenuItem *self, + GActionGroup *action_group); + +#endif diff --git a/src/indicator-messages.c b/src/indicator-messages.c index 14833fd..67a28e9 100644 --- a/src/indicator-messages.c +++ b/src/indicator-messages.c @@ -36,6 +36,8 @@ with this program. If not, see . #include "dbus-data.h" +#include "im-app-menu-item.h" + #define INDICATOR_MESSAGES_TYPE (indicator_messages_get_type ()) #define INDICATOR_MESSAGES(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), INDICATOR_MESSAGES_TYPE, IndicatorMessages)) #define INDICATOR_MESSAGES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), INDICATOR_MESSAGES_TYPE, IndicatorMessagesClass)) @@ -140,6 +142,10 @@ indicator_messages_init (IndicatorMessages *self) update_menu (self); g_object_unref (bus); + + /* make sure custom menu item types are registered (so that + * gtk_model_new_from_menu can pick them up */ + im_app_menu_item_get_type (); } /* Unref stuff */ -- cgit v1.2.3 From daec6bad9a1a2c8a994b174e21e46f3865e45208 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 20 Aug 2012 22:08:15 +0200 Subject: Export both static shortcuts also when the app is running --- src/app-section.c | 49 ++++++++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/src/app-section.c b/src/app-section.c index 1627d40..d80e750 100644 --- a/src/app-section.c +++ b/src/app-section.c @@ -31,6 +31,7 @@ with this program. If not, see . #include "app-section.h" #include "dbus-data.h" #include "gmenuutils.h" +#include "gactionmuxer.h" struct _AppSectionPrivate { @@ -40,10 +41,11 @@ struct _AppSectionPrivate IndicatorDesktopShortcuts * ids; GMenu *menu; - GSimpleActionGroup *static_shortcuts; - GMenuModel *remote_menu; - GActionGroup *actions; + + GSimpleActionGroup *static_shortcuts; + GActionGroup *source_actions; + GActionMuxer *muxer; gboolean draws_attention; gboolean uses_chat_status; @@ -153,6 +155,9 @@ app_section_init (AppSection *self) priv->menu = g_menu_new (); priv->static_shortcuts = g_simple_action_group_new (); + priv->muxer = g_action_muxer_new (); + g_action_muxer_insert (priv->muxer, NULL, G_ACTION_GROUP (priv->static_shortcuts)); + priv->draws_attention = FALSE; return; @@ -217,13 +222,14 @@ app_section_dispose (GObject *object) priv->name_watch_id = 0; } - if (priv->actions) { - g_object_disconnect (priv->actions, + if (priv->source_actions) { + g_action_muxer_remove (priv->muxer, "source"); + g_object_disconnect (priv->source_actions, "any_signal::action-added", action_added, self, "any_signal::action-state-changed", action_state_changed, self, "any_signal::action-removed", action_removed, self, NULL); - g_clear_object (&priv->actions); + g_clear_object (&priv->source_actions); } g_clear_object (&priv->remote_menu); @@ -434,7 +440,7 @@ GActionGroup * app_section_get_actions (AppSection *self) { AppSectionPrivate * priv = self->priv; - return priv->actions ? priv->actions : G_ACTION_GROUP (priv->static_shortcuts); + return G_ACTION_GROUP (priv->muxer); } GMenuModel * @@ -465,15 +471,15 @@ app_section_clear_draws_attention (AppSection *self) gchar **action_names; gchar **it; - if (priv->actions == NULL) + if (priv->source_actions == NULL) return; - action_names = g_action_group_list_actions (priv->actions); + action_names = g_action_group_list_actions (priv->source_actions); for (it = action_names; *it; it++) { GVariant *state; - state = g_action_group_get_action_state (priv->actions, *it); + state = g_action_group_get_action_state (priv->source_actions, *it); if (!state) continue; @@ -487,7 +493,7 @@ app_section_clear_draws_attention (AppSection *self) g_variant_get (state, "(ux&sb)", &count, &time, &str, NULL); new_state = g_variant_new ("(uxsb)", count, time, str, FALSE); - g_action_group_change_action_state (priv->actions, *it, new_state); + g_action_group_change_action_state (priv->source_actions, *it, new_state); } g_variant_unref (state); @@ -524,14 +530,16 @@ app_section_set_object_path (AppSection *self, const gchar *object_path) { AppSectionPrivate *priv = self->priv; + GMenuItem *item; g_object_freeze_notify (G_OBJECT (self)); app_section_unset_object_path (self); - priv->actions = G_ACTION_GROUP (g_dbus_action_group_get (bus, bus_name, object_path)); + priv->source_actions = G_ACTION_GROUP (g_dbus_action_group_get (bus, bus_name, object_path)); + g_action_muxer_insert (priv->muxer, "source", priv->source_actions); - priv->draws_attention = any_action_draws_attention (priv->actions, NULL); - g_object_connect (priv->actions, + priv->draws_attention = any_action_draws_attention (priv->source_actions, NULL); + g_object_connect (priv->source_actions, "signal::action-added", action_added, self, "signal::action-state-changed", action_state_changed, self, "signal::action-removed", action_removed, self, @@ -539,7 +547,10 @@ app_section_set_object_path (AppSection *self, priv->remote_menu = G_MENU_MODEL (g_dbus_menu_model_get (bus, bus_name, object_path)); - g_menu_append_section (priv->menu, NULL, priv->remote_menu); + item = g_menu_item_new_section (NULL, priv->remote_menu); + g_menu_item_set_attribute (item, "action-namespace", "s", "source"); + g_menu_append_item (priv->menu, item); + g_object_unref (item); priv->name_watch_id = g_bus_watch_name_on_connection (bus, bus_name, 0, NULL, application_vanished, @@ -572,13 +583,13 @@ app_section_unset_object_path (AppSection *self) priv->name_watch_id = 0; } - if (priv->actions) { - g_object_disconnect (priv->actions, + if (priv->source_actions) { + g_object_disconnect (priv->source_actions, "any_signal::action-added", action_added, self, "any_signal::action-state-changed", action_state_changed, self, "any_signal::action-removed", action_removed, self, NULL); - g_clear_object (&priv->actions); + g_clear_object (&priv->source_actions); } if (priv->remote_menu) { @@ -690,5 +701,5 @@ app_section_get_uses_chat_status (AppSection *self) AppSectionPrivate * priv = self->priv; /* chat status is only useful when the app is running */ - return priv->uses_chat_status && priv->actions; + return priv->uses_chat_status && priv->source_actions; } -- cgit v1.2.3 From ce52ecafde8a9fccb22f870d98e396e3df7472cd Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 20 Aug 2012 22:10:17 +0200 Subject: app-section: rename remote_menu to source_menu Because it contains the message sources. --- src/app-section.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/app-section.c b/src/app-section.c index d80e750..9e83f13 100644 --- a/src/app-section.c +++ b/src/app-section.c @@ -41,7 +41,7 @@ struct _AppSectionPrivate IndicatorDesktopShortcuts * ids; GMenu *menu; - GMenuModel *remote_menu; + GMenuModel *source_menu; GSimpleActionGroup *static_shortcuts; GActionGroup *source_actions; @@ -232,7 +232,7 @@ app_section_dispose (GObject *object) g_clear_object (&priv->source_actions); } - g_clear_object (&priv->remote_menu); + g_clear_object (&priv->source_menu); if (priv->ids != NULL) { g_object_unref(priv->ids); @@ -545,9 +545,9 @@ app_section_set_object_path (AppSection *self, "signal::action-removed", action_removed, self, NULL); - priv->remote_menu = G_MENU_MODEL (g_dbus_menu_model_get (bus, bus_name, object_path)); + priv->source_menu = G_MENU_MODEL (g_dbus_menu_model_get (bus, bus_name, object_path)); - item = g_menu_item_new_section (NULL, priv->remote_menu); + item = g_menu_item_new_section (NULL, priv->source_menu); g_menu_item_set_attribute (item, "action-namespace", "s", "source"); g_menu_append_item (priv->menu, item); g_object_unref (item); @@ -592,11 +592,11 @@ app_section_unset_object_path (AppSection *self) g_clear_object (&priv->source_actions); } - if (priv->remote_menu) { + if (priv->source_menu) { /* the last menu item points is linked to the app's menumodel */ gint n_items = g_menu_model_get_n_items (G_MENU_MODEL (priv->menu)); g_menu_remove (priv->menu, n_items -1); - g_clear_object (&priv->remote_menu); + g_clear_object (&priv->source_menu); } priv->draws_attention = FALSE; -- cgit v1.2.3 From b64ac4ede11db0741077b7a427b659a6a06f2c92 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 20 Aug 2012 23:09:54 +0200 Subject: gtupleaction: set enabled to TRUE by default --- libmessaging-menu/gtupleaction.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libmessaging-menu/gtupleaction.c b/libmessaging-menu/gtupleaction.c index f9e6fd7..21bc003 100644 --- a/libmessaging-menu/gtupleaction.c +++ b/libmessaging-menu/gtupleaction.c @@ -312,6 +312,7 @@ g_tuple_action_class_init (GTupleActionClass *class) static void g_tuple_action_init (GTupleAction *action) { + action->enabled = TRUE; } GTupleAction * -- cgit v1.2.3 From 234c3cb933fcd422d9185b4bb01bed3223f0e791 Mon Sep 17 00:00:00 2001 From: Sebastien Bacher Date: Mon, 20 Aug 2012 23:16:04 +0200 Subject: libmessaging-menu: only export symbols tha t belong to the API --- libmessaging-menu/Makefile.am | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libmessaging-menu/Makefile.am b/libmessaging-menu/Makefile.am index 3799723..187e6dc 100644 --- a/libmessaging-menu/Makefile.am +++ b/libmessaging-menu/Makefile.am @@ -18,6 +18,8 @@ libmessaging_menu_la_CFLAGS = \ $(GIO_CFLAGS) \ -Wall +libmessaging_menu_la_LDFLAGS = -export-symbols-regex="^messaging_menu_.*" + BUILT_SOURCES = \ indicator-messages-service.c \ indicator-messages-service.h -- cgit v1.2.3 From 4e68daeee7fe848ce95157c18f1499335b0888fc Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Mon, 20 Aug 2012 23:44:39 +0200 Subject: Insert new app items right before the "Clear" item This still isn't as specified by design (should be alphabetically), but at least "Clear" is below the app items now. --- src/messages-service.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/messages-service.c b/src/messages-service.c index ccd2eba..aade829 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -168,7 +168,7 @@ add_application (const gchar *desktop_id) /* TODO insert it at the right position (alphabetically by application name) */ menuitem = g_menu_item_new_section (NULL, app_section_get_menu (section)); g_menu_item_set_attribute (menuitem, "action-namespace", "s", id); - g_menu_insert_item (menu, 2, menuitem); + g_menu_insert_item (menu, g_menu_model_get_n_items (G_MENU_MODEL (menu)) -1, menuitem); g_object_unref (menuitem); } -- cgit v1.2.3 From 91eb0b1a17c5bc9d0087fe807f373d1b8a8eb87b Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Tue, 21 Aug 2012 01:41:26 +0200 Subject: Use a custom menu item for message source menu items --- libmessaging-menu/messaging-menu.c | 1 + src/Makefile.am | 2 + src/im-source-menu-item.c | 278 +++++++++++++++++++++++++++++++++++++ src/im-source-menu-item.h | 54 +++++++ src/indicator-messages.c | 2 + 5 files changed, 337 insertions(+) create mode 100644 src/im-source-menu-item.c create mode 100644 src/im-source-menu-item.h diff --git a/libmessaging-menu/messaging-menu.c b/libmessaging-menu/messaging-menu.c index 22e4793..ea33cd6 100644 --- a/libmessaging-menu/messaging-menu.c +++ b/libmessaging-menu/messaging-menu.c @@ -439,6 +439,7 @@ messaging_menu_app_insert_source_action (MessagingMenuApp *app, g_object_unref (action); menuitem = g_menu_item_new (label, id); + g_menu_item_set_attribute (menuitem, "x-canonical-type", "s", "ImSourceMenuItem"); if (icon) { gchar *icon_name = g_icon_to_string (icon); diff --git a/src/Makefile.am b/src/Makefile.am index 37009b7..403a289 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -17,6 +17,8 @@ libmessaging_la_SOURCES = \ indicator-messages.c \ im-app-menu-item.c \ im-app-menu-item.h \ + im-source-menu-item.c \ + im-source-menu-item.h \ indicator-messages-service.c \ indicator-messages-service.h dbus-data.h diff --git a/src/im-source-menu-item.c b/src/im-source-menu-item.c new file mode 100644 index 0000000..82d553f --- /dev/null +++ b/src/im-source-menu-item.c @@ -0,0 +1,278 @@ +/* + * Copyright 2012 Canonical Ltd. + * + * 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 . + * + * Authors: + * Lars Uebernickel + */ + +#include "im-source-menu-item.h" + +struct _ImSourceMenuItemPrivate +{ + GActionGroup *action_group; + gchar *action; + + GtkWidget *label; +}; + +enum +{ + PROP_0, + PROP_MENU_ITEM, + PROP_ACTION_GROUP, + NUM_PROPERTIES +}; + +static GParamSpec *properties[NUM_PROPERTIES]; + +G_DEFINE_TYPE (ImSourceMenuItem, im_source_menu_item, GTK_TYPE_MENU_ITEM); + +static void +im_source_menu_item_constructed (GObject *object) +{ + ImSourceMenuItemPrivate *priv = IM_SOURCE_MENU_ITEM (object)->priv; + GtkWidget *grid; + gint icon_width; + + gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_width, NULL); + + priv->label = g_object_ref (gtk_label_new ("")); + gtk_widget_set_margin_left (priv->label, icon_width + 2); + + grid = gtk_grid_new (); + gtk_grid_attach (GTK_GRID (grid), priv->label, 0, 0, 1, 1); + + gtk_container_add (GTK_CONTAINER (object), grid); + gtk_widget_show_all (grid); + + G_OBJECT_CLASS (im_source_menu_item_parent_class)->constructed (object); +} + +static void +im_source_menu_item_set_action_name (ImSourceMenuItem *self, + const gchar *action_name) +{ + ImSourceMenuItemPrivate *priv = self->priv; + gboolean enabled = FALSE; + GVariant *state; + + if (priv->action != NULL) + g_free (priv->action); + + priv->action = g_strdup (action_name); + + if (priv->action_group != NULL && priv->action != NULL && + g_action_group_query_action (priv->action_group, priv->action, + &enabled, NULL, NULL, NULL, &state)) + { + if (!state || !g_variant_is_of_type (state, G_VARIANT_TYPE ("(uxsb)"))) + enabled = FALSE; + + if (state) + g_variant_unref (state); + } + + gtk_widget_set_sensitive (GTK_WIDGET (self), enabled); +} + +static void +im_source_menu_item_action_added (GActionGroup *action_group, + gchar *action_name, + gpointer user_data) +{ + ImSourceMenuItem *self = user_data; + + if (g_strcmp0 (self->priv->action, action_name) == 0) + im_source_menu_item_set_action_name (self, action_name); +} + +static void +im_source_menu_item_action_removed (GActionGroup *action_group, + gchar *action_name, + gpointer user_data) +{ + ImSourceMenuItem *self = user_data; + + if (g_strcmp0 (self->priv->action, action_name) == 0) + { + gtk_widget_set_sensitive (GTK_WIDGET (self), FALSE); + } +} + +static void +im_source_menu_item_action_enabled_changed (GActionGroup *action_group, + gchar *action_name, + gboolean enabled, + gpointer user_data) +{ + ImSourceMenuItem *self = user_data; + + if (g_strcmp0 (self->priv->action, action_name) == 0) + gtk_widget_set_sensitive (GTK_WIDGET (self), enabled); +} + +static void +im_source_menu_item_action_state_changed (GActionGroup *action_group, + gchar *action_name, + GVariant *value, + gpointer user_data) +{ + ImSourceMenuItem *self = user_data; + + if (g_strcmp0 (self->priv->action, action_name) == 0) + g_return_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("(uxsb)"))); +} + +static void +im_source_menu_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + ImSourceMenuItem *self = IM_SOURCE_MENU_ITEM (object); + + switch (property_id) + { + case PROP_MENU_ITEM: + im_source_menu_item_set_menu_item (self, G_MENU_ITEM (g_value_get_object (value))); + break; + + case PROP_ACTION_GROUP: + im_source_menu_item_set_action_group (self, G_ACTION_GROUP (g_value_get_object (value))); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +im_source_menu_item_dispose (GObject *object) +{ + ImSourceMenuItem *self = IM_SOURCE_MENU_ITEM (object); + + if (self->priv->action_group) + im_source_menu_item_set_action_group (self, NULL); + + G_OBJECT_CLASS (im_source_menu_item_parent_class)->dispose (object); +} + +static void +im_source_menu_item_finalize (GObject *object) +{ + ImSourceMenuItemPrivate *priv = IM_SOURCE_MENU_ITEM (object)->priv; + + g_free (priv->action); + + G_OBJECT_CLASS (im_source_menu_item_parent_class)->finalize (object); +} + +static void +im_source_menu_item_activate (GtkMenuItem *item) +{ + ImSourceMenuItemPrivate *priv = IM_SOURCE_MENU_ITEM (item)->priv; + + if (priv->action && priv->action_group) + g_action_group_activate_action (priv->action_group, priv->action, NULL); +} + +static void +im_source_menu_item_class_init (ImSourceMenuItemClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkMenuItemClass *menu_item_class = GTK_MENU_ITEM_CLASS (klass); + + g_type_class_add_private (klass, sizeof (ImSourceMenuItemPrivate)); + + object_class->constructed = im_source_menu_item_constructed; + object_class->set_property = im_source_menu_set_property; + object_class->dispose = im_source_menu_item_dispose; + object_class->finalize = im_source_menu_item_finalize; + + menu_item_class->activate = im_source_menu_item_activate; + + properties[PROP_MENU_ITEM] = g_param_spec_object ("menu-item", + "Menu item", + "The model GMenuItem for this menu item", + G_TYPE_MENU_ITEM, + G_PARAM_WRITABLE | + G_PARAM_STATIC_STRINGS); + + properties[PROP_ACTION_GROUP] = g_param_spec_object ("action-group", + "Action group", + "The action group associated with this menu item", + G_TYPE_ACTION_GROUP, + G_PARAM_WRITABLE | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, NUM_PROPERTIES, properties); +} + +static void +im_source_menu_item_init (ImSourceMenuItem *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + IM_TYPE_SOURCE_MENU_ITEM, + ImSourceMenuItemPrivate); + g_message (G_STRFUNC); +} + +void +im_source_menu_item_set_menu_item (ImSourceMenuItem *self, + GMenuItem *menuitem) +{ + gchar *label; + gchar *action = NULL; + + g_menu_item_get_attribute (menuitem, "label", "s", &label); + gtk_label_set_label (GTK_LABEL (self->priv->label), label ? label : ""); + + g_menu_item_get_attribute (menuitem, "action", "s", &action); + im_source_menu_item_set_action_name (self, action); + + g_free (label); + g_free (action); +} + +void +im_source_menu_item_set_action_group (ImSourceMenuItem *self, + GActionGroup *action_group) +{ + ImSourceMenuItemPrivate *priv = self->priv; + + if (priv->action_group != NULL) + { + g_signal_handlers_disconnect_by_func (priv->action_group, im_source_menu_item_action_added, self); + g_signal_handlers_disconnect_by_func (priv->action_group, im_source_menu_item_action_removed, self); + g_signal_handlers_disconnect_by_func (priv->action_group, im_source_menu_item_action_enabled_changed, self); + g_signal_handlers_disconnect_by_func (priv->action_group, im_source_menu_item_action_state_changed, self); + + g_clear_object (&priv->action_group); + } + + if (action_group != NULL) + { + priv->action_group = g_object_ref (action_group); + + g_signal_connect (priv->action_group, "action-added", + G_CALLBACK (im_source_menu_item_action_added), self); + g_signal_connect (priv->action_group, "action-removed", + G_CALLBACK (im_source_menu_item_action_removed), self); + g_signal_connect (priv->action_group, "action-enabled-changed", + G_CALLBACK (im_source_menu_item_action_enabled_changed), self); + g_signal_connect (priv->action_group, "action-state-changed", + G_CALLBACK (im_source_menu_item_action_state_changed), self); + } +} diff --git a/src/im-source-menu-item.h b/src/im-source-menu-item.h new file mode 100644 index 0000000..c359b94 --- /dev/null +++ b/src/im-source-menu-item.h @@ -0,0 +1,54 @@ +/* + * Copyright 2012 Canonical Ltd. + * + * 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 . + * + * Authors: + * Lars Uebernickel + */ + +#ifndef __IM_SOURCE_MENU_ITEM_H__ +#define __IM_SOURCE_MENU_ITEM_H__ + +#include + +#define IM_TYPE_SOURCE_MENU_ITEM (im_source_menu_item_get_type ()) +#define IM_SOURCE_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IM_TYPE_SOURCE_MENU_ITEM, ImSourceMenuItem)) +#define IM_SOURCE_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), IM_TYPE_SOURCE_MENU_ITEM, ImSourceMenuItemClass)) +#define IS_IM_SOURCE_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IM_TYPE_SOURCE_MENU_ITEM)) +#define IS_IM_SOURCE_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), IM_TYPE_SOURCE_MENU_ITEM)) +#define IM_SOURCE_MENU_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), IM_TYPE_SOURCE_MENU_ITEM, ImSourceMenuItemClass)) + +typedef struct _ImSourceMenuItem ImSourceMenuItem; +typedef struct _ImSourceMenuItemClass ImSourceMenuItemClass; +typedef struct _ImSourceMenuItemPrivate ImSourceMenuItemPrivate; + +struct _ImSourceMenuItemClass +{ + GtkMenuItemClass parent_class; +}; + +struct _ImSourceMenuItem +{ + GtkMenuItem parent; + ImSourceMenuItemPrivate *priv; +}; + +GType im_source_menu_item_get_type (void); + +void im_source_menu_item_set_menu_item (ImSourceMenuItem *item, + GMenuItem *menuitem); +void im_source_menu_item_set_action_group (ImSourceMenuItem *self, + GActionGroup *action_group); + +#endif diff --git a/src/indicator-messages.c b/src/indicator-messages.c index 4e8701a..d898ad6 100644 --- a/src/indicator-messages.c +++ b/src/indicator-messages.c @@ -37,6 +37,7 @@ with this program. If not, see . #include "dbus-data.h" #include "im-app-menu-item.h" +#include "im-source-menu-item.h" #define INDICATOR_MESSAGES_TYPE (indicator_messages_get_type ()) #define INDICATOR_MESSAGES(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), INDICATOR_MESSAGES_TYPE, IndicatorMessages)) @@ -146,6 +147,7 @@ indicator_messages_init (IndicatorMessages *self) /* make sure custom menu item types are registered (so that * gtk_model_new_from_menu can pick them up */ im_app_menu_item_get_type (); + im_source_menu_item_get_type (); } /* Unref stuff */ -- cgit v1.2.3 From 699c7421e9591326e1629e2fce586e0336623936 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Tue, 21 Aug 2012 10:52:42 +0200 Subject: ImSourceMenuItem: show source detail (count or time) --- src/im-source-menu-item.c | 116 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 113 insertions(+), 3 deletions(-) diff --git a/src/im-source-menu-item.c b/src/im-source-menu-item.c index 82d553f..b0c55f4 100644 --- a/src/im-source-menu-item.c +++ b/src/im-source-menu-item.c @@ -19,12 +19,15 @@ #include "im-source-menu-item.h" +#include + struct _ImSourceMenuItemPrivate { GActionGroup *action_group; gchar *action; GtkWidget *label; + GtkWidget *detail; }; enum @@ -51,8 +54,15 @@ im_source_menu_item_constructed (GObject *object) priv->label = g_object_ref (gtk_label_new ("")); gtk_widget_set_margin_left (priv->label, icon_width + 2); + priv->detail = g_object_ref (gtk_label_new ("")); + gtk_widget_set_halign (priv->detail, GTK_ALIGN_END); + gtk_widget_set_hexpand (priv->detail, TRUE); + gtk_misc_set_alignment (GTK_MISC (priv->label), 1.0, 0.5); + gtk_style_context_add_class (gtk_widget_get_style_context (priv->detail), "accelerator"); + grid = gtk_grid_new (); gtk_grid_attach (GTK_GRID (grid), priv->label, 0, 0, 1, 1); + gtk_grid_attach (GTK_GRID (grid), priv->detail, 1, 0, 1, 1); gtk_container_add (GTK_CONTAINER (object), grid); gtk_widget_show_all (grid); @@ -60,6 +70,104 @@ im_source_menu_item_constructed (GObject *object) G_OBJECT_CLASS (im_source_menu_item_parent_class)->constructed (object); } +/* collapse_whitespace: + * @str: the source string + * + * Collapses all occurences of consecutive whitespace charactes in @str + * into a single space. + * + * Returns: (transfer full): a newly-allocated string + */ +static gchar * +collapse_whitespace (const gchar *str) +{ + GString *result; + gboolean in_space = FALSE; + + if (str == NULL) + return NULL; + + result = g_string_new (""); + + while (*str) + { + gunichar c = g_utf8_get_char_validated (str, -1); + + if (c < 0) + break; + + if (!g_unichar_isspace (c)) + { + g_string_append_unichar (result, c); + in_space = FALSE; + } + else if (!in_space) + { + g_string_append_c (result, ' '); + in_space = TRUE; + } + + str = g_utf8_next_char (str); + } + + return g_string_free (result, FALSE); +} + +static gchar * +im_source_menu_item_time_span_string (gint64 timestamp) +{ + gchar *str; + gint64 span; + gint hours; + gint minutes; + + span = MAX (g_get_real_time () - timestamp, 0) / G_USEC_PER_SEC; + hours = span / 3600; + minutes = (span / 60) % 60; + + if (hours == 0) + { + /* TRANSLATORS: number of minutes that have passed */ + str = g_strdup_printf (ngettext ("%d m", "%d m", minutes), minutes); + } + else + { + /* TRANSLATORS: number of hours that have passed */ + str = g_strdup_printf (ngettext ("%d h", "%d h", hours), hours); + } + + return str; +} + +static gboolean +im_source_menu_item_set_state (ImSourceMenuItem *self, + GVariant *state) +{ + ImSourceMenuItemPrivate *priv = self->priv; + guint32 count; + gint64 time; + const gchar *str; + gchar *detail; + + g_return_val_if_fail (g_variant_is_of_type (state, G_VARIANT_TYPE ("(uxsb)")), FALSE); + + g_variant_get (state, "(ux&sb)", &count, &time, &str, NULL); + + if (count != 0) + detail = g_strdup_printf ("%d", count); + else if (time != 0) + detail = im_source_menu_item_time_span_string (time); + else if (str != NULL && *str) + detail = collapse_whitespace (str); + else + detail = NULL; + + gtk_label_set_text (GTK_LABEL (priv->detail), detail ? detail : ""); + + g_free (detail); + return TRUE; +} + static void im_source_menu_item_set_action_name (ImSourceMenuItem *self, const gchar *action_name) @@ -77,7 +185,7 @@ im_source_menu_item_set_action_name (ImSourceMenuItem *self, g_action_group_query_action (priv->action_group, priv->action, &enabled, NULL, NULL, NULL, &state)) { - if (!state || !g_variant_is_of_type (state, G_VARIANT_TYPE ("(uxsb)"))) + if (!state || !im_source_menu_item_set_state (self, state)) enabled = FALSE; if (state) @@ -132,7 +240,7 @@ im_source_menu_item_action_state_changed (GActionGroup *action_group, ImSourceMenuItem *self = user_data; if (g_strcmp0 (self->priv->action, action_name) == 0) - g_return_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("(uxsb)"))); + im_source_menu_item_set_state (self, value); } static void @@ -166,6 +274,9 @@ im_source_menu_item_dispose (GObject *object) if (self->priv->action_group) im_source_menu_item_set_action_group (self, NULL); + g_clear_object (&self->priv->label); + g_clear_object (&self->priv->detail); + G_OBJECT_CLASS (im_source_menu_item_parent_class)->dispose (object); } @@ -226,7 +337,6 @@ im_source_menu_item_init (ImSourceMenuItem *self) self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, IM_TYPE_SOURCE_MENU_ITEM, ImSourceMenuItemPrivate); - g_message (G_STRFUNC); } void -- cgit v1.2.3 From 7d036b65aac90b646eb7845cfc8e229464f372f0 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Tue, 21 Aug 2012 11:40:47 +0200 Subject: Show icons in application and source menu items Everthing goes through GIcon now, using g_icon_{to,new_for}_string to set a string attribute on the menu item. The attribute is prefixed x-canonical- for now. --- libmessaging-menu/messaging-menu.c | 6 ++--- src/app-section.c | 8 +++---- src/dbus-data.h | 3 --- src/gmenuutils.c | 2 +- src/im-app-menu-item.c | 47 +++++++++++++++++++++++++++++++++++++- src/im-source-menu-item.c | 28 ++++++++++++++++++++--- src/indicator-messages.c | 25 +++++++++++++++----- src/messages-service.c | 11 +++++++-- 8 files changed, 107 insertions(+), 23 deletions(-) diff --git a/libmessaging-menu/messaging-menu.c b/libmessaging-menu/messaging-menu.c index ea33cd6..336e89c 100644 --- a/libmessaging-menu/messaging-menu.c +++ b/libmessaging-menu/messaging-menu.c @@ -442,9 +442,9 @@ messaging_menu_app_insert_source_action (MessagingMenuApp *app, g_menu_item_set_attribute (menuitem, "x-canonical-type", "s", "ImSourceMenuItem"); if (icon) { - gchar *icon_name = g_icon_to_string (icon); - g_menu_item_set_attribute (menuitem, "indicator-icon-name", icon_name); - g_free (icon_name); + gchar *iconstr = g_icon_to_string (icon); + g_menu_item_set_attribute (menuitem, "x-canonical-icon", "s", iconstr); + g_free (iconstr); } g_menu_insert_item (app->menu, position, menuitem); g_object_unref (menuitem); diff --git a/src/app-section.c b/src/app-section.c index 1602ac6..70bf21e 100644 --- a/src/app-section.c +++ b/src/app-section.c @@ -312,7 +312,7 @@ app_section_set_app_info (AppSection *self, GSimpleAction *launch; GFile *keyfile; GMenuItem *item; - gchar *iconname; + gchar *iconstr; g_return_if_fail (priv->appinfo == NULL); @@ -330,9 +330,9 @@ app_section_set_app_info (AppSection *self, item = g_menu_item_new (g_app_info_get_name (G_APP_INFO (priv->appinfo)), "launch"); g_menu_item_set_attribute (item, "x-canonical-type", "s", "ImAppMenuItem"); - iconname = g_icon_to_string (g_app_info_get_icon (G_APP_INFO (priv->appinfo))); - g_menu_item_set_attribute (item, INDICATOR_MENU_ATTRIBUTE_ICON_NAME, "s", iconname); - g_free (iconname); + iconstr = g_icon_to_string (g_app_info_get_icon (G_APP_INFO (priv->appinfo))); + g_menu_item_set_attribute (item, "x-canonical-icon", "s", iconstr); + g_free (iconstr); g_menu_append_item (priv->menu, item); g_object_unref (item); diff --git a/src/dbus-data.h b/src/dbus-data.h index 3c72b81..64747a9 100644 --- a/src/dbus-data.h +++ b/src/dbus-data.h @@ -8,7 +8,4 @@ #define INDICATOR_MESSAGES_DBUS_SERVICE_OBJECT "/com/canonical/indicator/messages/service" #define INDICATOR_MESSAGES_DBUS_SERVICE_INTERFACE "com.canonical.indicator.messages.service" -#define INDICATOR_MENU_ATTRIBUTE_ICON_NAME "indicator-icon-name" -#define INDICATOR_MENU_ATTRIBUTE_ACCESSIBLE_DESCRIPTION "indicator-accessible-description" - #endif /* __DBUS_DATA_H__ */ diff --git a/src/gmenuutils.c b/src/gmenuutils.c index 056e75f..f3ceba7 100644 --- a/src/gmenuutils.c +++ b/src/gmenuutils.c @@ -71,7 +71,7 @@ g_menu_append_with_icon_name (GMenu *menu, GMenuItem *item; item = g_menu_item_new (label, detailed_action); - g_menu_item_set_attribute (item, INDICATOR_MENU_ATTRIBUTE_ICON_NAME, "s", icon_name); + g_menu_item_set_attribute (item, "x-canonical-icon", "s", icon_name); g_menu_append_item (menu, item); diff --git a/src/im-app-menu-item.c b/src/im-app-menu-item.c index f4430be..eddf562 100644 --- a/src/im-app-menu-item.c +++ b/src/im-app-menu-item.c @@ -24,6 +24,9 @@ struct _ImAppMenuItemPrivate GActionGroup *action_group; gchar *action; gboolean is_running; + + GtkWidget *icon; + GtkWidget *label; }; enum @@ -38,6 +41,26 @@ static GParamSpec *properties[NUM_PROPERTIES]; G_DEFINE_TYPE (ImAppMenuItem, im_app_menu_item, GTK_TYPE_MENU_ITEM); +static void +im_app_menu_item_constructed (GObject *object) +{ + ImAppMenuItemPrivate *priv = IM_APP_MENU_ITEM (object)->priv; + GtkWidget *grid; + + priv->icon = g_object_ref (gtk_image_new ()); + + priv->label = g_object_ref (gtk_label_new ("")); + + grid = gtk_grid_new (); + gtk_grid_attach (GTK_GRID (grid), priv->icon, 0, 0, 1, 1); + gtk_grid_attach (GTK_GRID (grid), priv->label, 1, 0, 1, 1); + + gtk_container_add (GTK_CONTAINER (object), grid); + gtk_widget_show_all (grid); + + G_OBJECT_CLASS (im_app_menu_item_parent_class)->constructed (object); +} + static void im_app_menu_item_set_action_name (ImAppMenuItem *self, const gchar *action_name) @@ -156,6 +179,9 @@ im_app_menu_item_dispose (GObject *object) if (self->priv->action_group) im_app_menu_item_set_action_group (self, NULL); + g_clear_object (&self->priv->icon); + g_clear_object (&self->priv->label); + G_OBJECT_CLASS (im_app_menu_item_parent_class)->dispose (object); } @@ -223,6 +249,7 @@ im_app_menu_item_class_init (ImAppMenuItemClass *klass) g_type_class_add_private (klass, sizeof (ImAppMenuItemPrivate)); + object_class->constructed = im_app_menu_item_constructed; object_class->set_property = im_app_menu_set_property; object_class->dispose = im_app_menu_item_dispose; object_class->finalize = im_app_menu_item_finalize; @@ -260,15 +287,33 @@ void im_app_menu_item_set_menu_item (ImAppMenuItem *self, GMenuItem *menuitem) { + gchar *iconstr = NULL; + GIcon *icon = NULL; gchar *label; gchar *action = NULL; + if (g_menu_item_get_attribute (menuitem, "x-canonical-icon", "s", &iconstr)) + { + GError *error; + + icon = g_icon_new_for_string (iconstr, &error); + if (icon == NULL) + { + g_warning ("unable to set icon: %s", error->message); + g_error_free (error); + } + g_free (iconstr); + } + gtk_image_set_from_gicon (GTK_IMAGE (self->priv->icon), icon, GTK_ICON_SIZE_MENU); + g_menu_item_get_attribute (menuitem, "label", "s", &label); - gtk_menu_item_set_label (GTK_MENU_ITEM (self), label ? label : ""); + gtk_label_set_label (GTK_LABEL (self->priv->label), label ? label : ""); g_menu_item_get_attribute (menuitem, "action", "s", &action); im_app_menu_item_set_action_name (self, action); + if (icon) + g_object_unref (icon); g_free (label); g_free (action); } diff --git a/src/im-source-menu-item.c b/src/im-source-menu-item.c index b0c55f4..269c75d 100644 --- a/src/im-source-menu-item.c +++ b/src/im-source-menu-item.c @@ -26,6 +26,7 @@ struct _ImSourceMenuItemPrivate GActionGroup *action_group; gchar *action; + GtkWidget *icon; GtkWidget *label; GtkWidget *detail; }; @@ -51,8 +52,10 @@ im_source_menu_item_constructed (GObject *object) gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_width, NULL); + priv->icon = g_object_ref (gtk_image_new ()); + gtk_widget_set_margin_left (priv->icon, icon_width + 2); + priv->label = g_object_ref (gtk_label_new ("")); - gtk_widget_set_margin_left (priv->label, icon_width + 2); priv->detail = g_object_ref (gtk_label_new ("")); gtk_widget_set_halign (priv->detail, GTK_ALIGN_END); @@ -61,8 +64,9 @@ im_source_menu_item_constructed (GObject *object) gtk_style_context_add_class (gtk_widget_get_style_context (priv->detail), "accelerator"); grid = gtk_grid_new (); - gtk_grid_attach (GTK_GRID (grid), priv->label, 0, 0, 1, 1); - gtk_grid_attach (GTK_GRID (grid), priv->detail, 1, 0, 1, 1); + gtk_grid_attach (GTK_GRID (grid), priv->icon, 0, 0, 1, 1); + gtk_grid_attach (GTK_GRID (grid), priv->label, 1, 0, 1, 1); + gtk_grid_attach (GTK_GRID (grid), priv->detail, 2, 0, 1, 1); gtk_container_add (GTK_CONTAINER (object), grid); gtk_widget_show_all (grid); @@ -274,6 +278,7 @@ im_source_menu_item_dispose (GObject *object) if (self->priv->action_group) im_source_menu_item_set_action_group (self, NULL); + g_clear_object (&self->priv->icon); g_clear_object (&self->priv->label); g_clear_object (&self->priv->detail); @@ -343,15 +348,32 @@ void im_source_menu_item_set_menu_item (ImSourceMenuItem *self, GMenuItem *menuitem) { + gchar *iconstr = NULL; + GIcon *icon = NULL; gchar *label; gchar *action = NULL; + if (g_menu_item_get_attribute (menuitem, "x-canonical-icon", "s", &iconstr)) + { + GError *error; + icon = g_icon_new_for_string (iconstr, &error); + if (icon == NULL) + { + g_warning ("unable to set icon: %s", error->message); + g_error_free (error); + } + g_free (iconstr); + } + gtk_image_set_from_gicon (GTK_IMAGE (self->priv->icon), icon, GTK_ICON_SIZE_MENU); + g_menu_item_get_attribute (menuitem, "label", "s", &label); gtk_label_set_label (GTK_LABEL (self->priv->label), label ? label : ""); g_menu_item_get_attribute (menuitem, "action", "s", &action); im_source_menu_item_set_action_name (self, action); + if (icon) + g_object_unref (icon); g_free (label); g_free (action); } diff --git a/src/indicator-messages.c b/src/indicator-messages.c index d898ad6..2824b0c 100644 --- a/src/indicator-messages.c +++ b/src/indicator-messages.c @@ -232,21 +232,34 @@ indicator_messages_accessible_desc_updated (IndicatorMessages *self) static void update_root_item (IndicatorMessages * self) { - const gchar *icon_name; + gchar *iconstr; if (g_menu_model_get_n_items (self->menu) == 0) return; - g_menu_model_get_item_attribute (self->menu, 0, INDICATOR_MENU_ATTRIBUTE_ICON_NAME, - "&s", &icon_name); + if (g_menu_model_get_item_attribute (self->menu, 0, "x-canonical-icon", "s", &iconstr)) { + GIcon *icon; + GError *error; + + icon = g_icon_new_for_string (iconstr, &error); + if (icon) { + gtk_image_set_from_gicon (GTK_IMAGE (self->image), icon, GTK_ICON_SIZE_MENU); + g_object_unref (icon); + } + else { + g_warning ("unable to load icon: %s", error->message); + g_error_free (error); + } + + g_free (iconstr); + } g_free (self->accessible_desc); + self->accessible_desc = NULL; - g_menu_model_get_item_attribute (self->menu, 0, INDICATOR_MENU_ATTRIBUTE_ACCESSIBLE_DESCRIPTION, + g_menu_model_get_item_attribute (self->menu, 0, "x-canonical-accessible-description", "s", &self->accessible_desc); indicator_messages_accessible_desc_updated (self); - - gtk_image_set_from_icon_name (GTK_IMAGE (self->image), icon_name, GTK_ICON_SIZE_MENU); } static void diff --git a/src/messages-service.c b/src/messages-service.c index aade829..7654e1f 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -464,6 +464,8 @@ main (int argc, char ** argv) GMainLoop * mainloop = NULL; IndicatorService * service = NULL; GMenuItem *header; + GIcon *icon; + gchar *iconstr; /* Glib init */ g_type_init(); @@ -501,11 +503,14 @@ main (int argc, char ** argv) chat_section = create_status_section (); g_menu_append (menu, _("Clear"), "clear"); + icon = g_themed_icon_new ("indicator-messages"); + iconstr = g_icon_to_string (icon); + toplevel_menu = g_menu_new (); header = g_menu_item_new (NULL, "messages"); g_menu_item_set_submenu (header, G_MENU_MODEL (menu)); - g_menu_item_set_attribute (header, INDICATOR_MENU_ATTRIBUTE_ICON_NAME, "s", "indicator-messages"); - g_menu_item_set_attribute (header, INDICATOR_MENU_ATTRIBUTE_ACCESSIBLE_DESCRIPTION, "s", _("Messages")); + g_menu_item_set_attribute (header, "x-canonical-icon", "s", iconstr); + g_menu_item_set_attribute (header, "x-canonical-accessible-description", "s", _("Messages")); g_menu_append_item (toplevel_menu, header); g_object_unref (header); @@ -518,6 +523,8 @@ main (int argc, char ** argv) g_main_loop_run(mainloop); /* Clean up */ + g_free (iconstr); + g_object_unref (icon); g_object_unref (messages_service); g_object_unref (chat_section); g_object_unref (settings); -- cgit v1.2.3 From 5df53a2c98d806f3b266d0032986d4dab3beb7a3 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Tue, 21 Aug 2012 12:03:21 +0200 Subject: Fix out-of-tree builds (for make distcheck) --- po/POTFILES.in | 1 - test/Makefile.am | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/po/POTFILES.in b/po/POTFILES.in index 21cd0b1..edb0388 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -1,4 +1,3 @@ [encoding: UTF-8] -src/messages-service-dbus.c src/indicator-messages.c src/messages-service.c diff --git a/test/Makefile.am b/test/Makefile.am index ebf2da2..4671446 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -38,8 +38,8 @@ noinst_LTLIBRARIES = \ libindicator-messages-service.la libindicator_messages_service_la_SOURCES = \ - $(top_srcdir)/src/indicator-messages-service.c \ - $(top_srcdir)/src/indicator-messages-service.h \ + $(top_builddir)/src/indicator-messages-service.c \ + $(top_builddir)/src/indicator-messages-service.h \ $(top_srcdir)/src/app-section.c \ $(top_srcdir)/src/app-section.h \ $(top_srcdir)/src/gactionmuxer.c \ @@ -52,6 +52,7 @@ libindicator_messages_service_ladir = \ libindicator_messages_service_la_CFLAGS = \ $(APPLET_CFLAGS) \ $(COVERAGE_CFLAGS) \ + -I$(top_builddir)/src \ -Wall \ -Wl,-Bsymbolic-functions \ -Wl,-z,defs \ -- cgit v1.2.3 From ee34069e5e7c4679a5882e37aca805fb5234d5d9 Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Tue, 21 Aug 2012 12:26:45 +0200 Subject: Update remaining license headers --- src/indicator-messages.c | 3 ++- src/messages-service.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/indicator-messages.c b/src/indicator-messages.c index 2824b0c..946da55 100644 --- a/src/indicator-messages.c +++ b/src/indicator-messages.c @@ -2,10 +2,11 @@ An indicator to show information that is in messaging applications that the user is using. -Copyright 2009 Canonical Ltd. +Copyright 2012 Canonical Ltd. Authors: Ted Gould + Lars Uebernickel 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 diff --git a/src/messages-service.c b/src/messages-service.c index 7654e1f..407b8ba 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -2,10 +2,11 @@ An indicator to show information that is in messaging applications that the user is using. -Copyright 2009 Canonical Ltd. +Copyright 2012 Canonical Ltd. Authors: Ted Gould + Lars Uebernickel 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 -- cgit v1.2.3 From e3c2920cf5d1f08466bc93a79a9642525eec838e Mon Sep 17 00:00:00 2001 From: Lars Uebernickel Date: Tue, 21 Aug 2012 12:32:15 +0200 Subject: 12.10.0 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index dc56181..f9f00e9 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ -AC_INIT(indicator-messages, 0.6.0) +AC_INIT(indicator-messages, 12.10.0) AC_PREREQ(2.62) -- cgit v1.2.3