diff options
author | Sebastien Bacher <seb128@ubuntu.com> | 2012-10-02 23:18:17 +0200 |
---|---|---|
committer | Sebastien Bacher <seb128@ubuntu.com> | 2012-10-02 23:18:17 +0200 |
commit | 78f8f75ee73478ecb704aecc467c861fa4558b52 (patch) | |
tree | a75c86a1f9262d9dc0954ffdab75524163584874 | |
parent | c8794795a7054eff4e21bbca52321195f2d8720c (diff) | |
parent | 36692583866dac99672571d6d83ed2c65b9e795d (diff) | |
download | ayatana-indicator-messages-78f8f75ee73478ecb704aecc467c861fa4558b52.tar.gz ayatana-indicator-messages-78f8f75ee73478ecb704aecc467c861fa4558b52.tar.bz2 ayatana-indicator-messages-78f8f75ee73478ecb704aecc467c861fa4558b52.zip |
Import upstream version 12.10.4
50 files changed, 1409 insertions, 319 deletions
@@ -21,4 +21,5 @@ Sebastien Bacher Sebstien Bacher Sven Baars + Tarmac Ted Gould @@ -1,5 +1,264 @@ # Generated by Makefile. Do not edit. +2012-10-02 Lars Uebernickel <lars.uebernickel@canonical.com> + + Merge lp:~larsu/indicator-messages/lp1056595 + + Use fallback icon names (without status emblems). + +2012-09-28 Lars Uebernickel <lars.uebernickel@canonical.com> + + Include fallback icon names + + And use g_icon_new_from_string in the indicator to make it load fallbacks. + +2012-10-02 Lars Uebernickel <lars.uebernickel@canonical.com> + + Merge lp:~larsu/indicator-messages/lp1058386 + + Don't crash when getting an invalid desktop id. + +2012-10-01 Lars Uebernickel <lars.uebernickel@canonical.com> + + libmessaging-menu: don't crash when getting an invalid desktop id + + Instead, silently don't export menus and actions. The single warning about the + desktop id being invalid should be enough. + +2012-09-26 Lars Uebernickel <lars.uebernickel@canonical.com> + + Merge lp:~larsu/indicator-messages/lp1055966 + + Request GTK_ICON_SIZE_LARGE_TOOLBAR icons for the indicator. + +2012-09-25 Lars Uebernickel <lars.uebernickel@canonical.com> + + Request LARGE_TOOLBAR icons for the panel + + To make it consistent with the other indicators. + +2012-09-19 Lars Uebernickel <lars.uebernickel@canonical.com> + + 12.10.3 + +2012-09-19 Lars Uebernickel <lars.uebernickel@canonical.com> + + Bump required gtk version to 3.5.18 + +2012-09-19 Lars Uebernickel <lars.uebernickel@canonical.com> + + Merge lp:~larsu/indicator-messages/fix-set-status + +2012-09-19 Lars Uebernickel <lars.uebernickel@canonical.com> + + messages-service: define all global variables as static + +2012-09-18 Lars Uebernickel <lars.uebernickel@canonical.com> + + Use indicator-message icons with chat status + + Changes the state of the "messages" action from a boolean (draws-attention) to + a string (icon-name). This has the added benefit that more logic is moved from + the plugin into the service. + + It also fixes an edge case: the messaging menu didn't have the blue icon after + the service restarted (if anything was drawing attention). + +2012-09-18 Lars Uebernickel <lars.uebernickel@canonical.com> + + Set the global chat status more intelligently + + Up until now, the global chat status was set every time an application called + _set_status. Thus, global status really meant "status of the app that last + changed the status". + + Now, the service remembers the chat status for each application and sets the + global status as a combination of all of application statuses. If applications + have different statuses, the menu items are shown in an inconsistent state. + This is implemented in IdoMenuItem by making it accept state as an array of + strings in addition to a single string. It is drawn inconsistent if the state + contains the menu item's target value in addition to other values. + + When the global status is changed through the messaging menu, the service + doesn't update the action immediately anymore. Instead, it notifies all + applications about the change via the "status-changed" signal. Applications + must call _set_state to acknowledge that they have indeed changed their state. + This is consistent with libmessaging-menu's documentation and design. + + Also, the SetStatus D-Bus call was missing a "desktop-id" parameter to tell the + menu which application changed status. Changing this doesn't break existing + apps, as the D-Bus interface is considered private to indicator-messages. + +2012-09-18 Lars Uebernickel <lars.uebernickel@canonical.com> + + libmessaging-menu: don't set app->status when global status changes + + The application's status only changes when it calls _set_status, so it's wrong + to set the internal status when the global status changes. + + This shouldn't be a problem in practice, as app->status is not accessible from + the API. + +2012-09-18 Lars Uebernickel <lars.uebernickel@canonical.com> + + libmessaging-menu: don't call SetStatus(OFFLINE) for all apps + + Only notify the service about status if the application has actually called + messaging_menu_app_set_status. This saves a d-bus call per non-chat + application and - more importantly - doesn't make the messaging menu go into + "unknown status" mode when one application is reporting 'online' status. + +2012-09-18 Lars Uebernickel <lars.uebernickel@canonical.com> + + Merge lp:~larsu/indicator-messages/show-separators + +2012-09-14 Lars Uebernickel <lars.uebernickel@canonical.com> + + messages-services: don't call g_object_unref with NULL + +2012-09-13 Lars Uebernickel <lars.uebernickel@canonical.com> + + Show menu separators between sections + + Previously, gtk didn't support changing the menu model on an already-created + GtkMenu. Since IndicatorObject doesn't allow changing the GtkMenu it exports + to the panel, IndicatorMessages created a menu with a single section, into + which the menu from the service was inserted (and removed when the service + died). This led to seperators not being shown, because separators are only + shown between top-level sections. + + Gtk now has gtk_menu_shell_bind_model, which allows us to get rid of top-level + wrapper section. + +2012-09-06 Lars Uebernickel <lars.uebernickel@canonical.com> + + messages-service: update chat section when an app is removed + +2012-09-06 Lars Uebernickel <lars.uebernickel@canonical.com> + + messages-service: fix merge error + + Check whether no apps are left in remove_section instead of remove_application, + so that it is also done when an AppSection emits "destroy". This is a result + of improper merging of the watch-desktop-files and hide-indicator branches. + +2012-09-06 Lars Uebernickel <lars.uebernickel@canonical.com> + + Merge lp:~larsu/indicator-messages/watch-desktop-files + +2012-09-05 Lars Uebernickel <lars.uebernickel@canonical.com> + + messages-service.c: remove redundant g_hash_table_remove + +2012-09-05 Lars Uebernickel <lars.uebernickel@canonical.com> + + app-section.c: remove unused function app_section_get_name + +2012-09-05 Lars Uebernickel <lars.uebernickel@canonical.com> + + app-section.c: make destroy_signal static + +2012-09-05 Lars Uebernickel <lars.uebernickel@canonical.com> + + app-section: remove unused private member + +2012-09-05 Lars Uebernickel <lars.uebernickel@canonical.com> + + Watch desktop files for changes + + This introduces a slightly clumsy "destroy" signal for AppSection to notify + outsiders that the desktop file was deleted. This will do for now, but a + larger refactoring which pulls all the desktop-file-reading code out of + appsection is in order. + +2012-09-05 Lars Uebernickel <lars.uebernickel@canonical.com> + + Hide the indicator when no application is configured to use it.. Fixes: https://bugs.launchpad.net/bugs/661059, https://bugs.launchpad.net/bugs/1045039. Approved by jenkins, Charles Kerr. + +2012-09-05 Lars Uebernickel <lars.uebernickel@canonical.com> + + indicator-messages.c: don't call menu_items_changed directly + +2012-09-04 Lars Uebernickel <lars.uebernickel@canonical.com> + + Hide indicator when no applications are configured to use it + + This is done by removing the header item from the menu model in the service. + On the panel side, call indicator_object_hide() if the recevied menu is empty. + +2012-09-04 Lars Uebernickel <lars.uebernickel@canonical.com> + + Some minor enhancements to the in-source documentation.. Approved by jenkins, Charles Kerr. + +2012-09-04 Lars Uebernickel <lars.uebernickel@canonical.com> + + libmessaging-menu: fix shortcut action documentation + +2012-09-02 Lars Uebernickel <lars.uebernickel@canonical.com> + + libmessaging-menu: add convenience doc + + The most common case when inserting a timed source is to insert a source with + the current time. Emphasize this in the documentation by linking to the + convenience methods from the _with_time variants. + +2012-09-02 Lars Uebernickel <lars.uebernickel@canonical.com> + + libmessaging-menu: document that @time is expressed in microseconds + +2012-09-02 Lars Uebernickel <lars.uebernickel@canonical.com> + + libmessaging-menu: add @include hint to documentation + +2012-09-04 Lars Uebernickel <lars.uebernickel@canonical.com> + + Draw counts as lozenges again. + + Introduces IdoDetailLabel, a GtkWidget that renders detail strings (e.g. as lozenges) on the right side of a menu item.. Approved by Charles Kerr. + +2012-09-04 Lars Uebernickel <lars.uebernickel@canonical.com> + + ido-detail-label: factor common code out of set_text and _count + + This was only half-heartedly done with the _clear function, which left a + dangling pointer. + + Contributed by Charles Kerr. Thanks! + +2012-09-04 Lars Uebernickel <lars.uebernickel@canonical.com> + + ido-detail-label: chain up dispose and finalize calls + +2012-09-03 Lars Uebernickel <lars.uebernickel@canonical.com> + + im-source-menu-item: ellipsize label when it's longer than 40 em + + Also make sure that the label is left-aligned when ellipsized. + +2012-09-03 Lars Uebernickel <lars.uebernickel@canonical.com> + + im-source-menu-item: draw lozenges around counts + + A new widget class IdoDetailLabel is introduced, which can display either a + string or a count. Counts are drawn as lozenges. + +2012-09-03 Lars Uebernickel <lars.uebernickel@canonical.com> + + im-source-menu-item: refactor setting detail string + +2012-09-03 Lars Uebernickel <lars.uebernickel@canonical.com> + + Update bzrignore + +2012-09-01 Lars Uebernickel <lars.uebernickel@canonical.com> + + libmessaging-menu: make generated .gir compatible with vala + + In particular, mamke sure the <c:namespace> and <package> tags are included in + the .gir. + + Fixes launchpad bug #1044096, thanks Jim! + 2012-08-31 Lars Uebernickel <lars.uebernickel@canonical.com> 12.10.2 diff --git a/Makefile.in b/Makefile.in index 45488cf..cee079c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.11.5 from Makefile.am. +# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, @@ -654,7 +654,7 @@ distcheck: dist *.zip*) \ unzip $(distdir).zip ;;\ esac - chmod -R a-w $(distdir); chmod a+w $(distdir) + chmod -R a-w $(distdir); chmod u+w $(distdir) mkdir $(distdir)/_build mkdir $(distdir)/_inst chmod a-w $(distdir) @@ -1,4 +1,22 @@ +12.10.4 + +* specify fallback icons for the ones with status emblem (lp #1056595) +* make icon size consistent with the other indicators (lp #1055966) +* libmessaging-menu: fix crash when receiving a invalid desktop id (lp #1058386) + + +12.10.3 + +* hide indicator when no application shows in the menu (lp #661059) +* remove apps as soon as they are uninstalled (lp #864545) +* make generated .gir compatible with vala (lp #104496) +* draw counts as lozenges (lp #1046331) +* show separators (lp #1048245) +* show chat presence in the panel (lp #859905) +* improve documentation + + 12.10.2 * libmessaging-menu: @@ -1,4 +1,4 @@ -# generated automatically by aclocal 1.11.5 -*- Autoconf -*- +# generated automatically by aclocal 1.11.6 -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, # 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, @@ -9738,7 +9738,7 @@ AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.11' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. -m4_if([$1], [1.11.5], [], +m4_if([$1], [1.11.6], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) @@ -9754,7 +9754,7 @@ m4_define([_AM_AUTOCONF_VERSION], []) # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], -[AM_AUTOMAKE_VERSION([1.11.5])dnl +[AM_AUTOMAKE_VERSION([1.11.6])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for indicator-messages 12.10.2. +# Generated by GNU Autoconf 2.69 for indicator-messages 12.10.4. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -587,8 +587,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='indicator-messages' PACKAGE_TARNAME='indicator-messages' -PACKAGE_VERSION='12.10.2' -PACKAGE_STRING='indicator-messages 12.10.2' +PACKAGE_VERSION='12.10.4' +PACKAGE_STRING='indicator-messages 12.10.4' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -1448,7 +1448,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures indicator-messages 12.10.2 to adapt to many kinds of systems. +\`configure' configures indicator-messages 12.10.4 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1519,7 +1519,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of indicator-messages 12.10.2:";; + short | recursive ) echo "Configuration of indicator-messages 12.10.4:";; esac cat <<\_ACEOF @@ -1660,7 +1660,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -indicator-messages configure 12.10.2 +indicator-messages configure 12.10.4 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2233,7 +2233,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by indicator-messages $as_me 12.10.2, which was +It was created by indicator-messages $as_me 12.10.4, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -3053,7 +3053,7 @@ fi # Define the identity of the package. PACKAGE='indicator-messages' - VERSION='12.10.2' + VERSION='12.10.4' cat >>confdefs.h <<_ACEOF @@ -16783,7 +16783,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu # Dependencies ########################### -GTK_REQUIRED_VERSION=3.5.12 +GTK_REQUIRED_VERSION=3.5.18 GIO_UNIX_REQUIRED_VERSION=2.33.10 INDICATOR_REQUIRED_VERSION=0.3.19 GLIB_REQUIRED_VERSION=2.33.10 @@ -19578,7 +19578,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by indicator-messages $as_me 12.10.2, which was +This file was extended by indicator-messages $as_me 12.10.4, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -19644,7 +19644,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -indicator-messages config.status 12.10.2 +indicator-messages config.status 12.10.4 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 37268a2..971bd96 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ -AC_INIT(indicator-messages, 12.10.2) +AC_INIT(indicator-messages, 12.10.4) AC_PREREQ(2.62) @@ -38,7 +38,7 @@ AC_PROG_CXX # Dependencies ########################### -GTK_REQUIRED_VERSION=3.5.12 +GTK_REQUIRED_VERSION=3.5.18 GIO_UNIX_REQUIRED_VERSION=2.33.10 INDICATOR_REQUIRED_VERSION=0.3.19 GLIB_REQUIRED_VERSION=2.33.10 diff --git a/data/Makefile.in b/data/Makefile.in index b456915..9493258 100644 --- a/data/Makefile.in +++ b/data/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.11.5 from Makefile.am. +# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, diff --git a/data/icons/16x16/Makefile.in b/data/icons/16x16/Makefile.in index 6d8d66d..441ba9b 100644 --- a/data/icons/16x16/Makefile.in +++ b/data/icons/16x16/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.11.5 from Makefile.am. +# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, diff --git a/data/icons/16x16/categories/Makefile.in b/data/icons/16x16/categories/Makefile.in index 12373ab..c10dd98 100644 --- a/data/icons/16x16/categories/Makefile.in +++ b/data/icons/16x16/categories/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.11.5 from Makefile.am. +# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, diff --git a/data/icons/16x16/status/Makefile.in b/data/icons/16x16/status/Makefile.in index 8d8ebff..c515777 100644 --- a/data/icons/16x16/status/Makefile.in +++ b/data/icons/16x16/status/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.11.5 from Makefile.am. +# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, diff --git a/data/icons/22x22/Makefile.in b/data/icons/22x22/Makefile.in index 7314f25..fa9ae77 100644 --- a/data/icons/22x22/Makefile.in +++ b/data/icons/22x22/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.11.5 from Makefile.am. +# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, diff --git a/data/icons/22x22/categories/Makefile.in b/data/icons/22x22/categories/Makefile.in index 21cb923..ddd2aa8 100644 --- a/data/icons/22x22/categories/Makefile.in +++ b/data/icons/22x22/categories/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.11.5 from Makefile.am. +# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, diff --git a/data/icons/22x22/status/Makefile.in b/data/icons/22x22/status/Makefile.in index 1f2abad..1960f48 100644 --- a/data/icons/22x22/status/Makefile.in +++ b/data/icons/22x22/status/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.11.5 from Makefile.am. +# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, diff --git a/data/icons/24x24/Makefile.in b/data/icons/24x24/Makefile.in index d1024b4..687b185 100644 --- a/data/icons/24x24/Makefile.in +++ b/data/icons/24x24/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.11.5 from Makefile.am. +# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, diff --git a/data/icons/24x24/status/Makefile.in b/data/icons/24x24/status/Makefile.in index d5e7f65..8179b82 100644 --- a/data/icons/24x24/status/Makefile.in +++ b/data/icons/24x24/status/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.11.5 from Makefile.am. +# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, diff --git a/data/icons/32x32/Makefile.in b/data/icons/32x32/Makefile.in index 7edc9f4..b84587e 100644 --- a/data/icons/32x32/Makefile.in +++ b/data/icons/32x32/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.11.5 from Makefile.am. +# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, diff --git a/data/icons/32x32/categories/Makefile.in b/data/icons/32x32/categories/Makefile.in index bdbe0ad..5247c18 100644 --- a/data/icons/32x32/categories/Makefile.in +++ b/data/icons/32x32/categories/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.11.5 from Makefile.am. +# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, diff --git a/data/icons/32x32/status/Makefile.in b/data/icons/32x32/status/Makefile.in index b04fb23..c3def49 100644 --- a/data/icons/32x32/status/Makefile.in +++ b/data/icons/32x32/status/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.11.5 from Makefile.am. +# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, diff --git a/data/icons/48x48/Makefile.in b/data/icons/48x48/Makefile.in index bf7bbb0..6dd6abd 100644 --- a/data/icons/48x48/Makefile.in +++ b/data/icons/48x48/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.11.5 from Makefile.am. +# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, diff --git a/data/icons/48x48/status/Makefile.in b/data/icons/48x48/status/Makefile.in index 618c959..5da0b48 100644 --- a/data/icons/48x48/status/Makefile.in +++ b/data/icons/48x48/status/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.11.5 from Makefile.am. +# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, diff --git a/data/icons/Makefile.in b/data/icons/Makefile.in index 4fc8008..2636126 100644 --- a/data/icons/Makefile.in +++ b/data/icons/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.11.5 from Makefile.am. +# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, diff --git a/data/icons/scalable/Makefile.in b/data/icons/scalable/Makefile.in index 640f589..b74adc8 100644 --- a/data/icons/scalable/Makefile.in +++ b/data/icons/scalable/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.11.5 from Makefile.am. +# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, diff --git a/data/icons/scalable/categories/Makefile.in b/data/icons/scalable/categories/Makefile.in index 8bbd2f0..6571305 100644 --- a/data/icons/scalable/categories/Makefile.in +++ b/data/icons/scalable/categories/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.11.5 from Makefile.am. +# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, diff --git a/data/icons/scalable/status/Makefile.in b/data/icons/scalable/status/Makefile.in index ea3cb73..d57cb58 100644 --- a/data/icons/scalable/status/Makefile.in +++ b/data/icons/scalable/status/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.11.5 from Makefile.am. +# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, diff --git a/doc/Makefile.in b/doc/Makefile.in index cc002a6..d967458 100644 --- a/doc/Makefile.in +++ b/doc/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.11.5 from Makefile.am. +# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, diff --git a/doc/reference/Makefile.in b/doc/reference/Makefile.in index eda7a81..3eb5410 100644 --- a/doc/reference/Makefile.in +++ b/doc/reference/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.11.5 from Makefile.am. +# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, diff --git a/doc/reference/html/MessagingMenuApp.html b/doc/reference/html/MessagingMenuApp.html index e89bc0d..aab65dc 100644 --- a/doc/reference/html/MessagingMenuApp.html +++ b/doc/reference/html/MessagingMenuApp.html @@ -43,7 +43,10 @@ </tr></table></div> <div class="refsynopsisdiv"> <a name="MessagingMenuApp.synopsis"></a><h2>Synopsis</h2> -<pre class="synopsis"> <a class="link" href="MessagingMenuApp.html#MessagingMenuApp-struct" title="MessagingMenuApp">MessagingMenuApp</a>; +<pre class="synopsis"> +#include <messaging-menu.h> + + <a class="link" href="MessagingMenuApp.html#MessagingMenuApp-struct" title="MessagingMenuApp">MessagingMenuApp</a>; typedef <a class="link" href="MessagingMenuApp.html#MessagingMenuAppClass" title="MessagingMenuAppClass">MessagingMenuAppClass</a>; enum <a class="link" href="MessagingMenuApp.html#MessagingMenuStatus" title="enum MessagingMenuStatus">MessagingMenuStatus</a>; <span class="returnvalue">void</span> <a class="link" href="MessagingMenuApp.html#messaging-menu-app-append-source" title="messaging_menu_app_append_source ()">messaging_menu_app_append_source</a> (<em class="parameter"><code><a class="link" href="MessagingMenuApp.html" title="MessagingMenuApp"><span class="type">MessagingMenuApp</span></a> *app</code></em>, @@ -159,11 +162,12 @@ desktop file. Activating this item starts the application. </p> <p> Following the application item, the Messaging Menu inserts all -shortcuts actions found in the desktop file which are marked as -appearing in the Messaging Menu (the TargetEnvironment or OnlyShowIn -keywords contains "Messaging Menu"). The <a class="ulink" href="http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.1.html#extra-actions" target="_top"> +shortcut actions found in the desktop file. Actions whose +<code class="code">NotShowIn</code> keyword contains "Messaging Menu" or whose +<code class="code">OnlyShowIn</code> keyword does not contain "Messaging Menu" +will not appear (the <a class="ulink" href="http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.1.html#extra-actions" target="_top"> desktop file specification</a> contains a detailed explanation of -shortcut actions [1]. An application cannot add, remove, or change +shortcut actions.) An application cannot add, remove, or change these shortcut items while it is running. </p> <p> @@ -416,8 +420,10 @@ It is an error to insert a source with an <em class="parameter"><code>id</code>< <em class="parameter"><code>const <a href="http://library.gnome.org/devel/glib/unstable/glib-Basic-Types.html#gchar"><span class="type">gchar</span></a> *label</code></em>, <em class="parameter"><code><span class="type">gint64</span> time</code></em>);</pre> <p> -Appends a new message source to the end of the section representing <em class="parameter"><code>app</code></em> and -initializes it with <em class="parameter"><code>time</code></em>. +Appends a new message source to the end of the section representing +<em class="parameter"><code>app</code></em> and initializes it with <em class="parameter"><code>time</code></em>. Use +<a class="link" href="MessagingMenuApp.html#messaging-menu-app-append-source" title="messaging_menu_app_append_source ()"><code class="function">messaging_menu_app_append_source()</code></a> to append a source with the +current time. </p> <p> To change the time, use <a class="link" href="MessagingMenuApp.html#messaging-menu-app-set-source-time" title="messaging_menu_app_set_source_time ()"><code class="function">messaging_menu_app_set_source_time()</code></a>. @@ -449,7 +455,7 @@ It is an error to insert a source with an <em class="parameter"><code>id</code>< </tr> <tr> <td><p><span class="term"><em class="parameter"><code>time</code></em> :</span></p></td> -<td>the time when the source was created</td> +<td>the time when the source was created, in microseconds</td> </tr> </tbody> </table></div> @@ -669,7 +675,8 @@ It is an error to insert a source with an <em class="parameter"><code>id</code>< <em class="parameter"><code><span class="type">gint64</span> time</code></em>);</pre> <p> Inserts a new message source into the section representing <em class="parameter"><code>app</code></em> and -initializes it with <em class="parameter"><code>time</code></em>. +initializes it with <em class="parameter"><code>time</code></em>. Use <a class="link" href="MessagingMenuApp.html#messaging-menu-app-insert-source" title="messaging_menu_app_insert_source ()"><code class="function">messaging_menu_app_insert_source()</code></a> to +insert a source with the current time. </p> <p> To change the time, use <a class="link" href="MessagingMenuApp.html#messaging-menu-app-set-source-time" title="messaging_menu_app_set_source_time ()"><code class="function">messaging_menu_app_set_source_time()</code></a>. @@ -705,7 +712,7 @@ It is an error to insert a source with an <em class="parameter"><code>id</code>< </tr> <tr> <td><p><span class="term"><em class="parameter"><code>time</code></em> :</span></p></td> -<td>the time when the source was created</td> +<td>the time when the source was created, in microseconds</td> </tr> </tbody> </table></div> @@ -885,7 +892,7 @@ count associated with it. </tr> <tr> <td><p><span class="term"><em class="parameter"><code>time</code></em> :</span></p></td> -<td>the new time for the source</td> +<td>the new time for the source, in microseconds</td> </tr> </tbody> </table></div> diff --git a/doc/reference/html/ch01.html b/doc/reference/html/ch01.html index 522cb09..e0b133a 100644 --- a/doc/reference/html/ch01.html +++ b/doc/reference/html/ch01.html @@ -21,7 +21,7 @@ </tr></table> <div class="chapter"> <div class="titlepage"><div><div><h2 class="title"> -<a name="idp3768560"></a>API Reference</h2></div></div></div> +<a name="idp3325184"></a>API Reference</h2></div></div></div> <div class="toc"><dl><dt> <span class="refentrytitle"><a href="MessagingMenuApp.html">MessagingMenuApp</a></span><span class="refpurpose"> — An application section in the messaging menu</span> </dt></dl></div> diff --git a/doc/reference/html/index.html b/doc/reference/html/index.html index ae97e66..b899df6 100644 --- a/doc/reference/html/index.html +++ b/doc/reference/html/index.html @@ -14,7 +14,7 @@ <div class="titlepage"> <div> <div><table class="navigation" id="top" width="100%" cellpadding="2" cellspacing="0"><tr><th valign="middle"><p class="title">Messaging Menu Reference Manual</p></th></tr></table></div> -<div><p class="releaseinfo">for libmessaging-menu 12.10.2</p></div> +<div><p class="releaseinfo">for libmessaging-menu 12.10.4</p></div> <div><p class="copyright">Copyright © 2012 Canonical Ltd.</p></div> </div> <hr> diff --git a/doc/reference/messaging-menu-docs.xml b/doc/reference/messaging-menu-docs.xml index b63236a..771e269 100644 --- a/doc/reference/messaging-menu-docs.xml +++ b/doc/reference/messaging-menu-docs.xml @@ -2,7 +2,7 @@ <!DOCTYPE book PUBLIC '-//OASIS//DTD DocBook XML V4.5//EN' 'http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd' [ <!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'"> -<!ENTITY version "12.10.2"> +<!ENTITY version "12.10.4"> ]> <book lang="en" id="messaging-menu" xmlns:xi="http://www.w3.org/2003/XInclude"> <title>Messaging Menu Reference Manual</title> diff --git a/libmessaging-menu/Makefile.am b/libmessaging-menu/Makefile.am index ef37700..7a6ee31 100644 --- a/libmessaging-menu/Makefile.am +++ b/libmessaging-menu/Makefile.am @@ -50,8 +50,10 @@ 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_SCANNERFLAGS = --c-include="messaging-menu.h" MessagingMenu_1_0_gir_LIBS = libmessaging-menu.la MessagingMenu_1_0_gir_FILES = messaging-menu.c messaging-menu.h +MessagingMenu_1_0_gir_EXPORT_PACKAGES = messaging-menu INTROSPECTION_GIRS += MessagingMenu-1.0.gir girdir = $(datadir)/gir-1.0 diff --git a/libmessaging-menu/Makefile.in b/libmessaging-menu/Makefile.in index 29215c2..f1d3cab 100644 --- a/libmessaging-menu/Makefile.in +++ b/libmessaging-menu/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.11.5 from Makefile.am. +# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, @@ -365,8 +365,10 @@ INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir) @HAVE_INTROSPECTION_TRUE@MessagingMenu_1_0_gir_NAMESPACE = MessagingMenu @HAVE_INTROSPECTION_TRUE@MessagingMenu_1_0_gir_INCLUDES = GObject-2.0 Gio-2.0 @HAVE_INTROSPECTION_TRUE@MessagingMenu_1_0_gir_CFLAGS = $(INCLUDES) $(GIO_CFLAGS) +@HAVE_INTROSPECTION_TRUE@MessagingMenu_1_0_gir_SCANNERFLAGS = --c-include="messaging-menu.h" @HAVE_INTROSPECTION_TRUE@MessagingMenu_1_0_gir_LIBS = libmessaging-menu.la @HAVE_INTROSPECTION_TRUE@MessagingMenu_1_0_gir_FILES = messaging-menu.c messaging-menu.h +@HAVE_INTROSPECTION_TRUE@MessagingMenu_1_0_gir_EXPORT_PACKAGES = messaging-menu @HAVE_INTROSPECTION_TRUE@girdir = $(datadir)/gir-1.0 @HAVE_INTROSPECTION_TRUE@gir_DATA = $(INTROSPECTION_GIRS) @HAVE_INTROSPECTION_TRUE@typelibdir = $(libdir)/girepository-1.0 diff --git a/libmessaging-menu/indicator-messages-service.c b/libmessaging-menu/indicator-messages-service.c index a42a534..7f2ab87 100644 --- a/libmessaging-menu/indicator-messages-service.c +++ b/libmessaging-menu/indicator-messages-service.c @@ -1,5 +1,5 @@ /* - * Generated by gdbus-codegen 2.33.10. DO NOT EDIT. + * Generated by gdbus-codegen 2.33.12. DO NOT EDIT. * * The license of this code is the same as for the source it was derived from. */ @@ -235,6 +235,17 @@ static const _ExtendedGDBusMethodInfo _indicator_messages_service_method_info_un FALSE }; +static const _ExtendedGDBusArgInfo _indicator_messages_service_method_info_set_status_IN_ARG_desktop_id = +{ + { + -1, + (gchar *) "desktop_id", + (gchar *) "s", + NULL + }, + FALSE +}; + static const _ExtendedGDBusArgInfo _indicator_messages_service_method_info_set_status_IN_ARG_status = { { @@ -248,6 +259,7 @@ static const _ExtendedGDBusArgInfo _indicator_messages_service_method_info_set_s static const _ExtendedGDBusArgInfo * const _indicator_messages_service_method_info_set_status_IN_ARG_pointers[] = { + &_indicator_messages_service_method_info_set_status_IN_ARG_desktop_id, &_indicator_messages_service_method_info_set_status_IN_ARG_status, NULL }; @@ -424,6 +436,7 @@ indicator_messages_service_default_init (IndicatorMessagesServiceIface *iface) * IndicatorMessagesService::handle-set-status: * @object: A #IndicatorMessagesService. * @invocation: A #GDBusMethodInvocation. + * @arg_desktop_id: Argument passed by remote caller. * @arg_status: Argument passed by remote caller. * * Signal emitted when a remote caller is invoking the <link linkend="gdbus-method-com-canonical-indicator-messages-service.SetStatus">SetStatus()</link> D-Bus method. @@ -440,8 +453,8 @@ indicator_messages_service_default_init (IndicatorMessagesServiceIface *iface) NULL, g_cclosure_marshal_generic, G_TYPE_BOOLEAN, - 2, - G_TYPE_DBUS_METHOD_INVOCATION, G_TYPE_STRING); + 3, + G_TYPE_DBUS_METHOD_INVOCATION, G_TYPE_STRING, G_TYPE_STRING); /* GObject signals for received D-Bus signals: */ /** @@ -688,6 +701,7 @@ _out: /** * indicator_messages_service_call_set_status: * @proxy: A #IndicatorMessagesServiceProxy. + * @arg_desktop_id: Argument to pass with the method invocation. * @arg_status: Argument to pass with the method invocation. * @cancellable: (allow-none): A #GCancellable or %NULL. * @callback: A #GAsyncReadyCallback to call when the request is satisfied or %NULL. @@ -702,6 +716,7 @@ _out: void indicator_messages_service_call_set_status ( IndicatorMessagesService *proxy, + const gchar *arg_desktop_id, const gchar *arg_status, GCancellable *cancellable, GAsyncReadyCallback callback, @@ -709,7 +724,8 @@ indicator_messages_service_call_set_status ( { g_dbus_proxy_call (G_DBUS_PROXY (proxy), "SetStatus", - g_variant_new ("(s)", + g_variant_new ("(ss)", + arg_desktop_id, arg_status), G_DBUS_CALL_FLAGS_NONE, -1, @@ -748,6 +764,7 @@ _out: /** * indicator_messages_service_call_set_status_sync: * @proxy: A #IndicatorMessagesServiceProxy. + * @arg_desktop_id: Argument to pass with the method invocation. * @arg_status: Argument to pass with the method invocation. * @cancellable: (allow-none): A #GCancellable or %NULL. * @error: Return location for error or %NULL. @@ -761,6 +778,7 @@ _out: gboolean indicator_messages_service_call_set_status_sync ( IndicatorMessagesService *proxy, + const gchar *arg_desktop_id, const gchar *arg_status, GCancellable *cancellable, GError **error) @@ -768,7 +786,8 @@ indicator_messages_service_call_set_status_sync ( GVariant *_ret; _ret = g_dbus_proxy_call_sync (G_DBUS_PROXY (proxy), "SetStatus", - g_variant_new ("(s)", + g_variant_new ("(ss)", + arg_desktop_id, arg_status), G_DBUS_CALL_FLAGS_NONE, -1, diff --git a/libmessaging-menu/indicator-messages-service.h b/libmessaging-menu/indicator-messages-service.h index 2adaaf3..2401d0e 100644 --- a/libmessaging-menu/indicator-messages-service.h +++ b/libmessaging-menu/indicator-messages-service.h @@ -1,5 +1,5 @@ /* - * Generated by gdbus-codegen 2.33.10. DO NOT EDIT. + * Generated by gdbus-codegen 2.33.12. DO NOT EDIT. * * The license of this code is the same as for the source it was derived from. */ @@ -38,6 +38,7 @@ struct _IndicatorMessagesServiceIface gboolean (*handle_set_status) ( IndicatorMessagesService *object, GDBusMethodInvocation *invocation, + const gchar *arg_desktop_id, const gchar *arg_status); gboolean (*handle_unregister_application) ( @@ -120,6 +121,7 @@ gboolean indicator_messages_service_call_unregister_application_sync ( void indicator_messages_service_call_set_status ( IndicatorMessagesService *proxy, + const gchar *arg_desktop_id, const gchar *arg_status, GCancellable *cancellable, GAsyncReadyCallback callback, @@ -132,6 +134,7 @@ gboolean indicator_messages_service_call_set_status_finish ( gboolean indicator_messages_service_call_set_status_sync ( IndicatorMessagesService *proxy, + const gchar *arg_desktop_id, const gchar *arg_status, GCancellable *cancellable, GError **error); diff --git a/libmessaging-menu/messaging-menu.c b/libmessaging-menu/messaging-menu.c index 93727fc..3c5c6d4 100644 --- a/libmessaging-menu/messaging-menu.c +++ b/libmessaging-menu/messaging-menu.c @@ -27,6 +27,7 @@ * SECTION:messaging-menu * @title: MessagingMenuApp * @short_description: An application section in the messaging menu + * @include: messaging-menu.h * * A #MessagingMenuApp represents an application section in the * Messaging Menu. An application section is tied to an installed @@ -42,12 +43,13 @@ * desktop file. Activating this item starts the application. * * Following the application item, the Messaging Menu inserts all - * shortcuts actions found in the desktop file which are marked as - * appearing in the Messaging Menu (the TargetEnvironment or OnlyShowIn - * keywords contains "Messaging Menu"). The <ulink + * shortcut actions found in the desktop file. Actions whose + * <code>NotShowIn</code> keyword contains "Messaging Menu" or whose + * <code>OnlyShowIn</code> keyword does not contain "Messaging Menu" + * will not appear (the <ulink * url="http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.1.html#extra-actions"> * desktop file specification</ulink> contains a detailed explanation of - * shortcut actions [1]. An application cannot add, remove, or change + * shortcut actions.) An application cannot add, remove, or change * these shortcut items while it is running. * * Next, an application section contains menu items for message sources. @@ -100,6 +102,7 @@ struct _MessagingMenuApp GDesktopAppInfo *appinfo; int registered; /* -1 for unknown */ MessagingMenuStatus status; + gboolean status_set; GSimpleActionGroup *source_actions; GMenu *menu; @@ -145,7 +148,8 @@ messaging_menu_app_get_dbus_object_path (MessagingMenuApp *app) { gchar *path; - g_return_val_if_fail (app->appinfo != NULL, NULL); + if (!app->appinfo) + return NULL; path = g_strconcat ("/com/canonical/indicator/messages/", g_app_info_get_id (G_APP_INFO (app->appinfo)), @@ -167,6 +171,10 @@ export_menus_and_actions (GObject *source, guint id; gchar *object_path; + object_path = messaging_menu_app_get_dbus_object_path (app); + if (!object_path) + return; + bus = g_bus_get_finish (res, &error); if (bus == NULL) { @@ -175,8 +183,6 @@ export_menus_and_actions (GObject *source, return; } - object_path = messaging_menu_app_get_dbus_object_path (app); - id = g_dbus_connection_export_action_group (bus, object_path, G_ACTION_GROUP (app->source_actions), @@ -368,7 +374,8 @@ created_messages_service (GObject *source_object, messaging_menu_app_register (app); else if (app->registered == FALSE) messaging_menu_app_unregister (app); - messaging_menu_app_set_status (app, app->status); + if (app->status_set) + messaging_menu_app_set_status (app, app->status); } static void @@ -408,7 +415,7 @@ static void messaging_menu_app_init (MessagingMenuApp *app) { app->registered = -1; - app->status = MESSAGING_MENU_STATUS_OFFLINE; + app->status_set = FALSE; app->cancellable = g_cancellable_new (); @@ -475,6 +482,8 @@ messaging_menu_app_register (MessagingMenuApp *app) return; object_path = messaging_menu_app_get_dbus_object_path (app); + if (!object_path) + return; indicator_messages_service_call_register_application (app->messages_service, g_app_info_get_id (G_APP_INFO (app->appinfo)), @@ -506,6 +515,9 @@ messaging_menu_app_unregister (MessagingMenuApp *app) if (!app->messages_service) return; + if (!app->appinfo) + return; + indicator_messages_service_call_unregister_application (app->messages_service, g_app_info_get_id (G_APP_INFO (app->appinfo)), app->cancellable, @@ -536,12 +548,17 @@ messaging_menu_app_set_status (MessagingMenuApp *app, status <= MESSAGING_MENU_STATUS_OFFLINE); app->status = status; + app->status_set = TRUE; /* state will be synced right after connecting to the service */ if (!app->messages_service) return; + if (!app->appinfo) + return; + indicator_messages_service_call_set_status (app->messages_service, + g_app_info_get_id (G_APP_INFO (app->appinfo)), status_ids [status], app->cancellable, NULL, NULL); @@ -575,8 +592,7 @@ global_status_changed (IndicatorMessagesService *service, 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); + g_signal_emit (app, signals[STATUS_CHANGED], 0, status); } static void @@ -762,10 +778,11 @@ void messaging_menu_app_append_source_with_count (MessagingMenuApp *app, * @id: a unique identifier for the source to be added * @icon: (allow-none): the icon associated with the source * @label: a user-visible string best describing the source - * @time: the time when the source was created + * @time: the time when the source was created, in microseconds * * Inserts a new message source into the section representing @app and - * initializes it with @time. + * initializes it with @time. Use messaging_menu_app_insert_source() to + * insert a source with the current time. * * To change the time, use messaging_menu_app_set_source_time(). * @@ -790,10 +807,12 @@ messaging_menu_app_insert_source_with_time (MessagingMenuApp *app, * @id: a unique identifier for the source to be added * @icon: (allow-none): the icon associated with the source * @label: a user-visible string best describing the source - * @time: the time when the source was created + * @time: the time when the source was created, in microseconds * - * Appends a new message source to the end of the section representing @app and - * initializes it with @time. + * Appends a new message source to the end of the section representing + * @app and initializes it with @time. Use + * messaging_menu_app_append_source() to append a source with the + * current time. * * To change the time, use messaging_menu_app_set_source_time(). * @@ -1044,7 +1063,7 @@ void messaging_menu_app_set_source_count (MessagingMenuApp *app, * messaging_menu_app_set_source_time: * @app: a #MessagingMenuApp * @source_id: a source id - * @time: the new time for the source + * @time: the new time for the source, in microseconds * * Updates the time of @source_id to @time. * diff --git a/src/Makefile.am b/src/Makefile.am index 4d86730..1df80e5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -21,6 +21,8 @@ libmessaging_la_SOURCES = \ im-app-menu-item.h \ im-source-menu-item.c \ im-source-menu-item.h \ + ido-detail-label.c \ + ido-detail-label.h \ indicator-messages-service.c \ indicator-messages-service.h dbus-data.h diff --git a/src/Makefile.in b/src/Makefile.in index 9fe1c45..2fd86c6 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.11.5 from Makefile.am. +# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, @@ -100,6 +100,7 @@ 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-ido-detail-label.lo \ libmessaging_la-indicator-messages-service.lo libmessaging_la_OBJECTS = $(am_libmessaging_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) @@ -366,6 +367,8 @@ libmessaging_la_SOURCES = \ im-app-menu-item.h \ im-source-menu-item.c \ im-source-menu-item.h \ + ido-detail-label.c \ + ido-detail-label.h \ indicator-messages-service.c \ indicator-messages-service.h @@ -549,6 +552,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-detail-label.Plo@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@ @@ -604,6 +608,13 @@ libmessaging_la-im-source-menu-item.lo: im-source-menu-item.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-im-source-menu-item.lo `test -f 'im-source-menu-item.c' || echo '$(srcdir)/'`im-source-menu-item.c +libmessaging_la-ido-detail-label.lo: ido-detail-label.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-detail-label.lo -MD -MP -MF $(DEPDIR)/libmessaging_la-ido-detail-label.Tpo -c -o libmessaging_la-ido-detail-label.lo `test -f 'ido-detail-label.c' || echo '$(srcdir)/'`ido-detail-label.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmessaging_la-ido-detail-label.Tpo $(DEPDIR)/libmessaging_la-ido-detail-label.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ido-detail-label.c' object='libmessaging_la-ido-detail-label.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-detail-label.lo `test -f 'ido-detail-label.c' || echo '$(srcdir)/'`ido-detail-label.c + libmessaging_la-indicator-messages-service.lo: indicator-messages-service.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-indicator-messages-service.lo -MD -MP -MF $(DEPDIR)/libmessaging_la-indicator-messages-service.Tpo -c -o libmessaging_la-indicator-messages-service.lo `test -f 'indicator-messages-service.c' || echo '$(srcdir)/'`indicator-messages-service.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmessaging_la-indicator-messages-service.Tpo $(DEPDIR)/libmessaging_la-indicator-messages-service.Plo diff --git a/src/app-section.c b/src/app-section.c index bed1302..6aac52a 100644 --- a/src/app-section.c +++ b/src/app-section.c @@ -37,7 +37,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>. struct _AppSectionPrivate { GDesktopAppInfo * appinfo; - guint unreadcount; + GFileMonitor *desktop_file_monitor; IndicatorDesktopShortcuts * ids; @@ -50,6 +50,7 @@ struct _AppSectionPrivate gboolean draws_attention; gboolean uses_chat_status; + gchar *chat_status; guint name_watch_id; }; @@ -60,10 +61,12 @@ enum { PROP_ACTIONS, PROP_DRAWS_ATTENTION, PROP_USES_CHAT_STATUS, + PROP_CHAT_STATUS, NUM_PROPERTIES }; static GParamSpec *properties[NUM_PROPERTIES]; +static guint destroy_signal; /* Prototypes */ static void app_section_class_init (AppSectionClass *klass); @@ -77,6 +80,7 @@ static void app_section_set_property (GObject *object, const GValue *value, GParamSpec *pspec); static void app_section_dispose (GObject *object); +static void app_section_finalize (GObject *object); static void activate_cb (GSimpleAction *action, GVariant *param, gpointer userdata); @@ -98,6 +102,11 @@ static void action_removed (GActionGroup *group, const gchar *action_name, gpointer user_data); static gboolean action_draws_attention (GVariant *state); +static void desktop_file_changed_cb (GFileMonitor *monitor, + GFile *file, + GFile *other_file, + GFileMonitorEvent event, + gpointer user_data); /* GObject Boilerplate */ G_DEFINE_TYPE (AppSection, app_section, G_TYPE_OBJECT); @@ -112,6 +121,7 @@ app_section_class_init (AppSectionClass *klass) object_class->get_property = app_section_get_property; object_class->set_property = app_section_set_property; object_class->dispose = app_section_dispose; + object_class->finalize = app_section_finalize; properties[PROP_APPINFO] = g_param_spec_object ("app-info", "AppInfo", @@ -137,7 +147,22 @@ app_section_class_init (AppSectionClass *klass) FALSE, G_PARAM_READABLE); + properties[PROP_CHAT_STATUS] = g_param_spec_string ("chat-status", + "Chat status", + "Current chat status of the application", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, NUM_PROPERTIES, properties); + + destroy_signal = g_signal_new ("destroy", + APP_SECTION_TYPE, + G_SIGNAL_RUN_FIRST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); } static void @@ -151,7 +176,6 @@ app_section_init (AppSection *self) priv = self->priv; priv->appinfo = NULL; - priv->unreadcount = 0; priv->menu = g_menu_new (); priv->static_shortcuts = g_simple_action_group_new (); @@ -186,6 +210,10 @@ app_section_get_property (GObject *object, g_value_set_boolean (value, app_section_get_uses_chat_status (self)); break; + case PROP_CHAT_STATUS: + g_value_set_string (value, app_section_get_status (self)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } @@ -205,16 +233,26 @@ app_section_set_property (GObject *object, app_section_set_app_info (self, g_value_get_object (value)); break; + case PROP_CHAT_STATUS: + app_section_set_status (self, g_value_get_string (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 = self->priv; + if (priv->desktop_file_monitor) { + g_signal_handlers_disconnect_by_func (priv->desktop_file_monitor, desktop_file_changed_cb, self); + g_clear_object (&priv->desktop_file_monitor); + } + g_clear_object (&priv->menu); g_clear_object (&priv->static_shortcuts); @@ -242,6 +280,16 @@ app_section_dispose (GObject *object) G_OBJECT_CLASS (app_section_parent_class)->dispose (object); } +static void +app_section_finalize (GObject *object) +{ + AppSection * self = APP_SECTION(object); + + g_free (self->priv->chat_status); + + 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, @@ -289,6 +337,9 @@ keyfile_loaded (GObject *source_object, G_KEY_FILE_DESKTOP_GROUP, "X-MessagingMenu-UsesChatSection", &error); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_USES_CHAT_STATUS]); + if (error) { if (error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND) { g_warning ("could not read X-MessagingMenu-UsesChatSection: %s", @@ -298,34 +349,48 @@ keyfile_loaded (GObject *source_object, 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) +g_menu_clear (GMenu *menu) +{ + gint n_items = g_menu_model_get_n_items (G_MENU_MODEL (menu)); + + while (n_items--) + g_menu_remove (menu, 0); +} + +static void +g_simple_action_group_clear (GSimpleActionGroup *group) +{ + gchar **actions; + gchar **it; + + actions = g_action_group_list_actions (G_ACTION_GROUP (group)); + for (it = actions; *it; it++) + g_simple_action_group_remove (group, *it); + + g_strfreev (actions); +} + +static void +app_section_update_menu (AppSection *self) { AppSectionPrivate *priv = self->priv; GSimpleAction *launch; GFile *keyfile; GMenuItem *item; gchar *iconstr; + gboolean is_running; - g_return_if_fail (priv->appinfo == NULL); - - if (appinfo == NULL) { - g_warning ("appinfo must not be NULL"); - return; - } - - priv->appinfo = g_object_ref (appinfo); + g_menu_clear (priv->menu); + g_simple_action_group_clear (priv->static_shortcuts); - launch = g_simple_action_new_stateful ("launch", NULL, g_variant_new_boolean (FALSE)); + is_running = priv->name_watch_id > 0; + launch = g_simple_action_new_stateful ("launch", NULL, g_variant_new_boolean (is_running)); 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)); @@ -366,14 +431,65 @@ app_section_set_app_info (AppSection *self, 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]); + g_object_unref (keyfile); g_object_unref (launch); } +static void +desktop_file_changed_cb (GFileMonitor *monitor, + GFile *file, + GFile *other_file, + GFileMonitorEvent event, + gpointer user_data) +{ + AppSection *self = user_data; + + if (event == G_FILE_MONITOR_EVENT_CHANGED) { + app_section_update_menu (self); + } + else if (event == G_FILE_MONITOR_EVENT_DELETED || + event == G_FILE_MONITOR_EVENT_UNMOUNTED) { + g_signal_emit (self, destroy_signal, 0); + } +} + +static void +app_section_set_app_info (AppSection *self, + GDesktopAppInfo *appinfo) +{ + AppSectionPrivate *priv = self->priv; + GFile *desktop_file; + GError *error = NULL; + + g_return_if_fail (priv->appinfo == NULL); + g_return_if_fail (priv->desktop_file_monitor == NULL); + + if (appinfo == NULL) { + g_warning ("appinfo must not be NULL"); + return; + } + + priv->appinfo = g_object_ref (appinfo); + + desktop_file = g_file_new_for_path (g_desktop_app_info_get_filename (appinfo)); + priv->desktop_file_monitor = g_file_monitor (desktop_file, G_FILE_MONITOR_SEND_MOVED, NULL, &error); + if (priv->desktop_file_monitor == NULL) { + g_warning ("unable to watch desktop file: %s", error->message); + g_error_free (error); + } + g_signal_connect (priv->desktop_file_monitor, "changed", + G_CALLBACK (desktop_file_changed_cb), self); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_APPINFO]); + + app_section_update_menu (self); + + g_object_unref (desktop_file); +} + AppSection * app_section_new (GDesktopAppInfo *appinfo) { @@ -407,25 +523,6 @@ launch_action_change_state (GSimpleAction *action, g_simple_action_set_state (action, value); } -guint -app_section_get_count (AppSection * self) -{ - AppSectionPrivate * priv = self->priv; - - return priv->unreadcount; -} - -const gchar * -app_section_get_name (AppSection * self) -{ - AppSectionPrivate * priv = self->priv; - - if (priv->appinfo) { - return g_app_info_get_name(G_APP_INFO(priv->appinfo)); - } - return NULL; -} - const gchar * app_section_get_desktop (AppSection * self) { @@ -600,10 +697,12 @@ app_section_unset_object_path (AppSection *self) } priv->draws_attention = FALSE; + g_clear_pointer (&priv->chat_status, g_free); 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_notify_by_pspec (G_OBJECT (self), properties[PROP_CHAT_STATUS]); g_action_group_change_action_state (G_ACTION_GROUP (priv->static_shortcuts), "launch", g_variant_new_boolean (FALSE)); @@ -695,3 +794,23 @@ app_section_get_uses_chat_status (AppSection *self) return priv->uses_chat_status; } + +const gchar * +app_section_get_status (AppSection *self) +{ + AppSectionPrivate * priv = self->priv; + + return priv->chat_status; +} + +void +app_section_set_status (AppSection *self, + const gchar *status) +{ + AppSectionPrivate * priv = self->priv; + + g_free (priv->chat_status); + priv->chat_status = g_strdup (status); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_CHAT_STATUS]); +} diff --git a/src/app-section.h b/src/app-section.h index 711fdc9..7c39e8e 100644 --- a/src/app-section.h +++ b/src/app-section.h @@ -51,8 +51,6 @@ struct _AppSection { 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); GActionGroup * app_section_get_actions (AppSection *self); GMenuModel * app_section_get_menu (AppSection *appitem); @@ -65,6 +63,9 @@ void app_section_set_object_path (AppSection *self, const gchar *object_path); void app_section_unset_object_path (AppSection *self); gboolean app_section_get_uses_chat_status (AppSection *self); +const gchar * app_section_get_status (AppSection *self); +void app_section_set_status (AppSection *self, + const gchar *status); G_END_DECLS diff --git a/src/ido-detail-label.c b/src/ido-detail-label.c new file mode 100644 index 0000000..780a2dd --- /dev/null +++ b/src/ido-detail-label.c @@ -0,0 +1,396 @@ +/* + * 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-detail-label.h" + +#include <math.h> + +G_DEFINE_TYPE (IdoDetailLabel, ido_detail_label, GTK_TYPE_WIDGET) + +struct _IdoDetailLabelPrivate +{ + gchar *text; + PangoLayout *layout; + gboolean draw_lozenge; +}; + +enum +{ + PROP_0, + PROP_TEXT, + NUM_PROPERTIES +}; + +static GParamSpec *properties[NUM_PROPERTIES]; + +static void +ido_detail_label_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + IdoDetailLabel *self = IDO_DETAIL_LABEL (object); + + switch (property_id) + { + case PROP_TEXT: + g_value_set_string (value, self->priv->text); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +ido_detail_label_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + IdoDetailLabel *self = IDO_DETAIL_LABEL (object); + + switch (property_id) + { + case PROP_TEXT: + ido_detail_label_set_text (self, g_value_get_string (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + + +static void +ido_detail_label_finalize (GObject *object) +{ + IdoDetailLabelPrivate *priv = IDO_DETAIL_LABEL (object)->priv; + + g_free (priv->text); + + G_OBJECT_CLASS (ido_detail_label_parent_class)->finalize (object); +} + +static void +ido_detail_label_dispose (GObject *object) +{ + IdoDetailLabelPrivate *priv = IDO_DETAIL_LABEL (object)->priv; + + g_clear_object (&priv->layout); + + G_OBJECT_CLASS (ido_detail_label_parent_class)->dispose (object); +} + +static void +ido_detail_label_ensure_layout (IdoDetailLabel *label) +{ + IdoDetailLabelPrivate *priv = label->priv; + + if (priv->layout == NULL) + { + priv->layout = gtk_widget_create_pango_layout (GTK_WIDGET (label), priv->text); + pango_layout_set_alignment (priv->layout, PANGO_ALIGN_CENTER); + pango_layout_set_ellipsize (priv->layout, PANGO_ELLIPSIZE_END); + pango_layout_set_height (priv->layout, -1); + + // TODO update layout on "style-updated" and "direction-changed" + } +} + +static void +cairo_lozenge (cairo_t *cr, + double x, + double y, + double w, + double h, + double radius) +{ + double x1 = x + w - radius; + double x2 = x + radius; + double y1 = y + radius; + double y2 = y + h - radius; + + cairo_move_to (cr, x + radius, y); + cairo_arc (cr, x1, y1, radius, G_PI * 1.5, G_PI * 2); + cairo_arc (cr, x1, y2, radius, 0, G_PI * 0.5); + cairo_arc (cr, x2, y2, radius, G_PI * 0.5, G_PI); + cairo_arc (cr, x2, y1, radius, G_PI, G_PI * 1.5); +} + +static PangoFontMetrics * +gtk_widget_get_font_metrics (GtkWidget *widget, + PangoContext *context) +{ + const PangoFontDescription *font; + + font = gtk_style_context_get_font (gtk_widget_get_style_context (widget), + gtk_widget_get_state_flags (widget)); + + return pango_context_get_metrics (context, + font, + pango_context_get_language (context)); +} + +static gint +ido_detail_label_get_minimum_text_width (IdoDetailLabel *label) +{ + IdoDetailLabelPrivate *priv = label->priv; + PangoContext *context; + PangoFontMetrics *metrics; + gint char_width; + gint w; + + context = pango_layout_get_context (priv->layout); + metrics = gtk_widget_get_font_metrics (GTK_WIDGET (label), context); + char_width = pango_font_metrics_get_approximate_digit_width (metrics); + + w = 2 * char_width / PANGO_SCALE; + pango_font_metrics_unref (metrics); + return w; +} + +static gboolean +ido_detail_label_draw (GtkWidget *widget, + cairo_t *cr) +{ + IdoDetailLabel *label = IDO_DETAIL_LABEL (widget); + IdoDetailLabelPrivate *priv = IDO_DETAIL_LABEL (widget)->priv; + PangoRectangle extents; + GtkAllocation allocation; + double x, w, h, radius; + GdkRGBA color; + + if (!priv->text || !*priv->text) + return TRUE; + + gtk_widget_get_allocation (widget, &allocation); + + ido_detail_label_ensure_layout (IDO_DETAIL_LABEL (widget)); + + pango_layout_get_extents (priv->layout, NULL, &extents); + pango_extents_to_pixels (&extents, NULL); + + h = MIN (allocation.height, extents.height); + radius = floor (h / 2.0); + w = MAX (ido_detail_label_get_minimum_text_width (label), extents.width) + 2.0 * radius; + x = allocation.width - w; + + pango_layout_set_width (priv->layout, (allocation.width - 2 * radius) * PANGO_SCALE); + pango_layout_get_extents (priv->layout, NULL, &extents); + pango_extents_to_pixels (&extents, NULL); + + 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); + + cairo_set_line_width (cr, 1.0); + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + + if (priv->draw_lozenge) + cairo_lozenge (cr, x, 0.0, w, h, radius); + + cairo_move_to (cr, x + radius, (allocation.height - extents.height) / 2.0); + pango_cairo_layout_path (cr, priv->layout); + cairo_fill (cr); + + return TRUE; +} + +static void +ido_detail_label_get_preferred_width (GtkWidget *widget, + gint *minimum, + gint *natural) +{ + IdoDetailLabelPrivate *priv = IDO_DETAIL_LABEL (widget)->priv; + PangoRectangle extents; + double radius; + + ido_detail_label_ensure_layout (IDO_DETAIL_LABEL (widget)); + + pango_layout_get_extents (priv->layout, NULL, &extents); + pango_extents_to_pixels (&extents, NULL); + + radius = floor (extents.height / 2.0); + + *minimum = ido_detail_label_get_minimum_text_width (IDO_DETAIL_LABEL (widget)) + 2.0 * radius; + *natural = MAX (*minimum, extents.width + 2.0 * radius); +} + +static void +ido_detail_label_get_preferred_height (GtkWidget *widget, + gint *minimum, + gint *natural) +{ + IdoDetailLabelPrivate *priv = IDO_DETAIL_LABEL (widget)->priv; + PangoContext *context; + PangoFontMetrics *metrics; + PangoRectangle extents; + + ido_detail_label_ensure_layout (IDO_DETAIL_LABEL (widget)); + + pango_layout_get_extents (priv->layout, NULL, &extents); + pango_extents_to_pixels (&extents, NULL); + context = pango_layout_get_context (priv->layout); + metrics = gtk_widget_get_font_metrics (widget, context); + + *minimum = *natural = (pango_font_metrics_get_ascent (metrics) + + pango_font_metrics_get_descent (metrics)) / PANGO_SCALE; + + pango_font_metrics_unref (metrics); +} + +static void +ido_detail_label_class_init (IdoDetailLabelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->get_property = ido_detail_label_get_property; + object_class->set_property = ido_detail_label_set_property; + object_class->finalize = ido_detail_label_finalize; + object_class->dispose = ido_detail_label_dispose; + + widget_class->draw = ido_detail_label_draw; + widget_class->get_preferred_width = ido_detail_label_get_preferred_width; + widget_class->get_preferred_height = ido_detail_label_get_preferred_height; + + g_type_class_add_private (klass, sizeof (IdoDetailLabelPrivate)); + + properties[PROP_TEXT] = g_param_spec_string ("text", + "Text", + "The text of the label", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, NUM_PROPERTIES, properties); +} + +static void +ido_detail_label_init (IdoDetailLabel *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + IDO_TYPE_DETAIL_LABEL, + IdoDetailLabelPrivate); + + gtk_widget_set_has_window (GTK_WIDGET (self), FALSE); +} + +GtkWidget * +ido_detail_label_new (const gchar *label) +{ + return g_object_new (IDO_TYPE_DETAIL_LABEL, + "text", label, + NULL); +} + +const gchar * +ido_detail_label_get_text (IdoDetailLabel *label) +{ + g_return_val_if_fail (IDO_IS_DETAIL_LABEL (label), NULL); + return label->priv->text; +} + +/* 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 void +ido_detail_label_set_text_impl (IdoDetailLabel *label, + const gchar *text, + gboolean draw_lozenge) +{ + IdoDetailLabelPrivate * priv = label->priv; + + g_clear_object (&priv->layout); + g_free (priv->text); + + priv->text = g_strdup (text); + priv->draw_lozenge = draw_lozenge; + + g_object_notify_by_pspec (G_OBJECT (label), properties[PROP_TEXT]); + gtk_widget_queue_resize (GTK_WIDGET (label)); +} + +void +ido_detail_label_set_text (IdoDetailLabel *label, + const gchar *text) +{ + gchar *str; + + g_return_if_fail (IDO_IS_DETAIL_LABEL (label)); + + str = collapse_whitespace (text); + ido_detail_label_set_text_impl (label, str, FALSE); + g_free (str); +} + +void +ido_detail_label_set_count (IdoDetailLabel *label, + gint count) +{ + gchar *text; + + g_return_if_fail (IDO_IS_DETAIL_LABEL (label)); + + text = g_strdup_printf ("%d", count); + ido_detail_label_set_text_impl (label, text, TRUE); + g_free (text); +} diff --git a/src/ido-detail-label.h b/src/ido-detail-label.h new file mode 100644 index 0000000..1995fee --- /dev/null +++ b/src/ido-detail-label.h @@ -0,0 +1,59 @@ +/* + * 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_DETAIL_LABEL_H__ +#define __IDO_DETAIL_LABEL_H__ + +#include <gtk/gtk.h> + +#define IDO_TYPE_DETAIL_LABEL (ido_detail_label_get_type()) +#define IDO_DETAIL_LABEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IDO_TYPE_DETAIL_LABEL, IdoDetailLabel)) +#define IDO_DETAIL_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), IDO_TYPE_DETAIL_LABEL, IdoDetailLabelClass)) +#define IDO_IS_DETAIL_LABEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IDO_TYPE_DETAIL_LABEL)) +#define IDO_IS_DETAIL_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), IDO_TYPE_DETAIL_LABEL)) +#define IDO_DETAIL_LABEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), IDO_TYPE_DETAIL_LABEL, IdoDetailLabelClass)) + +typedef struct _IdoDetailLabel IdoDetailLabel; +typedef struct _IdoDetailLabelClass IdoDetailLabelClass; +typedef struct _IdoDetailLabelPrivate IdoDetailLabelPrivate; + +struct _IdoDetailLabel +{ + GtkWidget parent; + IdoDetailLabelPrivate *priv; +}; + +struct _IdoDetailLabelClass +{ + GtkWidgetClass parent_class; +}; + +GType ido_detail_label_get_type (void) G_GNUC_CONST; + +GtkWidget * ido_detail_label_new (const gchar *str); + +const gchar * ido_detail_label_get_text (IdoDetailLabel *label); + +void ido_detail_label_set_text (IdoDetailLabel *label, + const gchar *text); + +void ido_detail_label_set_count (IdoDetailLabel *label, + gint count); + +#endif diff --git a/src/ido-menu-item.c b/src/ido-menu-item.c index 6b19d2a..32044ff 100644 --- a/src/ido-menu-item.c +++ b/src/ido-menu-item.c @@ -99,8 +99,37 @@ ido_menu_item_set_state (IdoMenuItem *self, if (priv->target) { ido_menu_item_set_has_indicator (self, TRUE); + ido_menu_item_set_active (self, FALSE); 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)); + gtk_check_menu_item_set_inconsistent (GTK_CHECK_MENU_ITEM (self), FALSE); + + if (g_variant_is_of_type (state, G_VARIANT_TYPE_STRING)) + { + ido_menu_item_set_active (self, g_variant_equal (priv->target, state)); + } + else if (g_variant_is_of_type (state, G_VARIANT_TYPE ("as")) && + g_variant_is_of_type (priv->target, G_VARIANT_TYPE_STRING)) + { + const gchar *target_str; + const gchar **state_strs; + const gchar **it; + + target_str = g_variant_get_string (priv->target, NULL); + state_strs = g_variant_get_strv (state, NULL); + + it = state_strs; + while (*it != NULL && !g_str_equal (*it, target_str)) + it++; + + if (*it != NULL) + { + ido_menu_item_set_active (self, TRUE); + gtk_check_menu_item_set_inconsistent (GTK_CHECK_MENU_ITEM (self), + g_strv_length ((gchar **)state_strs) > 1); + } + + g_free (state_strs); + } } else if (g_variant_is_of_type (state, G_VARIANT_TYPE_BOOLEAN)) { @@ -258,7 +287,8 @@ ido_menu_item_activate (GtkMenuItem *item) 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); + if (priv->in_set_active) + GTK_MENU_ITEM_CLASS (ido_menu_item_parent_class)->activate (item); } static void diff --git a/src/im-source-menu-item.c b/src/im-source-menu-item.c index 5aebb68..775fa91 100644 --- a/src/im-source-menu-item.c +++ b/src/im-source-menu-item.c @@ -20,6 +20,7 @@ #include "im-source-menu-item.h" #include <libintl.h> +#include "ido-detail-label.h" struct _ImSourceMenuItemPrivate { @@ -59,11 +60,13 @@ im_source_menu_item_constructed (GObject *object) gtk_widget_set_margin_left (priv->icon, icon_width + 6); priv->label = g_object_ref (gtk_label_new ("")); + gtk_label_set_max_width_chars (GTK_LABEL (priv->label), 40); + gtk_label_set_ellipsize (GTK_LABEL (priv->label), PANGO_ELLIPSIZE_END); + gtk_misc_set_alignment (GTK_MISC (priv->label), 0.0, 0.5); - priv->detail = g_object_ref (gtk_label_new ("")); + priv->detail = g_object_ref (ido_detail_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 (); @@ -77,49 +80,6 @@ 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) { @@ -146,16 +106,28 @@ im_source_menu_item_time_span_string (gint64 timestamp) return str; } +static void +im_source_menu_item_set_detail_time (ImSourceMenuItem *self, + gint64 time) +{ + ImSourceMenuItemPrivate *priv = self->priv; + gchar *str; + + priv->time = time; + + str = im_source_menu_item_time_span_string (priv->time); + ido_detail_label_set_text (IDO_DETAIL_LABEL (priv->detail), str); + + g_free (str); +} + 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); + im_source_menu_item_set_detail_time (self, self->priv->time); - g_free (str); return TRUE; } @@ -167,7 +139,6 @@ im_source_menu_item_set_state (ImSourceMenuItem *self, guint32 count; gint64 time; const gchar *str; - gchar *detail; if (priv->timer_id != 0) { @@ -180,21 +151,15 @@ im_source_menu_item_set_state (ImSourceMenuItem *self, g_variant_get (state, "(ux&sb)", &count, &time, &str, NULL); if (count != 0) - detail = g_strdup_printf ("%d", count); + ido_detail_label_set_count (IDO_DETAIL_LABEL (priv->detail), count); else if (time != 0) { - priv->time = time; - detail = im_source_menu_item_time_span_string (time); + im_source_menu_item_set_detail_time (self, 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 - detail = NULL; - - gtk_label_set_text (GTK_LABEL (priv->detail), detail ? detail : ""); + ido_detail_label_set_text (IDO_DETAIL_LABEL (priv->detail), str); - g_free (detail); return TRUE; } diff --git a/src/indicator-messages-service.c b/src/indicator-messages-service.c index a42a534..7f2ab87 100644 --- a/src/indicator-messages-service.c +++ b/src/indicator-messages-service.c @@ -1,5 +1,5 @@ /* - * Generated by gdbus-codegen 2.33.10. DO NOT EDIT. + * Generated by gdbus-codegen 2.33.12. DO NOT EDIT. * * The license of this code is the same as for the source it was derived from. */ @@ -235,6 +235,17 @@ static const _ExtendedGDBusMethodInfo _indicator_messages_service_method_info_un FALSE }; +static const _ExtendedGDBusArgInfo _indicator_messages_service_method_info_set_status_IN_ARG_desktop_id = +{ + { + -1, + (gchar *) "desktop_id", + (gchar *) "s", + NULL + }, + FALSE +}; + static const _ExtendedGDBusArgInfo _indicator_messages_service_method_info_set_status_IN_ARG_status = { { @@ -248,6 +259,7 @@ static const _ExtendedGDBusArgInfo _indicator_messages_service_method_info_set_s static const _ExtendedGDBusArgInfo * const _indicator_messages_service_method_info_set_status_IN_ARG_pointers[] = { + &_indicator_messages_service_method_info_set_status_IN_ARG_desktop_id, &_indicator_messages_service_method_info_set_status_IN_ARG_status, NULL }; @@ -424,6 +436,7 @@ indicator_messages_service_default_init (IndicatorMessagesServiceIface *iface) * IndicatorMessagesService::handle-set-status: * @object: A #IndicatorMessagesService. * @invocation: A #GDBusMethodInvocation. + * @arg_desktop_id: Argument passed by remote caller. * @arg_status: Argument passed by remote caller. * * Signal emitted when a remote caller is invoking the <link linkend="gdbus-method-com-canonical-indicator-messages-service.SetStatus">SetStatus()</link> D-Bus method. @@ -440,8 +453,8 @@ indicator_messages_service_default_init (IndicatorMessagesServiceIface *iface) NULL, g_cclosure_marshal_generic, G_TYPE_BOOLEAN, - 2, - G_TYPE_DBUS_METHOD_INVOCATION, G_TYPE_STRING); + 3, + G_TYPE_DBUS_METHOD_INVOCATION, G_TYPE_STRING, G_TYPE_STRING); /* GObject signals for received D-Bus signals: */ /** @@ -688,6 +701,7 @@ _out: /** * indicator_messages_service_call_set_status: * @proxy: A #IndicatorMessagesServiceProxy. + * @arg_desktop_id: Argument to pass with the method invocation. * @arg_status: Argument to pass with the method invocation. * @cancellable: (allow-none): A #GCancellable or %NULL. * @callback: A #GAsyncReadyCallback to call when the request is satisfied or %NULL. @@ -702,6 +716,7 @@ _out: void indicator_messages_service_call_set_status ( IndicatorMessagesService *proxy, + const gchar *arg_desktop_id, const gchar *arg_status, GCancellable *cancellable, GAsyncReadyCallback callback, @@ -709,7 +724,8 @@ indicator_messages_service_call_set_status ( { g_dbus_proxy_call (G_DBUS_PROXY (proxy), "SetStatus", - g_variant_new ("(s)", + g_variant_new ("(ss)", + arg_desktop_id, arg_status), G_DBUS_CALL_FLAGS_NONE, -1, @@ -748,6 +764,7 @@ _out: /** * indicator_messages_service_call_set_status_sync: * @proxy: A #IndicatorMessagesServiceProxy. + * @arg_desktop_id: Argument to pass with the method invocation. * @arg_status: Argument to pass with the method invocation. * @cancellable: (allow-none): A #GCancellable or %NULL. * @error: Return location for error or %NULL. @@ -761,6 +778,7 @@ _out: gboolean indicator_messages_service_call_set_status_sync ( IndicatorMessagesService *proxy, + const gchar *arg_desktop_id, const gchar *arg_status, GCancellable *cancellable, GError **error) @@ -768,7 +786,8 @@ indicator_messages_service_call_set_status_sync ( GVariant *_ret; _ret = g_dbus_proxy_call_sync (G_DBUS_PROXY (proxy), "SetStatus", - g_variant_new ("(s)", + g_variant_new ("(ss)", + arg_desktop_id, arg_status), G_DBUS_CALL_FLAGS_NONE, -1, diff --git a/src/indicator-messages-service.h b/src/indicator-messages-service.h index 2adaaf3..2401d0e 100644 --- a/src/indicator-messages-service.h +++ b/src/indicator-messages-service.h @@ -1,5 +1,5 @@ /* - * Generated by gdbus-codegen 2.33.10. DO NOT EDIT. + * Generated by gdbus-codegen 2.33.12. DO NOT EDIT. * * The license of this code is the same as for the source it was derived from. */ @@ -38,6 +38,7 @@ struct _IndicatorMessagesServiceIface gboolean (*handle_set_status) ( IndicatorMessagesService *object, GDBusMethodInvocation *invocation, + const gchar *arg_desktop_id, const gchar *arg_status); gboolean (*handle_unregister_application) ( @@ -120,6 +121,7 @@ gboolean indicator_messages_service_call_unregister_application_sync ( void indicator_messages_service_call_set_status ( IndicatorMessagesService *proxy, + const gchar *arg_desktop_id, const gchar *arg_status, GCancellable *cancellable, GAsyncReadyCallback callback, @@ -132,6 +134,7 @@ gboolean indicator_messages_service_call_set_status_finish ( gboolean indicator_messages_service_call_set_status_sync ( IndicatorMessagesService *proxy, + const gchar *arg_desktop_id, const gchar *arg_status, GCancellable *cancellable, GError **error); diff --git a/src/indicator-messages.c b/src/indicator-messages.c index 942e46f..5c5df31 100644 --- a/src/indicator-messages.c +++ b/src/indicator-messages.c @@ -58,7 +58,6 @@ struct _IndicatorMessages { IndicatorObject parent; IndicatorServiceManager * service; GActionGroup *actions; - GMenu *menu_wrapper; GMenuModel *menu; GtkWidget *image; GtkWidget *gtkmenu; @@ -83,17 +82,19 @@ 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_root_item (IndicatorMessages * self); -static void update_menu (IndicatorMessages *self); static void menu_items_changed (GMenuModel *menu, gint position, gint removed, gint added, gpointer user_data); +static void messages_action_added (GActionGroup *action_group, + gchar *action_name, + gpointer user_data); static void messages_state_changed (GActionGroup *action_group, gchar *action_name, GVariant *value, gpointer user_data); +static void indicator_messages_add_toplevel_menu (IndicatorMessages *self); G_DEFINE_TYPE (IndicatorMessages, indicator_messages, INDICATOR_OBJECT_TYPE); @@ -122,8 +123,7 @@ indicator_messages_init (IndicatorMessages *self) g_signal_connect (self->service, "connection-change", G_CALLBACK (service_connection_changed), self); - self->menu_wrapper = g_menu_new (); - self->gtkmenu = gtk_menu_new_from_model (G_MENU_MODEL (self->menu_wrapper)); + self->gtkmenu = gtk_menu_new (); g_object_ref_sink (self->gtkmenu); self->image = g_object_ref_sink (gtk_image_new ()); @@ -143,7 +143,6 @@ indicator_messages_dispose (GObject *object) g_return_if_fail(self != NULL); g_clear_object (&self->service); - g_clear_object (&self->menu_wrapper); g_clear_object (&self->actions); g_clear_object (&self->menu); g_clear_object (&self->gtkmenu); @@ -178,6 +177,7 @@ static void service_connection_changed (IndicatorServiceManager *sm, GError *error = NULL; if (self->actions != NULL) { + g_signal_handlers_disconnect_by_func (self->actions, messages_action_added, self); g_signal_handlers_disconnect_by_func (self->actions, messages_state_changed, self); g_clear_object (&self->actions); } @@ -185,8 +185,7 @@ static void service_connection_changed (IndicatorServiceManager *sm, 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); + gtk_menu_shell_bind_model (GTK_MENU_SHELL (self->gtkmenu), NULL, NULL, FALSE); if (connected == FALSE) return; @@ -204,6 +203,8 @@ static void service_connection_changed (IndicatorServiceManager *sm, gtk_widget_insert_action_group (self->gtkmenu, get_name_hint (INDICATOR_OBJECT (self)), self->actions); + g_signal_connect (self->actions, "action-added::messages", + G_CALLBACK (messages_action_added), self); g_signal_connect (self->actions, "action-state-changed::messages", G_CALLBACK (messages_state_changed), self); @@ -212,8 +213,10 @@ static void service_connection_changed (IndicatorServiceManager *sm, INDICATOR_MESSAGES_DBUS_OBJECT)); g_signal_connect (self->menu, "items-changed", G_CALLBACK (menu_items_changed), self); - update_root_item (self); - update_menu (self); + if (g_menu_model_get_n_items (self->menu) == 1) + indicator_messages_add_toplevel_menu (self); + else + indicator_object_set_visible (INDICATOR_OBJECT (self), FALSE); g_object_unref (bus); } @@ -261,24 +264,19 @@ indicator_messages_accessible_desc_updated (IndicatorMessages *self) g_list_free (entries); } -static void -update_root_item (IndicatorMessages * self) +static GIcon * +g_menu_model_get_item_attribute_icon (GMenuModel *menu, + gint index, + const gchar *attribute) { gchar *iconstr; + GIcon *icon = NULL; - if (g_menu_model_get_n_items (self->menu) == 0) - return; - - if (g_menu_model_get_item_attribute (self->menu, 0, "x-canonical-icon", "s", &iconstr)) { - GIcon *icon; + if (g_menu_model_get_item_attribute (menu, index, attribute, "s", &iconstr)) { 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 { + if (icon == NULL) { g_warning ("unable to load icon: %s", error->message); g_error_free (error); } @@ -286,37 +284,39 @@ update_root_item (IndicatorMessages * self) g_free (iconstr); } - g_free (self->accessible_desc); - self->accessible_desc = NULL; - - g_menu_model_get_item_attribute (self->menu, 0, "x-canonical-accessible-description", - "s", &self->accessible_desc); - indicator_messages_accessible_desc_updated (self); + return icon; } static void -update_menu (IndicatorMessages *self) +indicator_messages_add_toplevel_menu (IndicatorMessages *self) { + GIcon *icon; GMenuModel *popup; - GMenuItem *item; - if (self->menu == NULL || g_menu_model_get_n_items (self->menu) == 0) - return; + indicator_object_set_visible (INDICATOR_OBJECT (self), TRUE); - popup = g_menu_model_get_item_link (self->menu, 0, G_MENU_LINK_SUBMENU); - if (popup == NULL) - return; + icon = g_menu_model_get_item_attribute_icon (self->menu, 0, "x-canonical-icon"); + if (icon) { + gtk_image_set_from_gicon (GTK_IMAGE (self->image), icon, GTK_ICON_SIZE_LARGE_TOOLBAR); + g_object_unref (icon); + } - if (g_menu_model_get_n_items (G_MENU_MODEL (self->menu_wrapper)) == 1) - g_menu_remove (self->menu_wrapper, 0); + g_free (self->accessible_desc); + self->accessible_desc = NULL; + if (g_menu_model_get_item_attribute (self->menu, 0, "x-canonical-accessible-description", + "s", &self->accessible_desc)) { + indicator_messages_accessible_desc_updated (self); + } - 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); + popup = g_menu_model_get_item_link (self->menu, 0, G_MENU_LINK_SUBMENU); + if (popup) { + gtk_menu_shell_bind_model (GTK_MENU_SHELL (self->gtkmenu), + popup, + get_name_hint (INDICATOR_OBJECT (self)), + TRUE); - g_object_unref (item); - g_object_unref (popup); + g_object_unref (popup); + } } static void @@ -328,13 +328,49 @@ menu_items_changed (GMenuModel *menu, { IndicatorMessages *self = user_data; - if (position == 0) { - update_root_item (self); - update_menu (self); + g_return_if_fail (position == 0); + + if (added == 1) + indicator_messages_add_toplevel_menu (self); + else if (removed == 1) + indicator_object_set_visible (INDICATOR_OBJECT (self), FALSE); +} + +static void +indicator_messages_update_icon (IndicatorMessages *self, + GVariant *state) +{ + GIcon *icon; + GError *error = NULL; + + g_return_if_fail (g_variant_is_of_type (state, G_VARIANT_TYPE_STRING)); + + icon = g_icon_new_for_string (g_variant_get_string (state, NULL), &error); + if (icon == NULL) { + g_warning ("unable to load icon: %s", error->message); + g_error_free (error); + } + else { + gtk_image_set_from_gicon (GTK_IMAGE (self->image), icon, GTK_ICON_SIZE_LARGE_TOOLBAR); + g_object_unref (icon); } } static void +messages_action_added (GActionGroup *action_group, + gchar *action_name, + gpointer user_data) +{ + IndicatorMessages *self = user_data; + GVariant *state; + + state = g_action_group_get_action_state (action_group, "messages"); + indicator_messages_update_icon (self, state); + + g_variant_unref (state); +} + +static void messages_state_changed (GActionGroup *action_group, gchar *action_name, GVariant *value, @@ -342,10 +378,5 @@ messages_state_changed (GActionGroup *action_group, { 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); + indicator_messages_update_icon (self, value); } diff --git a/src/messages-service.c b/src/messages-service.c index 15c5123..b36a0a2 100644 --- a/src/messages-service.c +++ b/src/messages-service.c @@ -35,16 +35,67 @@ with this program. If not, see <http://www.gnu.org/licenses/>. #include "gmenuutils.h" #include "indicator-messages-service.h" +#define NUM_STATUSES 5 + static GHashTable *applications; -IndicatorMessagesService *messages_service; +static IndicatorMessagesService *messages_service; static GSimpleActionGroup *actions; static GActionMuxer *action_muxer; static GMenu *toplevel_menu; static GMenu *menu; static GMenuModel *chat_section; static GSettings *settings; +static gboolean draws_attention; +static const gchar *global_status[6]; /* max 5: available, away, busy, invisible, offline */ + +static gchar * +indicator_messages_get_icon_name () +{ + GString *name; + GIcon *icon; + gchar *iconstr; + + name = g_string_new ("indicator-messages"); + + if (global_status[0] != NULL) + { + if (global_status[1] != NULL) + g_string_append (name, "-mixed"); + else + g_string_append_printf (name, "-%s", global_status[0]); + } + + if (draws_attention) + g_string_append (name, "-new"); + + icon = g_themed_icon_new (name->str); + g_themed_icon_append_name (G_THEMED_ICON (icon), + draws_attention ? "indicator-messages-new" + : "indicator-messages"); + + iconstr = g_icon_to_string (icon); + + g_object_unref (icon); + g_string_free (name, TRUE); + + return iconstr; +} + +static void +indicator_messages_update_icon () +{ + GSimpleAction *messages; + gchar *icon; + messages = G_SIMPLE_ACTION (g_simple_action_group_lookup (actions, "messages")); + g_return_if_fail (messages != NULL); + + icon = indicator_messages_get_icon_name (); + g_simple_action_set_state (messages, g_variant_new_string (icon)); + + g_free (icon); +} static gchar * g_app_info_get_simple_id (GAppInfo *appinfo) @@ -92,18 +143,16 @@ 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 (messages != NULL && clear != NULL); + g_return_if_fail (clear != NULL); + + draws_attention = g_hash_table_find (applications, app_section_draws_attention, NULL) != NULL; - attention = g_hash_table_find (applications, app_section_draws_attention, NULL) != NULL; + g_simple_action_set_enabled (clear, draws_attention); - g_simple_action_set_state (messages, g_variant_new_boolean (attention)); - g_simple_action_set_enabled (clear, attention); + indicator_messages_update_icon (); } static gboolean @@ -116,9 +165,7 @@ app_section_uses_chat (gpointer key, } static void -uses_chat_status_changed (GObject *object, - GParamSpec *pspec, - gpointer user_data) +update_chat_section () { gboolean show_chat; GMenuModel *first_section; @@ -135,7 +182,99 @@ uses_chat_status_changed (GObject *object, g_menu_insert_section (menu, 0, NULL, chat_section); } - g_object_unref (first_section); + if (first_section != NULL) + g_object_unref (first_section); + + indicator_messages_update_icon (); +} + +static void +uses_chat_status_changed (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + update_chat_section (); +} + +static gboolean +strv_contains (const gchar **strv, + const gchar *needle) +{ + const gchar **it; + + it = strv; + while (*it != NULL && !g_str_equal (*it, needle)) + it++; + + return *it != NULL; +} + +static void +update_chat_status () +{ + GHashTableIter iter; + AppSection *section; + int pos; + GAction *status; + + for (pos = 0; pos < G_N_ELEMENTS (global_status); pos++) + global_status[pos] = NULL; + + pos = 0; + g_hash_table_iter_init (&iter, applications); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) §ion) && + pos < G_N_ELEMENTS (global_status)) + { + const gchar *status_str = NULL; + + status_str = app_section_get_status (section); + if (status_str != NULL && !strv_contains (global_status, status_str)) + global_status[pos++] = status_str; + } + + if (pos == 0) + global_status[0] = "offline"; + + status = g_simple_action_group_lookup (actions, "status"); + g_return_if_fail (status != NULL); + + g_simple_action_set_state (G_SIMPLE_ACTION (status), g_variant_new_strv (global_status, -1)); + + indicator_messages_update_icon (); +} + +static void +chat_status_changed (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + update_chat_status (); +} + +static void +remove_section (AppSection *section, + const gchar *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); + + 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); + g_signal_handlers_disconnect_by_func (section, chat_status_changed, NULL); + g_signal_handlers_disconnect_by_func (section, remove_section, NULL); + + g_hash_table_remove (applications, id); + + if (g_hash_table_size (applications) == 0 && + g_menu_model_get_n_items (G_MENU_MODEL (toplevel_menu)) == 1) { + g_menu_remove (toplevel_menu, 0); + } + + update_chat_status (); + update_chat_section (); } static AppSection * @@ -167,6 +306,13 @@ add_application (const gchar *desktop_id) G_CALLBACK (draws_attention_changed), NULL); g_signal_connect (section, "notify::uses-chat-status", G_CALLBACK (uses_chat_status_changed), NULL); + g_signal_connect (section, "notify::chat-status", + G_CALLBACK (chat_status_changed), NULL); + g_signal_connect_data (section, "destroy", + G_CALLBACK (remove_section), + g_strdup (id), + (GClosureNotify) g_free, + 0); /* TODO insert it at the right position (alphabetically by application name) */ menuitem = g_menu_item_new_section (NULL, app_section_get_menu (section)); @@ -175,6 +321,17 @@ add_application (const gchar *desktop_id) g_object_unref (menuitem); } + if (g_menu_model_get_n_items (G_MENU_MODEL (toplevel_menu)) == 0) { + GMenuItem *header; + + header = g_menu_item_new (NULL, "messages"); + g_menu_item_set_submenu (header, G_MENU_MODEL (menu)); + g_menu_item_set_attribute (header, "x-canonical-accessible-description", "s", _("Messages")); + g_menu_append_item (toplevel_menu, header); + + g_object_unref (header); + } + g_free (id); g_object_unref (appinfo); return section; @@ -197,20 +354,12 @@ remove_application (const char *desktop_id) section = g_hash_table_lookup (applications, id); if (section) { - 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); - - 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); + remove_section (section, id); } else { g_warning ("could not remove '%s', it's not registered", desktop_id); } - g_hash_table_remove (applications, id); g_free (id); g_object_unref (appinfo); } @@ -276,48 +425,15 @@ clear_action_activate (GSimpleAction *simple, } static void -radio_item_activate (GSimpleAction *action, - GVariant *parameter, - gpointer user_data) -{ - 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_action (GSimpleAction *action, - GVariant *value, - gpointer user_data) +status_action_activate (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) { const gchar *status; - g_variant_get (value, "&s", &status); + status = g_variant_get_string (parameter, NULL); - 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")); - - if (!g_action_state_equal (G_ACTION (action), value)) { - g_simple_action_set_state (action, value); - indicator_messages_service_emit_status_changed (messages_service, status); - } + indicator_messages_service_emit_status_changed (messages_service, status); } static void @@ -359,17 +475,35 @@ unregister_application (IndicatorMessagesService *service, static void set_status (IndicatorMessagesService *service, GDBusMethodInvocation *invocation, + const gchar *desktop_id, const gchar *status_str, gpointer user_data) { - GAction *status; + GDesktopAppInfo *appinfo; + gchar *id; + AppSection *section; - status = g_simple_action_group_lookup (actions, "status"); - g_return_if_fail (status != NULL); + g_return_if_fail (g_str_equal (status_str, "available") || + g_str_equal (status_str, "away")|| + g_str_equal (status_str, "busy") || + g_str_equal (status_str, "invisible") || + g_str_equal (status_str, "offline")); - g_action_change_state (status, g_variant_new_string (status_str)); + appinfo = g_desktop_app_info_new (desktop_id); + if (!appinfo) { + g_warning ("could not set status for '%s', there's no desktop file with that id", desktop_id); + return; + } + + id = g_app_info_get_simple_id (G_APP_INFO (appinfo)); + section = g_hash_table_lookup (applications, id); + if (section != NULL) + app_section_set_status (section, status_str); indicator_messages_service_complete_set_status (service, invocation); + + g_free (id); + g_object_unref (appinfo); } static GSimpleActionGroup * @@ -379,17 +513,19 @@ create_action_group (void) GSimpleAction *messages; GSimpleAction *clear; GSimpleAction *status; + const gchar *default_status[] = { "offline", NULL }; + gchar *icon; 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)); + /* state of the messages action is its icon name */ + icon = indicator_messages_get_icon_name (); + messages = g_simple_action_new_stateful ("messages", G_VARIANT_TYPE ("s"), + g_variant_new_string (icon)); 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_action), NULL); + g_variant_new_strv (default_status, -1)); + g_signal_connect (status, "activate", G_CALLBACK (status_action_activate), NULL); clear = g_simple_action_new ("clear", NULL); g_simple_action_set_enabled (clear, FALSE); @@ -399,6 +535,7 @@ create_action_group (void) g_simple_action_group_insert (actions, G_ACTION (status)); g_simple_action_group_insert (actions, G_ACTION (clear)); + g_free (icon); return actions; } @@ -484,9 +621,6 @@ main (int argc, char ** argv) { GMainLoop * mainloop = NULL; IndicatorService * service = NULL; - GMenuItem *header; - GIcon *icon; - gchar *iconstr; /* Glib init */ g_type_init(); @@ -524,16 +658,7 @@ 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, "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); settings = g_settings_new ("com.canonical.indicator.messages"); @@ -544,8 +669,6 @@ 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/src/messages-service.xml b/src/messages-service.xml index edd47c7..00ae154 100644 --- a/src/messages-service.xml +++ b/src/messages-service.xml @@ -12,6 +12,7 @@ </method> <method name="SetStatus"> + <arg type="s" name="desktop_id" direction="in" /> <arg type="s" name="status" direction="in" /> </method> diff --git a/test/Makefile.in b/test/Makefile.in index e2866bc..d5078cd 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.11.5 from Makefile.am. +# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, |