diff options
-rw-r--r-- | configure.ac | 9 | ||||
-rw-r--r-- | libmessaging-menu/messaging-menu.c | 6 | ||||
-rw-r--r-- | po/POTFILES.in | 1 | ||||
-rw-r--r-- | src/app-section.c | 8 | ||||
-rw-r--r-- | src/dbus-data.h | 3 | ||||
-rw-r--r-- | src/gmenuutils.c | 2 | ||||
-rw-r--r-- | src/im-app-menu-item.c | 47 | ||||
-rw-r--r-- | src/im-source-menu-item.c | 142 | ||||
-rw-r--r-- | src/indicator-messages.c | 28 | ||||
-rw-r--r-- | src/messages-service.c | 14 | ||||
-rw-r--r-- | test/Makefile.am | 5 |
11 files changed, 230 insertions, 35 deletions
diff --git a/configure.ac b/configure.ac index dc56181..d9270dd 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) @@ -38,11 +38,10 @@ AC_PROG_CXX # Dependencies ########################### -GTK_REQUIRED_VERSION=3.0 -GIO_UNIX_REQUIRED_VERSION=2.18 -PANEL_REQUIRED_VERSION=2.0.0 +GTK_REQUIRED_VERSION=3.5.12 +GIO_UNIX_REQUIRED_VERSION=2.33.10 INDICATOR_REQUIRED_VERSION=0.3.19 -GLIB_REQUIRED_VERSION=2.31.20 +GLIB_REQUIRED_VERSION=2.33.10 INTROSPECTION_REQUIRED_VERSION=1.32.0 PKG_CHECK_MODULES(APPLET, gtk+-3.0 >= $GTK_REQUIRED_VERSION 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/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/src/app-section.c b/src/app-section.c index f922dca..1574892 100644 --- a/src/app-section.c +++ b/src/app-section.c @@ -314,7 +314,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); @@ -332,9 +332,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 @@ -39,6 +42,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 82d553f..269c75d 100644 --- a/src/im-source-menu-item.c +++ b/src/im-source-menu-item.c @@ -19,12 +19,16 @@ #include "im-source-menu-item.h" +#include <libintl.h> + struct _ImSourceMenuItemPrivate { GActionGroup *action_group; gchar *action; + GtkWidget *icon; GtkWidget *label; + GtkWidget *detail; }; enum @@ -48,11 +52,21 @@ 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); + 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->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); @@ -60,6 +74,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 +189,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 +244,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 +278,10 @@ 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); + G_OBJECT_CLASS (im_source_menu_item_parent_class)->dispose (object); } @@ -226,22 +342,38 @@ 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 *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..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 <ted@canonical.com> + Lars Uebernickel <lars.uebernickel@canonical.com> This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published @@ -232,21 +233,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..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 <ted@canonical.com> + Lars Uebernickel <lars.uebernickel@canonical.com> This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published @@ -464,6 +465,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 +504,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 +524,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); 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 \ |