aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/Makefile.in14
-rw-r--r--src/app-section.c26
-rw-r--r--src/gmenuutils.c10
-rw-r--r--src/ido-menu-item.c395
-rw-r--r--src/ido-menu-item.h54
-rw-r--r--src/im-app-menu-item.c1
-rw-r--r--src/im-source-menu-item.c36
-rw-r--r--src/indicator-messages-service.c2
-rw-r--r--src/indicator-messages-service.h2
-rw-r--r--src/indicator-messages.c121
-rw-r--r--src/messages-service.c32
12 files changed, 633 insertions, 62 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 403a289..4d86730 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 \
+ ido-menu-item.c \
+ ido-menu-item.h \
im-app-menu-item.c \
im-app-menu-item.h \
im-source-menu-item.c \
diff --git a/src/Makefile.in b/src/Makefile.in
index d95ba26..9fe1c45 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -60,7 +60,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/gcov.m4 \
$(top_srcdir)/m4/gtest.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
-mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
@@ -97,6 +97,7 @@ LTLIBRARIES = $(messaginglib_LTLIBRARIES)
am__DEPENDENCIES_1 =
libmessaging_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
am_libmessaging_la_OBJECTS = libmessaging_la-indicator-messages.lo \
+ libmessaging_la-ido-menu-item.lo \
libmessaging_la-im-app-menu-item.lo \
libmessaging_la-im-source-menu-item.lo \
libmessaging_la-indicator-messages-service.lo
@@ -220,7 +221,6 @@ GTKDOC_MKPDF = @GTKDOC_MKPDF@
GTKDOC_REBASE = @GTKDOC_REBASE@
HTML_DIR = @HTML_DIR@
INDICATORDIR = @INDICATORDIR@
-INDICATORICONSDIR = @INDICATORICONSDIR@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
@@ -360,6 +360,8 @@ messaginglibdir = $(INDICATORDIR)
messaginglib_LTLIBRARIES = libmessaging.la
libmessaging_la_SOURCES = \
indicator-messages.c \
+ ido-menu-item.c \
+ ido-menu-item.h \
im-app-menu-item.c \
im-app-menu-item.h \
im-source-menu-item.c \
@@ -547,6 +549,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/indicator_messages_service-gsettingsstrv.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/indicator_messages_service-indicator-messages-service.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/indicator_messages_service-messages-service.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmessaging_la-ido-menu-item.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmessaging_la-im-app-menu-item.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmessaging_la-im-source-menu-item.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmessaging_la-indicator-messages-service.Plo@am__quote@
@@ -580,6 +583,13 @@ libmessaging_la-indicator-messages.lo: indicator-messages.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmessaging_la_CFLAGS) $(CFLAGS) -c -o libmessaging_la-indicator-messages.lo `test -f 'indicator-messages.c' || echo '$(srcdir)/'`indicator-messages.c
+libmessaging_la-ido-menu-item.lo: ido-menu-item.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmessaging_la_CFLAGS) $(CFLAGS) -MT libmessaging_la-ido-menu-item.lo -MD -MP -MF $(DEPDIR)/libmessaging_la-ido-menu-item.Tpo -c -o libmessaging_la-ido-menu-item.lo `test -f 'ido-menu-item.c' || echo '$(srcdir)/'`ido-menu-item.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmessaging_la-ido-menu-item.Tpo $(DEPDIR)/libmessaging_la-ido-menu-item.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ido-menu-item.c' object='libmessaging_la-ido-menu-item.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmessaging_la_CFLAGS) $(CFLAGS) -c -o libmessaging_la-ido-menu-item.lo `test -f 'ido-menu-item.c' || echo '$(srcdir)/'`ido-menu-item.c
+
libmessaging_la-im-app-menu-item.lo: im-app-menu-item.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libmessaging_la_CFLAGS) $(CFLAGS) -MT libmessaging_la-im-app-menu-item.lo -MD -MP -MF $(DEPDIR)/libmessaging_la-im-app-menu-item.Tpo -c -o libmessaging_la-im-app-menu-item.lo `test -f 'im-app-menu-item.c' || echo '$(srcdir)/'`im-app-menu-item.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmessaging_la-im-app-menu-item.Tpo $(DEPDIR)/libmessaging_la-im-app-menu-item.Plo
diff --git a/src/app-section.c b/src/app-section.c
index 70bf21e..bed1302 100644
--- a/src/app-section.c
+++ b/src/app-section.c
@@ -233,6 +233,8 @@ app_section_dispose (GObject *object)
g_clear_object (&priv->source_actions);
}
+ g_clear_object (&priv->muxer);
+
g_clear_object (&priv->source_menu);
g_clear_object (&priv->ids);
g_clear_object (&priv->appinfo);
@@ -344,15 +346,21 @@ 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]);
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));
+ g_object_unref (action);
- g_menu_append (priv->menu, name, nicks[i]);
+ item = g_menu_item_new (name, nicks[i]);
+ g_menu_item_set_attribute (item, "x-canonical-type", "s", "IdoMenuItem");
+ g_menu_item_set_attribute (item, "x-canonical-icon", "s", ""); /* empty to get indentation */
+ g_menu_append_item (priv->menu, item);
+ g_object_unref (item);
g_free(name);
}
@@ -384,8 +392,10 @@ activate_cb (GSimpleAction *action,
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));
+ g_warning("Unable to execute application for desktop file '%s': %s",
+ g_desktop_app_info_get_filename (priv->appinfo),
+ error->message);
+ g_error_free (error);
}
}
@@ -673,16 +683,9 @@ action_removed (GActionGroup *group,
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);
}
gboolean
@@ -690,6 +693,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->source_actions;
+ return priv->uses_chat_status;
}
diff --git a/src/gmenuutils.c b/src/gmenuutils.c
index f3ceba7..f63615b 100644
--- a/src/gmenuutils.c
+++ b/src/gmenuutils.c
@@ -40,7 +40,15 @@ g_menu_find_section (GMenu *menu,
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))
+ GMenuModel *link;
+ gboolean found;
+
+ link = g_menu_model_get_item_link (model, i, G_MENU_LINK_SECTION);
+ found = section == link;
+
+ g_object_unref (link);
+
+ if (found)
return i;
}
diff --git a/src/ido-menu-item.c b/src/ido-menu-item.c
new file mode 100644
index 0000000..6b19d2a
--- /dev/null
+++ b/src/ido-menu-item.c
@@ -0,0 +1,395 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Lars Uebernickel <lars.uebernickel@canonical.com>
+ */
+
+#include "ido-menu-item.h"
+
+struct _IdoMenuItemPrivate
+{
+ GActionGroup *action_group;
+ gchar *action;
+ GVariant *target;
+
+ GtkWidget *icon;
+ GtkWidget *label;
+
+ gboolean has_indicator;
+ gboolean in_set_active;
+};
+
+enum
+{
+ PROP_0,
+ PROP_MENU_ITEM,
+ PROP_ACTION_GROUP,
+ NUM_PROPERTIES
+};
+
+static GParamSpec *properties[NUM_PROPERTIES];
+
+G_DEFINE_TYPE (IdoMenuItem, ido_menu_item, GTK_TYPE_CHECK_MENU_ITEM);
+
+static void
+ido_menu_item_constructed (GObject *object)
+{
+ IdoMenuItemPrivate *priv = IDO_MENU_ITEM (object)->priv;
+ GtkWidget *grid;
+
+ priv->icon = g_object_ref (gtk_image_new ());
+ gtk_widget_set_margin_right (priv->icon, 6);
+
+ 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 (ido_menu_item_parent_class)->constructed (object);
+}
+
+static void
+ido_menu_item_set_active (IdoMenuItem *self,
+ gboolean active)
+{
+ /* HACK gtk_check_menu_item_set_active calls gtk_menu_item_activate.
+ * Make sure our activate handler doesn't toggle the action as a
+ * result of calling this function. */
+
+ self->priv->in_set_active = TRUE;
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (self), active);
+ self->priv->in_set_active = FALSE;
+}
+
+static void
+ido_menu_item_set_has_indicator (IdoMenuItem *self,
+ gboolean has_indicator)
+{
+ if (has_indicator == self->priv->has_indicator)
+ return;
+
+ self->priv->has_indicator = has_indicator;
+
+ gtk_widget_queue_resize (GTK_WIDGET (self));
+}
+
+static void
+ido_menu_item_set_state (IdoMenuItem *self,
+ GVariant *state)
+{
+ IdoMenuItemPrivate *priv = self->priv;
+
+ if (priv->target)
+ {
+ ido_menu_item_set_has_indicator (self, TRUE);
+ gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (self), TRUE);
+ ido_menu_item_set_active (self, g_variant_equal (priv->target, state));
+ }
+ else if (g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN))
+ {
+ ido_menu_item_set_has_indicator (self, TRUE);
+ gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (self), FALSE);
+ ido_menu_item_set_active (self, g_variant_get_boolean (state));
+ }
+ else
+ {
+ ido_menu_item_set_has_indicator (self, FALSE);
+ }
+}
+
+static void
+ido_menu_item_set_action_name (IdoMenuItem *self,
+ const gchar *action_name)
+{
+ IdoMenuItemPrivate *priv = self->priv;
+ gboolean enabled = FALSE;
+ GVariant *state;
+ const GVariantType *param_type;
+
+ 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, &param_type, NULL, NULL, &state))
+ {
+ gtk_widget_set_sensitive (GTK_WIDGET (self), enabled);
+
+ if (state)
+ {
+ ido_menu_item_set_state (self, state);
+ g_variant_unref (state);
+ }
+ }
+ else
+ {
+ ido_menu_item_set_active (self, FALSE);
+ gtk_widget_set_sensitive (GTK_WIDGET (self), FALSE);
+ ido_menu_item_set_has_indicator (self, FALSE);
+ }
+}
+
+static void
+ido_menu_item_action_added (GActionGroup *action_group,
+ gchar *action_name,
+ gpointer user_data)
+{
+ IdoMenuItem *self = user_data;
+
+ if (g_strcmp0 (self->priv->action, action_name) == 0)
+ ido_menu_item_set_action_name (self, action_name);
+}
+
+static void
+ido_menu_item_action_removed (GActionGroup *action_group,
+ gchar *action_name,
+ gpointer user_data)
+{
+ IdoMenuItem *self = user_data;
+
+ if (g_strcmp0 (self->priv->action, action_name) == 0)
+ {
+ gtk_widget_set_sensitive (GTK_WIDGET (self), FALSE);
+ }
+}
+
+static void
+ido_menu_item_action_enabled_changed (GActionGroup *action_group,
+ gchar *action_name,
+ gboolean enabled,
+ gpointer user_data)
+{
+ IdoMenuItem *self = user_data;
+
+ if (g_strcmp0 (self->priv->action, action_name) == 0)
+ gtk_widget_set_sensitive (GTK_WIDGET (self), enabled);
+}
+
+static void
+ido_menu_item_action_state_changed (GActionGroup *action_group,
+ gchar *action_name,
+ GVariant *value,
+ gpointer user_data)
+{
+ IdoMenuItem *self = user_data;
+
+ if (g_strcmp0 (self->priv->action, action_name) == 0)
+ ido_menu_item_set_state (self, value);
+}
+
+static void
+ido_menu_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ IdoMenuItem *self = IDO_MENU_ITEM (object);
+
+ switch (property_id)
+ {
+ case PROP_MENU_ITEM:
+ ido_menu_item_set_menu_item (self, G_MENU_ITEM (g_value_get_object (value)));
+ break;
+
+ case PROP_ACTION_GROUP:
+ ido_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
+ido_menu_item_dispose (GObject *object)
+{
+ IdoMenuItem *self = IDO_MENU_ITEM (object);
+
+ if (self->priv->action_group)
+ ido_menu_item_set_action_group (self, NULL);
+
+ g_clear_object (&self->priv->icon);
+ g_clear_object (&self->priv->label);
+
+ if (self->priv->target)
+ {
+ g_variant_unref (self->priv->target);
+ self->priv->target = NULL;
+ }
+
+ G_OBJECT_CLASS (ido_menu_item_parent_class)->dispose (object);
+}
+
+static void
+ido_menu_item_finalize (GObject *object)
+{
+ IdoMenuItemPrivate *priv = IDO_MENU_ITEM (object)->priv;
+
+ g_free (priv->action);
+
+ G_OBJECT_CLASS (ido_menu_item_parent_class)->finalize (object);
+}
+
+static void
+ido_menu_item_activate (GtkMenuItem *item)
+{
+ IdoMenuItemPrivate *priv = IDO_MENU_ITEM (item)->priv;
+
+ /* see ido_menu_item_set_active */
+ if (!priv->in_set_active && priv->action && priv->action_group)
+ g_action_group_activate_action (priv->action_group, priv->action, priv->target);
+
+ GTK_MENU_ITEM_CLASS (ido_menu_item_parent_class)->activate (item);
+}
+
+static void
+ido_menu_item_draw_indicator (GtkCheckMenuItem *item,
+ cairo_t *cr)
+{
+ IdoMenuItem *self = IDO_MENU_ITEM (item);
+
+ if (self->priv->has_indicator)
+ GTK_CHECK_MENU_ITEM_CLASS (ido_menu_item_parent_class)
+ ->draw_indicator (item, cr);
+}
+
+static void
+ido_menu_item_class_init (IdoMenuItemClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkMenuItemClass *menu_item_class = GTK_MENU_ITEM_CLASS (klass);
+ GtkCheckMenuItemClass *check_class = GTK_CHECK_MENU_ITEM_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (IdoMenuItemPrivate));
+
+ object_class->constructed = ido_menu_item_constructed;
+ object_class->set_property = ido_menu_set_property;
+ object_class->dispose = ido_menu_item_dispose;
+ object_class->finalize = ido_menu_item_finalize;
+
+ menu_item_class->activate = ido_menu_item_activate;
+
+ check_class->draw_indicator = ido_menu_item_draw_indicator;
+
+ 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
+ido_menu_item_init (IdoMenuItem *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ IDO_TYPE_MENU_ITEM,
+ IdoMenuItemPrivate);
+}
+
+void
+ido_menu_item_set_menu_item (IdoMenuItem *self,
+ GMenuItem *menuitem)
+{
+ gchar *iconstr = NULL;
+ GIcon *icon = NULL;
+ gchar *label = NULL;
+ gchar *action = NULL;
+
+ if (g_menu_item_get_attribute (menuitem, "x-canonical-icon", "s", &iconstr))
+ {
+ GError *error;
+
+ /* only indent the label if icon is set to "" */
+ if (iconstr[0] == '\0')
+ {
+ gint width;
+
+ gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &width, NULL);
+ gtk_widget_set_size_request (self->priv->icon, width, -1);
+ }
+ else
+ {
+ 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 : "");
+
+ self->priv->target = g_menu_item_get_attribute_value (menuitem, "target", NULL);
+
+ g_menu_item_get_attribute (menuitem, "action", "s", &action);
+ ido_menu_item_set_action_name (self, action);
+
+ if (icon)
+ g_object_unref (icon);
+ g_free (label);
+ g_free (action);
+}
+
+void
+ido_menu_item_set_action_group (IdoMenuItem *self,
+ GActionGroup *action_group)
+{
+ IdoMenuItemPrivate *priv = self->priv;
+
+ if (priv->action_group != NULL)
+ {
+ g_signal_handlers_disconnect_by_func (priv->action_group, ido_menu_item_action_added, self);
+ g_signal_handlers_disconnect_by_func (priv->action_group, ido_menu_item_action_removed, self);
+ g_signal_handlers_disconnect_by_func (priv->action_group, ido_menu_item_action_enabled_changed, self);
+ g_signal_handlers_disconnect_by_func (priv->action_group, ido_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 (ido_menu_item_action_added), self);
+ g_signal_connect (priv->action_group, "action-removed",
+ G_CALLBACK (ido_menu_item_action_removed), self);
+ g_signal_connect (priv->action_group, "action-enabled-changed",
+ G_CALLBACK (ido_menu_item_action_enabled_changed), self);
+ g_signal_connect (priv->action_group, "action-state-changed",
+ G_CALLBACK (ido_menu_item_action_state_changed), self);
+ }
+}
diff --git a/src/ido-menu-item.h b/src/ido-menu-item.h
new file mode 100644
index 0000000..0521928
--- /dev/null
+++ b/src/ido-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 <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Lars Uebernickel <lars.uebernickel@canonical.com>
+ */
+
+#ifndef __IDO_MENU_ITEM_H__
+#define __IDO_MENU_ITEM_H__
+
+#include <gtk/gtk.h>
+
+#define IDO_TYPE_MENU_ITEM (ido_menu_item_get_type ())
+#define IDO_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IDO_TYPE_MENU_ITEM, IdoMenuItem))
+#define IDO_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), IDO_TYPE_MENU_ITEM, IdoMenuItemClass))
+#define IS_IDO_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IDO_TYPE_MENU_ITEM))
+#define IS_IDO_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), IDO_TYPE_MENU_ITEM))
+#define IDO_MENU_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), IDO_TYPE_MENU_ITEM, IdoMenuItemClass))
+
+typedef struct _IdoMenuItem IdoMenuItem;
+typedef struct _IdoMenuItemClass IdoMenuItemClass;
+typedef struct _IdoMenuItemPrivate IdoMenuItemPrivate;
+
+struct _IdoMenuItemClass
+{
+ GtkCheckMenuItemClass parent_class;
+};
+
+struct _IdoMenuItem
+{
+ GtkCheckMenuItem parent;
+ IdoMenuItemPrivate *priv;
+};
+
+GType ido_menu_item_get_type (void);
+
+void ido_menu_item_set_menu_item (IdoMenuItem *item,
+ GMenuItem *menuitem);
+void ido_menu_item_set_action_group (IdoMenuItem *self,
+ GActionGroup *action_group);
+
+#endif
diff --git a/src/im-app-menu-item.c b/src/im-app-menu-item.c
index eddf562..a204631 100644
--- a/src/im-app-menu-item.c
+++ b/src/im-app-menu-item.c
@@ -48,6 +48,7 @@ im_app_menu_item_constructed (GObject *object)
GtkWidget *grid;
priv->icon = g_object_ref (gtk_image_new ());
+ gtk_widget_set_margin_right (priv->icon, 6);
priv->label = g_object_ref (gtk_label_new (""));
diff --git a/src/im-source-menu-item.c b/src/im-source-menu-item.c
index 269c75d..5aebb68 100644
--- a/src/im-source-menu-item.c
+++ b/src/im-source-menu-item.c
@@ -29,6 +29,9 @@ struct _ImSourceMenuItemPrivate
GtkWidget *icon;
GtkWidget *label;
GtkWidget *detail;
+
+ gint64 time;
+ guint timer_id;
};
enum
@@ -53,7 +56,7 @@ 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);
+ gtk_widget_set_margin_left (priv->icon, icon_width + 6);
priv->label = g_object_ref (gtk_label_new (""));
@@ -144,6 +147,19 @@ im_source_menu_item_time_span_string (gint64 timestamp)
}
static gboolean
+im_source_menu_item_update_time (gpointer data)
+{
+ ImSourceMenuItem *self = data;
+ gchar *str;
+
+ str = im_source_menu_item_time_span_string (self->priv->time);
+ gtk_label_set_text (GTK_LABEL (self->priv->detail), str);
+
+ g_free (str);
+ return TRUE;
+}
+
+static gboolean
im_source_menu_item_set_state (ImSourceMenuItem *self,
GVariant *state)
{
@@ -153,6 +169,12 @@ im_source_menu_item_set_state (ImSourceMenuItem *self,
const gchar *str;
gchar *detail;
+ if (priv->timer_id != 0)
+ {
+ g_source_remove (priv->timer_id);
+ priv->timer_id = 0;
+ }
+
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);
@@ -160,7 +182,11 @@ im_source_menu_item_set_state (ImSourceMenuItem *self,
if (count != 0)
detail = g_strdup_printf ("%d", count);
else if (time != 0)
- detail = im_source_menu_item_time_span_string (time);
+ {
+ priv->time = time;
+ detail = im_source_menu_item_time_span_string (time);
+ priv->timer_id = g_timeout_add_seconds (59, im_source_menu_item_update_time, self);
+ }
else if (str != NULL && *str)
detail = collapse_whitespace (str);
else
@@ -275,6 +301,12 @@ im_source_menu_item_dispose (GObject *object)
{
ImSourceMenuItem *self = IM_SOURCE_MENU_ITEM (object);
+ if (self->priv->timer_id != 0)
+ {
+ g_source_remove (self->priv->timer_id);
+ self->priv->timer_id = 0;
+ }
+
if (self->priv->action_group)
im_source_menu_item_set_action_group (self, NULL);
diff --git a/src/indicator-messages-service.c b/src/indicator-messages-service.c
index 24772c1..a42a534 100644
--- a/src/indicator-messages-service.c
+++ b/src/indicator-messages-service.c
@@ -1,5 +1,5 @@
/*
- * Generated by gdbus-codegen 2.33.8. DO NOT EDIT.
+ * Generated by gdbus-codegen 2.33.10. DO NOT EDIT.
*
* The license of this code is the same as for the source it was derived from.
*/
diff --git a/src/indicator-messages-service.h b/src/indicator-messages-service.h
index cb399f5..2adaaf3 100644
--- a/src/indicator-messages-service.h
+++ b/src/indicator-messages-service.h
@@ -1,5 +1,5 @@
/*
- * Generated by gdbus-codegen 2.33.8. DO NOT EDIT.
+ * Generated by gdbus-codegen 2.33.10. DO NOT EDIT.
*
* The license of this code is the same as for the source it was derived from.
*/
diff --git a/src/indicator-messages.c b/src/indicator-messages.c
index 946da55..942e46f 100644
--- a/src/indicator-messages.c
+++ b/src/indicator-messages.c
@@ -32,11 +32,11 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#include <libindicator/indicator.h>
#include <libindicator/indicator-object.h>
-#include <libindicator/indicator-image-helper.h>
#include <libindicator/indicator-service-manager.h>
#include "dbus-data.h"
+#include "ido-menu-item.h"
#include "im-app-menu-item.h"
#include "im-source-menu-item.h"
@@ -61,6 +61,7 @@ struct _IndicatorMessages {
GMenu *menu_wrapper;
GMenuModel *menu;
GtkWidget *image;
+ GtkWidget *gtkmenu;
gchar *accessible_desc;
};
@@ -75,6 +76,9 @@ 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 void service_connection_changed (IndicatorServiceManager *sm,
+ gboolean connected,
+ gpointer user_data);
static GtkImage * get_image (IndicatorObject * io);
static GtkMenu * get_menu (IndicatorObject * io);
static const gchar * get_accessible_desc (IndicatorObject * io);
@@ -86,6 +90,10 @@ static void menu_items_changed (GMenuModel *menu,
gint removed,
gint added,
gpointer user_data);
+static void messages_state_changed (GActionGroup *action_group,
+ gchar *action_name,
+ GVariant *value,
+ gpointer user_data);
G_DEFINE_TYPE (IndicatorMessages, indicator_messages, INDICATOR_OBJECT_TYPE);
@@ -110,43 +118,19 @@ indicator_messages_class_init (IndicatorMessagesClass *klass)
static void
indicator_messages_init (IndicatorMessages *self)
{
- GDBusConnection *bus;
- GError *error = NULL;
-
- /* Default values */
- self->service = NULL;
-
- /* Complex stuff */
self->service = indicator_service_manager_new_version(INDICATOR_MESSAGES_DBUS_NAME, 1);
-
- 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));
-
- 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_root_item (self);
+ g_signal_connect (self->service, "connection-change",
+ G_CALLBACK (service_connection_changed), self);
self->menu_wrapper = g_menu_new ();
- update_menu (self);
+ self->gtkmenu = gtk_menu_new_from_model (G_MENU_MODEL (self->menu_wrapper));
+ g_object_ref_sink (self->gtkmenu);
- g_object_unref (bus);
+ self->image = g_object_ref_sink (gtk_image_new ());
/* make sure custom menu item types are registered (so that
* gtk_model_new_from_menu can pick them up */
+ ido_menu_item_get_type ();
im_app_menu_item_get_type ();
im_source_menu_item_get_type ();
}
@@ -162,6 +146,7 @@ indicator_messages_dispose (GObject *object)
g_clear_object (&self->menu_wrapper);
g_clear_object (&self->actions);
g_clear_object (&self->menu);
+ g_clear_object (&self->gtkmenu);
g_clear_object (&self->image);
G_OBJECT_CLASS (indicator_messages_parent_class)->dispose (object);
@@ -184,11 +169,61 @@ indicator_messages_finalize (GObject *object)
/* Functions */
+static void service_connection_changed (IndicatorServiceManager *sm,
+ gboolean connected,
+ gpointer user_data)
+{
+ IndicatorMessages *self = user_data;
+ GDBusConnection *bus;
+ GError *error = NULL;
+
+ if (self->actions != NULL) {
+ g_signal_handlers_disconnect_by_func (self->actions, messages_state_changed, self);
+ g_clear_object (&self->actions);
+ }
+ if (self->menu != NULL) {
+ g_signal_handlers_disconnect_by_func (self->menu, menu_items_changed, self);
+ g_clear_object (&self->menu);
+ }
+ if (g_menu_model_get_n_items (G_MENU_MODEL (self->menu_wrapper)) == 1)
+ g_menu_remove (self->menu_wrapper, 0);
+
+ if (connected == FALSE)
+ return;
+
+ 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));
+ gtk_widget_insert_action_group (self->gtkmenu,
+ get_name_hint (INDICATOR_OBJECT (self)),
+ self->actions);
+ g_signal_connect (self->actions, "action-state-changed::messages",
+ G_CALLBACK (messages_state_changed), self);
+
+ self->menu = G_MENU_MODEL (g_dbus_menu_model_get (bus,
+ INDICATOR_MESSAGES_DBUS_NAME,
+ INDICATOR_MESSAGES_DBUS_OBJECT));
+ g_signal_connect (self->menu, "items-changed", G_CALLBACK (menu_items_changed), self);
+
+ update_root_item (self);
+ update_menu (self);
+
+ g_object_unref (bus);
+}
+
static GtkImage *
get_image (IndicatorObject * io)
{
IndicatorMessages *self = INDICATOR_MESSAGES (io);
+ gtk_widget_show (self->image);
return GTK_IMAGE (self->image);
}
@@ -196,12 +231,8 @@ static GtkMenu *
get_menu (IndicatorObject * io)
{
IndicatorMessages *self = INDICATOR_MESSAGES (io);
- 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);
+ return GTK_MENU (self->gtkmenu);
}
static const gchar *
@@ -269,7 +300,7 @@ update_menu (IndicatorMessages *self)
GMenuModel *popup;
GMenuItem *item;
- if (g_menu_model_get_n_items (self->menu) == 0)
+ if (self->menu == NULL || g_menu_model_get_n_items (self->menu) == 0)
return;
popup = g_menu_model_get_item_link (self->menu, 0, G_MENU_LINK_SUBMENU);
@@ -302,3 +333,19 @@ menu_items_changed (GMenuModel *menu,
update_menu (self);
}
}
+
+static void
+messages_state_changed (GActionGroup *action_group,
+ gchar *action_name,
+ GVariant *value,
+ gpointer user_data)
+{
+ IndicatorMessages *self = user_data;
+
+ g_return_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN));
+
+ if (g_variant_get_boolean (value))
+ gtk_image_set_from_icon_name (GTK_IMAGE (self->image), "indicator-messages-new", GTK_ICON_SIZE_MENU);
+ else
+ gtk_image_set_from_icon_name (GTK_IMAGE (self->image), "indicator-messages", GTK_ICON_SIZE_MENU);
+}
diff --git a/src/messages-service.c b/src/messages-service.c
index 407b8ba..15c5123 100644
--- a/src/messages-service.c
+++ b/src/messages-service.c
@@ -134,6 +134,8 @@ uses_chat_status_changed (GObject *object,
if (show_chat)
g_menu_insert_section (menu, 0, NULL, chat_section);
}
+
+ g_object_unref (first_section);
}
static AppSection *
@@ -313,7 +315,6 @@ change_status_action (GSimpleAction *action,
g_str_equal (status, "offline"));
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);
}
@@ -405,14 +406,33 @@ static GMenuModel *
create_status_section (void)
{
GMenu *menu;
+ GMenuItem *item;
+ struct status_item {
+ gchar *label;
+ gchar *action;
+ gchar *icon_name;
+ } status_items[] = {
+ { _("Available"), "status::available", "user-available" },
+ { _("Away"), "status::away", "user-away" },
+ { _("Busy"), "status::busy", "user-busy" },
+ { _("Invisible"), "status::invisible", "user-invisible" },
+ { _("Offline"), "status::offline", "user-offline" }
+ };
+ int i;
menu = g_menu_new ();
- 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");
+ item = g_menu_item_new (NULL, NULL);
+ g_menu_item_set_attribute (item, "x-canonical-type", "s", "IdoMenuItem");
+
+ for (i = 0; i < G_N_ELEMENTS (status_items); i++) {
+ g_menu_item_set_label (item, status_items[i].label);
+ g_menu_item_set_detailed_action (item, status_items[i].action);
+ g_menu_item_set_attribute (item, "x-canonical-icon", "s", status_items[i].icon_name);
+ g_menu_append_item (menu, item);
+ }
+
+ g_object_unref (item);
return G_MENU_MODEL (menu);
}