ayatana-commits team mailing list archive
-
ayatana-commits team
-
Mailing list archive
-
Message #04134
[Merge] lp:~larsu/indicator-messages/notify-stopped-running into lp:indicator-messages/0.5
Lars Uebernickel has proposed merging lp:~larsu/indicator-messages/notify-stopped-running into lp:indicator-messages/0.5.
Requested reviews:
PS Jenkins bot (ps-jenkins): continuous-integration
Mathieu Trudel-Lapierre (mathieu-tl)
Related bugs:
Bug #1154099 in Messaging Menu: "Applications are not unmarked when MessagingMenuApp is unrefed"
https://bugs.launchpad.net/indicator-messages/+bug/1154099
For more details, see:
https://code.launchpad.net/~larsu/indicator-messages/notify-stopped-running/+merge/168201
--
The attached diff has been truncated due to its size.
https://code.launchpad.net/~larsu/indicator-messages/notify-stopped-running/+merge/168201
Your team ayatana-commits is subscribed to branch lp:indicator-messages/0.5.
=== added directory '.bzr-builddeb'
=== added file '.bzr-builddeb/default.conf'
--- .bzr-builddeb/default.conf 1970-01-01 00:00:00 +0000
+++ .bzr-builddeb/default.conf 2013-06-07 21:39:23 +0000
@@ -0,0 +1,2 @@
+[BUILDDEB]
+split = True
=== modified file '.bzrignore'
--- .bzrignore 2011-07-13 15:41:33 +0000
+++ .bzrignore 2013-06-07 21:39:23 +0000
@@ -1,49 +1,65 @@
-compile
-m4
-po
-src/libmessaging.la
-src/libmessaging_la-indicator-messages.lo
-config.guess.cdbs-orig
-config.sub.cdbs-orig
-debian/compat
-debian/files
-debian/indicator-messages
-debian/indicator-messages.debhelper.log
-debian/indicator-messages.postinst.debhelper
-debian/indicator-messages.postrm.debhelper
-debian/indicator-messages.substvars
-debian/stamp-autotools-files
-debian/stamp-makefile-build
-libmessaging_la-im-menu-item.lo
-src/libmessaging_la-app-menu-item.lo
-data/indicator-messages.service
-indicator-messages-service
-indicator-messages-service-activate
-src/messages-service-client.h
-src/messages-service-server.h
-po/indicator-messages.pot
-src/libmessaging_la-app-gtk-menu-item.lo
-src/gen-messages-service.xml.c
-src/gen-messages-service.xml.h
-src/libemesene.la
-src/libemesene_la-status-provider-emesene.lo
-src/libmc5.la
-src/libmc5_la-status-provider-mc5-marshal.lo
-src/libmc5_la-status-provider-mc5.lo
-src/libmessaging_la-gen-messages-service.xml.lo
-src/libpidgin.la
-src/libpidgin_la-status-provider-pidgin-marshal.lo
-src/libpidgin_la-status-provider-pidgin.lo
-src/libtelepathy.la
-src/libtelepathy_la-status-provider-telepathy-marshal.lo
-src/libtelepathy_la-status-provider-telepathy.lo
-src/status-provider-mc5-marshal.c
-src/status-provider-mc5-marshal.h
-src/status-provider-pidgin-marshal.c
-src/status-provider-pidgin-marshal.h
-src/status-provider-telepathy-marshal.c
-src/status-provider-telepathy-marshal.h
-src/libindicator-messages-status-provider.la
-src/libindicator_messages_status_provider_la-status-provider.lo
-indicator-messages-status-provider-0.5.pc
-indicator-messages-status-provider-0.5.pc.in
+Makefile
+Makefile.in
+Makefile.in.in
+*.o
+*.lo
+*.la
+*.pot
+.deps
+.libs
+*.valid
+stamp-*
+*.gcno
+*.gcda
+*.stamp
+*.gir
+*.typelib
+
+/COPYING
+/INSTALL
+/compile
+/libtool
+/config.*
+/configure
+/aclocal.m4
+/ltmain.sh
+/install-sh
+/missing
+/autom4te.cache
+/depcomp
+/mkinstalldirs
+/coverage.info
+/coveragereport
+/gtk-doc.make
+/indicator-messages-*.tar.gz
+
+/m4/*
+/po/POTFILES
+/data/indicator-messages.service
+/src/indicator-messages-service
+/src/indicator-messages-service.c
+/src/indicator-messages-service.h
+
+/libmessaging-menu/messaging-menu.pc
+/libmessaging-menu/indicator-messages-service.c
+/libmessaging-menu/indicator-messages-service.h
+
+/doc/reference/html
+/doc/reference/xml
+/doc/reference/messaging-menu-decl-list.txt
+/doc/reference/messaging-menu-decl.txt
+/doc/reference/messaging-menu-docs.sgml
+/doc/reference/messaging-menu-docs.xml
+/doc/reference/messaging-menu-overrides.txt
+/doc/reference/messaging-menu-sections.txt
+/doc/reference/messaging-menu-undeclared.txt
+/doc/reference/messaging-menu-undocumented.txt
+/doc/reference/messaging-menu-unused.txt
+/doc/reference/messaging-menu.args
+/doc/reference/messaging-menu.hierarchy
+/doc/reference/messaging-menu.interfaces
+/doc/reference/messaging-menu.prerequisites
+/doc/reference/messaging-menu.signals
+/doc/reference/messaging-menu.types
+
+/test/test-gactionmuxer
=== modified file 'Makefile.am'
--- Makefile.am 2010-10-08 22:13:11 +0000
+++ Makefile.am 2013-06-07 21:39:23 +0000
@@ -1,10 +1,27 @@
SUBDIRS = \
src \
+ libmessaging-menu \
data \
po
-DISTCHECK_CONFIGURE_FLAGS = --enable-localinstall --enable-deprecations
+if ENABLE_GTK_DOC
+SUBDIRS += doc
+endif
+
+if BUILD_TESTS
+SUBDIRS += \
+ test
+
+# build src first
+test: src
+
+endif
+
+
+
+
+DISTCHECK_CONFIGURE_FLAGS = --enable-localinstall --enable-deprecations --enable-introspection --enable-gtk-doc
dist-hook:
@if test -d "$(top_srcdir)/.bzr"; \
@@ -31,3 +48,6 @@
else \
echo Failed to generate AUTHORS: not a branch >&2; \
fi
+
+
+include $(top_srcdir)/Makefile.am.coverage
=== added file 'Makefile.am.coverage'
--- Makefile.am.coverage 1970-01-01 00:00:00 +0000
+++ Makefile.am.coverage 2013-06-07 21:39:23 +0000
@@ -0,0 +1,48 @@
+
+# Coverage targets
+
+.PHONY: clean-gcno clean-gcda \
+ coverage-html generate-coverage-html clean-coverage-html \
+ coverage-gcovr generate-coverage-gcovr clean-coverage-gcovr
+
+clean-local: clean-gcno clean-coverage-html clean-coverage-gcovr
+
+if HAVE_GCOV
+
+clean-gcno:
+ @echo Removing old coverage instrumentation
+ -find -name '*.gcno' -print | xargs -r rm
+
+clean-gcda:
+ @echo Removing old coverage results
+ -find -name '*.gcda' -print | xargs -r rm
+
+coverage-html: clean-gcda
+ -$(MAKE) $(AM_MAKEFLAGS) -k check
+ $(MAKE) $(AM_MAKEFLAGS) generate-coverage-html
+
+generate-coverage-html:
+ @echo Collecting coverage data
+ $(LCOV) --directory $(top_builddir) --capture --output-file coverage.info --no-checksum --compat-libtool
+ LANG=C $(GENHTML) --prefix $(top_builddir) --output-directory coveragereport --title "Code Coverage" --legend --show-details coverage.info
+
+clean-coverage-html: clean-gcda
+ -$(LCOV) --directory $(top_builddir) -z
+ -rm -rf coverage.info coveragereport
+
+if HAVE_GCOVR
+
+coverage-gcovr: clean-gcda
+ -$(MAKE) $(AM_MAKEFLAGS) -k check
+ $(MAKE) $(AM_MAKEFLAGS) generate-coverage-gcovr
+
+generate-coverage-gcovr:
+ @echo Generating coverage GCOVR report
+ $(GCOVR) -x -r $(top_builddir) -o $(top_builddir)/coverage.xml
+
+clean-coverage-gcovr: clean-gcda
+ -rm -rf $(top_builddir)/coverage.xml
+
+endif # HAVE_GCOVR
+
+endif # HAVE_GCOV
=== modified file 'NEWS'
--- NEWS 2008-12-05 03:13:41 +0000
+++ NEWS 2013-06-07 21:39:23 +0000
@@ -0,0 +1,42 @@
+
+12.10.5
+
+* fix crash caused by GError not being cleared (lp #1064314)
+* fix crash when registering an app that was previously unregistered (lp #1065169)
+* remove the icon if NULL is passed to source_set_icon (lp #1070421)
+* call gtk-update-icon-cache (lp #1060618)
+
+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:
+ - expand source documentation and add gtk-doc to the build system
+ - added new API: messaging_menu_app_set_source_{label,icon}
+ - fix bug: only one MessagingMenuApp was exported to the messaging menu
+
+
+12.10.1
+
+* presence icons are shown again
+* the icon is changed when a source draws attention
+* the time in source menu items is always kep current
+* fixed all g-ir-scanner warnings
+* libmessaging-menu now removes sources when they are activated
+* fixed several bugs
=== modified file 'autogen.sh'
--- autogen.sh 2009-04-05 11:03:12 +0000
+++ autogen.sh 2013-06-07 21:39:23 +0000
@@ -1,11 +1,5 @@
-#!/bin/sh
-
-PKG_NAME="indicator-messages"
-
-which gnome-autogen.sh || {
- echo "You need gnome-common from GNOME SVN"
- exit 1
-}
-
-USE_GNOME2_MACROS=1 \
-. gnome-autogen.sh
+#!/bin/sh -e
+
+gtkdocize
+autoreconf -i -f
+intltoolize
=== modified file 'configure.ac'
--- configure.ac 2011-09-28 15:33:24 +0000
+++ configure.ac 2013-06-07 21:39:23 +0000
@@ -1,10 +1,10 @@
-AC_INIT(src/indicator-messages.c)
+AC_INIT(indicator-messages, 12.10.5)
-AC_PREREQ(2.53)
+AC_PREREQ(2.62)
AM_CONFIG_HEADER(config.h)
-AM_INIT_AUTOMAKE(indicator-messages, 0.5.0)
+AM_INIT_AUTOMAKE([check-news])
AM_MAINTAINER_MODE
@@ -31,64 +31,73 @@
[CFLAGS="$CFLAGS -DG_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED -DGDK_PIXBUF_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED -DGSEAL_ENABLE -DGTK_DISABLE_SINGLE_INCLUDES"]
)
+# the Google Test targets are cpp
+AC_PROG_CXX
+
###########################
# Dependencies
###########################
-GTK_REQUIRED_VERSION=2.12
-GTK3_REQUIRED_VERSION=3.0
-GIO_UNIX_REQUIRED_VERSION=2.18
-PANEL_REQUIRED_VERSION=2.0.0
-INDICATE_REQUIRED_VERSION=0.4.90
+GTK_REQUIRED_VERSION=3.5.18
+GIO_UNIX_REQUIRED_VERSION=2.33.10
INDICATOR_REQUIRED_VERSION=0.3.19
-DBUSMENUGTK_REQUIRED_VERSION=0.3.94
-
-AC_ARG_WITH([gtk],
- [AS_HELP_STRING([--with-gtk],
- [Which version of gtk to use for the indicator @<:@default=3@:>@])],
- [],
- [with_gtk=3])
-
-AS_IF([test "x$with_gtk" = x3],
- [PKG_CHECK_MODULES(APPLET, gtk+-3.0 >= $GTK3_REQUIRED_VERSION
- gio-unix-2.0 >= $GIO_UNIX_REQUIRED_VERSION
- indicator3-0.4 >= $INDICATOR_REQUIRED_VERSION
- indicate-0.6 >= $INDICATE_REQUIRED_VERSION
- dbusmenu-gtk3-0.4 >= $DBUSMENUGTK_REQUIRED_VERSION)
- ],
- [test "x$with_gtk" = x2],
- [PKG_CHECK_MODULES(APPLET, gtk+-2.0 >= $GTK_REQUIRED_VERSION
- gio-unix-2.0 >= $GIO_UNIX_REQUIRED_VERSION
- indicator-0.4 >= $INDICATOR_REQUIRED_VERSION
- indicate-0.6 >= $INDICATE_REQUIRED_VERSION
- dbusmenu-gtk-0.4 >= $DBUSMENUGTK_REQUIRED_VERSION)
- ],
- [AC_MSG_FAILURE([Value for --with-indicator-gtk was neither 2 nor 3])]
-)
+GLIB_REQUIRED_VERSION=2.35.4
+INTROSPECTION_REQUIRED_VERSION=1.32.0
+
+PKG_CHECK_MODULES(APPLET, gtk+-3.0 >= $GTK_REQUIRED_VERSION
+ gio-unix-2.0 >= $GIO_UNIX_REQUIRED_VERSION
+ indicator3-0.4 >= $INDICATOR_REQUIRED_VERSION
+ glib-2.0 >= $GLIB_REQUIRED_VERSION
+ gmodule-2.0 >= $GLIB_REQUIRED_VERSION)
+
+PKG_CHECK_MODULES(GIO, gio-unix-2.0 >= $GIO_UNIX_REQUIRED_VERSION)
+
AC_SUBST(APPLET_CFLAGS)
AC_SUBST(APPLET_LIBS)
-###########################
-# Status Provider Deps
-###########################
-
-PKG_CHECK_MODULES(STATUS_PROVIDER_PIDGIN, dbus-glib-1)
-AC_SUBST(STATUS_PROVIDER_PIDGIN_CFLAGS)
-AC_SUBST(STATUS_PROVIDER_PIDGIN_LIBS)
-
-PKG_CHECK_MODULES(STATUS_PROVIDER_TELEPATHY, dbus-glib-1)
-AC_SUBST(STATUS_PROVIDER_TELEPATHY_CFLAGS)
-AC_SUBST(STATUS_PROVIDER_TELEPATHY_LIBS)
-
-TELEPATHYGLIB_REQUIRED_VERSION=0.9.0
-PKG_CHECK_MODULES(STATUS_PROVIDER_MC5, dbus-glib-1
- telepathy-glib >= $TELEPATHYGLIB_REQUIRED_VERSION)
-AC_SUBST(STATUS_PROVIDER_MC5_CFLAGS)
-AC_SUBST(STATUS_PROVIDER_MC5_LIBS)
-
-PKG_CHECK_MODULES(STATUS_PROVIDER_EMESENE, dbus-glib-1)
-AC_SUBST(STATUS_PROVIDER_EMESENE_CFLAGS)
-AC_SUBST(STATUS_PROVIDER_EMESENE_LIBS)
+GLIB_GSETTINGS
+
+GTK_DOC_CHECK([1.18], [--flavour no-tmpl])
+
+GOBJECT_INTROSPECTION_CHECK([$INTROSPECTION_REQUIRED_VERSION])
+
+###########################
+# gcov coverage reporting
+###########################
+
+m4_include([m4/gcov.m4])
+AC_TDD_GCOV
+AM_CONDITIONAL([HAVE_GCOV], [test "x$ac_cv_check_gcov" = xyes])
+AM_CONDITIONAL([HAVE_LCOV], [test "x$ac_cv_check_lcov" = xyes])
+AM_CONDITIONAL([HAVE_GCOVR], [test "x$ac_cv_check_gcovr" = xyes])
+AC_SUBST(COVERAGE_CFLAGS)
+AC_SUBST(COVERAGE_CXXFLAGS)
+AC_SUBST(COVERAGE_LDFLAGS)
+
+###########################
+# Tests
+###########################
+
+AC_ARG_ENABLE([tests],
+ [AS_HELP_STRING([--disable-tests], [Disable test scripts and tools (default=auto)])],
+ [enable_tests=${enableval}],
+ [enable_tests=auto])
+if test "x$enable_tests" != "xno"; then
+ m4_include([m4/gtest.m4])
+ CHECK_GTEST
+ AM_PATH_PYTHON(3.0,, [:])
+ AC_PYTHON_MODULE(dbusmock)
+ if test "x$have_gtest" = "xyes" -a "x$HAVE_PYMOD_DBUSMOCK" = "xyes"; then
+ enable_tests="yes"
+ else
+ if test "x$enable_tests" = "xyes"; then
+ AC_MSG_ERROR([tests were requested but gtest or dbusmock are not installed.])
+ else
+ enable_tests="no"
+ fi
+ fi
+fi
+AM_CONDITIONAL([BUILD_TESTS],[test "x$enable_tests" = "xyes"])
###########################
# Check to see if we're local
@@ -103,16 +112,10 @@
if test "x$with_localinstall" = "xyes"; then
INDICATORDIR="${libdir}/indicators/2/"
- INDICATORICONSDIR="${datadir}/libindicate/icons/"
-elif test "x$with_gtk" = x2; then
- INDICATORDIR=`$PKG_CONFIG --variable=indicatordir indicator-0.4`
- INDICATORICONSDIR=`$PKG_CONFIG --variable=iconsdir indicator-0.4`
else
INDICATORDIR=`$PKG_CONFIG --variable=indicatordir indicator3-0.4`
- INDICATORICONSDIR=`$PKG_CONFIG --variable=iconsdir indicator3-0.4`
fi
AC_SUBST(INDICATORDIR)
-AC_SUBST(INDICATORICONSDIR)
###########################
# DBus Service Info
@@ -159,7 +162,6 @@
AC_OUTPUT([
Makefile
src/Makefile
-src/indicator-messages-status-provider-0.5.pc.in
data/Makefile
data/icons/Makefile
data/icons/16x16/Makefile
@@ -179,6 +181,12 @@
data/icons/scalable/status/Makefile
data/icons/scalable/categories/Makefile
po/Makefile.in
+test/Makefile
+libmessaging-menu/Makefile
+libmessaging-menu/messaging-menu.pc
+doc/Makefile
+doc/reference/Makefile
+doc/reference/messaging-menu-docs.xml
])
###########################
@@ -191,4 +199,8 @@
Prefix: $prefix
Indicator Dir: $INDICATORDIR
+ tests: $enable_tests
+ gcov: $use_gcov
+ introspecion: $enable_introspection
+ documentation: $enable_gtk_doc
])
=== modified file 'data/Makefile.am'
--- data/Makefile.am 2009-09-09 18:58:33 +0000
+++ data/Makefile.am 2013-06-07 21:39:23 +0000
@@ -6,6 +6,11 @@
%.service: %.service.in
sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@
-EXTRA_DIST = indicator-messages.service.in
+gsettings_SCHEMAS = com.canonical.indicator.messages.gschema.xml
+@GSETTINGS_RULES@
+
+EXTRA_DIST = \
+ $(gsettings_SCHEMAS) \
+ indicator-messages.service.in
CLEANFILES = indicator-messages.service
=== added file 'data/com.canonical.indicator.messages.gschema.xml'
--- data/com.canonical.indicator.messages.gschema.xml 1970-01-01 00:00:00 +0000
+++ data/com.canonical.indicator.messages.gschema.xml 2013-06-07 21:39:23 +0000
@@ -0,0 +1,12 @@
+<schemalist>
+ <schema id="com.canonical.indicator.messages" path="/com/canonical/indicator/messages/" gettext-domain="indicator-messages">
+ <key name="applications" type="as">
+ <summary>List of applications that are shown in the messaging menu</summary>
+ <description>
+ Applications corresponding to the desktop file ids in this list are shown in the messaging menu.
+ </description>
+ <default>[]</default>
+ </key>
+ </schema>
+</schemalist>
+
=== modified file 'data/icons/16x16/categories/Makefile.am'
--- data/icons/16x16/categories/Makefile.am 2010-03-04 20:23:07 +0000
+++ data/icons/16x16/categories/Makefile.am 2013-06-07 21:39:23 +0000
@@ -1,5 +1,5 @@
-iconsdir = $(INDICATORICONSDIR)/hicolor/16x16/categories
+iconsdir = $(datadir)/icons/hicolor/16x16/categories
icons_DATA = \
applications-email-panel.png \
=== modified file 'data/icons/16x16/status/Makefile.am'
--- data/icons/16x16/status/Makefile.am 2010-02-18 04:59:43 +0000
+++ data/icons/16x16/status/Makefile.am 2013-06-07 21:39:23 +0000
@@ -1,5 +1,5 @@
-iconsdir = $(INDICATORICONSDIR)/hicolor/16x16/status
+iconsdir = $(datadir)/icons/hicolor/16x16/status
icons_DATA = \
application-running.png \
=== modified file 'data/icons/22x22/categories/Makefile.am'
--- data/icons/22x22/categories/Makefile.am 2010-03-04 20:23:07 +0000
+++ data/icons/22x22/categories/Makefile.am 2013-06-07 21:39:23 +0000
@@ -1,5 +1,5 @@
-iconsdir = $(INDICATORICONSDIR)/hicolor/22x22/categories
+iconsdir = $(datadir)/icons/hicolor/22x22/categories
icons_DATA = \
applications-email-panel.png
=== modified file 'data/icons/22x22/status/Makefile.am'
--- data/icons/22x22/status/Makefile.am 2009-09-25 01:28:38 +0000
+++ data/icons/22x22/status/Makefile.am 2013-06-07 21:39:23 +0000
@@ -1,5 +1,5 @@
-iconsdir = $(INDICATORICONSDIR)/hicolor/22x22/status
+iconsdir = $(datadir)/icons/hicolor/22x22/status
icons_DATA = \
indicator-messages.png \
=== modified file 'data/icons/24x24/status/Makefile.am'
--- data/icons/24x24/status/Makefile.am 2010-02-18 04:59:43 +0000
+++ data/icons/24x24/status/Makefile.am 2013-06-07 21:39:23 +0000
@@ -1,5 +1,5 @@
-iconsdir = $(INDICATORICONSDIR)/hicolor/24x24/status
+iconsdir = $(datadir)/icons/hicolor/24x24/status
icons_DATA = \
application-running.png \
=== modified file 'data/icons/32x32/categories/Makefile.am'
--- data/icons/32x32/categories/Makefile.am 2010-03-04 20:23:07 +0000
+++ data/icons/32x32/categories/Makefile.am 2013-06-07 21:39:23 +0000
@@ -1,5 +1,5 @@
-iconsdir = $(INDICATORICONSDIR)/hicolor/32x32/categories
+iconsdir = $(datadir)/icons/hicolor/32x32/categories
icons_DATA = \
applications-email-panel.png \
=== modified file 'data/icons/32x32/status/Makefile.am'
--- data/icons/32x32/status/Makefile.am 2010-02-18 04:59:43 +0000
+++ data/icons/32x32/status/Makefile.am 2013-06-07 21:39:23 +0000
@@ -1,5 +1,5 @@
-iconsdir = $(INDICATORICONSDIR)/hicolor/32x32/status
+iconsdir = $(datadir)/icons/hicolor/32x32/status
icons_DATA = \
application-running.png \
=== modified file 'data/icons/48x48/status/Makefile.am'
--- data/icons/48x48/status/Makefile.am 2010-02-18 04:59:43 +0000
+++ data/icons/48x48/status/Makefile.am 2013-06-07 21:39:23 +0000
@@ -1,5 +1,5 @@
-iconsdir = $(INDICATORICONSDIR)/hicolor/48x48/status
+iconsdir = $(datadir)/icons/hicolor/48x48/status
icons_DATA = \
application-running.png \
=== modified file 'data/icons/Makefile.am'
--- data/icons/Makefile.am 2009-02-04 16:01:51 +0000
+++ data/icons/Makefile.am 2013-06-07 21:39:23 +0000
@@ -1,6 +1,6 @@
SUBDIRS = scalable 16x16 22x22 24x24 32x32 48x48
-gtk_update_icon_cache = gtk-update-icon-cache -f -t $(pkgdatadir)/icons/hicolor
+gtk_update_icon_cache = gtk-update-icon-cache -f -t $(datadir)/icons/hicolor
install-data-hook: update-icon-cache
uninstall-hook: update-icon-cache
=== modified file 'data/icons/scalable/categories/Makefile.am'
--- data/icons/scalable/categories/Makefile.am 2010-03-04 20:23:07 +0000
+++ data/icons/scalable/categories/Makefile.am 2013-06-07 21:39:23 +0000
@@ -1,5 +1,5 @@
-iconsdir = $(INDICATORICONSDIR)/hicolor/scalable/categories
+iconsdir = $(datadir)/icons/hicolor/scalable/categories
icons_DATA = \
applications-email-panel.svg \
=== modified file 'data/icons/scalable/status/Makefile.am'
--- data/icons/scalable/status/Makefile.am 2010-02-18 04:59:43 +0000
+++ data/icons/scalable/status/Makefile.am 2013-06-07 21:39:23 +0000
@@ -1,5 +1,5 @@
-iconsdir = $(INDICATORICONSDIR)/hicolor/scalable/status
+iconsdir = $(datadir)/icons/hicolor/scalable/status
icons_DATA = \
application-running.svg \
=== added directory 'debian'
=== added file 'debian/changelog'
--- debian/changelog 1970-01-01 00:00:00 +0000
+++ debian/changelog 2013-06-07 21:39:23 +0000
@@ -0,0 +1,856 @@
+indicator-messages (12.10.6daily13.01.25-0ubuntu1) raring; urgency=low
+
+ [ Charles Kerr ]
+ * indicators call deprecated glib function g_type_init() (LP:
+ #1103087)
+
+ [ Automatic PS uploader ]
+ * Automatic snapshot from revision 335
+
+ -- Automatic PS uploader <ps-jenkins@xxxxxxxxxxxxxxxxxxx> Fri, 25 Jan 2013 02:01:11 +0000
+
+indicator-messages (12.10.6daily12.11.22-0ubuntu1) raring; urgency=low
+
+ [ Lars Uebernickel ]
+ * Crash in g_variant_valist_get_leaf when highlighted (LP: #1081754)
+
+ [ Automatic PS uploader ]
+ * Automatic snapshot from revision 333
+
+ -- Automatic PS uploader <ps-jenkins@xxxxxxxxxxxxxxxxxxx> Thu, 22 Nov 2012 10:02:35 +0000
+
+indicator-messages (12.10.6daily12.11.21.1-0ubuntu1) raring; urgency=low
+
+ [ Mathieu Trudel-Lapierre ]
+ * debian/rules:
+ - Use autogen.sh for dh_autoreconf.
+ - Drop the override for dh_makeshlibs.
+ - Add DPKG_GENSYMBOLS_CHECK_LEVEL=4.
+ * debian/control:
+ - Fix styling: add trailing commas at the end of lists.
+ - Update Vcs-Bzr, Vcs-Browser fields and add a notice for developers.
+ - Add libgtest-dev to Build-Depends.
+ * Automatic snapshot from revision 329 (bootstrap):
+ - Clear the detail (count or time) of a source when another type of detail
+ is set. (LP: #1071640)
+
+ [ Automatic PS uploader ]
+ * Automatic snapshot from revision 331
+
+ -- Automatic PS uploader <ps-jenkins@xxxxxxxxxxxxxxxxxxx> Wed, 21 Nov 2012 10:41:37 +0000
+
+indicator-messages (12.10.5-0ubuntu2) raring; urgency=low
+
+ * Upload to raring
+
+ -- Sebastien Bacher <seb128@xxxxxxxxxx> Wed, 07 Nov 2012 15:16:08 +0100
+
+indicator-messages (12.10.5-0ubuntu1) quantal-proposed; urgency=low
+
+ * New upstream release:
+ - fix crash caused by GError not being cleared (lp #1064314)
+ - fix crash when registering an app that was previously unregistered
+ (lp #1065169)
+ - remove the icon if NULL is passed to source_set_icon (lp #1070421)
+
+ -- Sebastien Bacher <seb128@xxxxxxxxxx> Wed, 24 Oct 2012 17:30:45 +0200
+
+indicator-messages (12.10.4-0ubuntu1) quantal; urgency=low
+
+ * New upstream release:
+ - don't segfault if .desktop file is not installed (lp: #1058386)
+ - Use fallback icon names (without status emblems).
+ (lp: #1056595)
+
+ -- Sebastien Bacher <seb128@xxxxxxxxxx> Tue, 02 Oct 2012 23:20:19 +0200
+
+indicator-messages (12.10.2-0ubuntu1) quantal; urgency=low
+
+ * New upstream release, includes apis to allow changing the label and
+ the icon of sources and add documentation
+ * debian/libmessaging-menu0.symbols:
+ - new version update
+ * debian/libmessaging-menu-dev.install:
+ - install the documentation
+ * debian/rules:
+ - build the documentation
+ - updated shlibs version
+ - use --with gir so gir:Depends work as it should
+ (lp: #1044125)
+
+ -- Sebastien Bacher <seb128@xxxxxxxxxx> Sat, 01 Sep 2012 12:36:35 +0200
+
+indicator-messages (12.10.1-0ubuntu1) quantal-proposed; urgency=low
+
+ * New upstream version
+ * debian/control:
+ - breaks on version of ported clients using libindicate
+ - set some conflicts on the old deprecated status provider binaries
+ - updated Build-Depends
+ * debian/control, debian/*.install:
+ - drop indicator-status-provider-*, those are deprecated
+ - new binaries for the libmessaging-menu library
+ * debian/libmessaging-menu0.symbols:
+ - symbol file for the new library
+ * Updated packaging to dh9, current standards
+ * Drop gtk2 build from the packaging since support for it was
+ dropped in trunk, thanks Lars Uebernickel
+
+ -- Sebastien Bacher <seb128@xxxxxxxxxx> Mon, 27 Aug 2012 18:56:59 +0200
+
+indicator-messages (0.6.0-0ubuntu1) precise; urgency=low
+
+ * New upstream release.
+ * Handle blank icons properly (LP: #956147)
+ * Fix telepathy offline/disconnected state bug
+
+ -- Charles Kerr <charles.kerr@xxxxxxxxxxxxx> Wed, 11 Apr 2012 11:09:46 -0500
+
+indicator-messages (0.5.95-0ubuntu1) precise; urgency=low
+
+ [ Charles Kerr ]
+ * New upstream release.
+ * Fix 0.5.94 blacklist regression.
+
+ [ Ken VanDine ]
+ * src/indicator-messages.c
+ * revert fix for the broken images in indicator-messages-service, it
+ caused the service to build against gtk and we can't parallel install
+ the service anyway
+
+ -- Ken VanDine <ken.vandine@xxxxxxxxxxxxx> Thu, 05 Apr 2012 16:47:19 -0400
+
+indicator-messages (0.5.94-0ubuntu1) precise; urgency=low
+
+ [ Ted Gould ]
+ * New upstream release.
+ * Fix for missing icons in the messaging menu (LP: #960553)
+ * Fix i18n for description (LP: #957525)
+ * Implementing initial testing
+ * Fixing blacklists (LP: #939258)
+ * debian/control: Adding dep on libgtest-dev
+
+ [ Ken VanDine ]
+ * debian/control: Don't build depend on libgtest-dev, it isn't in main
+ * debian/rules: disable tests, they require libgtest-dev
+
+ -- Ken VanDine <ken.vandine@xxxxxxxxxxxxx> Wed, 21 Mar 2012 17:00:10 -0400
+
+indicator-messages (0.5.93-0ubuntu2) precise; urgency=low
+
+ * src/im-menu-item.c
+ - cherry picked fix for missing icons in the messaging menu (LP: #960553)
+
+ -- Ken VanDine <ken.vandine@xxxxxxxxxxxxx> Tue, 20 Mar 2012 16:41:13 -0400
+
+indicator-messages (0.5.93-0ubuntu1) precise; urgency=low
+
+ * debian/control:
+ - drop build-depends on gnome-doc-utils and scrollkeeper, not required
+
+ [ Ted Gould ]
+ * New upstream release.
+ * Fixing alignment of menu items (LP: #939953)
+ * Vertically centering alignment of double high items (LP: #770486)
+ * Fixing setting of status on telepathy (LP: #943757)
+
+ -- Sebastien Bacher <seb128@xxxxxxxxxx> Thu, 08 Mar 2012 22:11:24 +0100
+
+indicator-messages (0.5.92-0ubuntu1) precise; urgency=low
+
+ [ Ted Gould ]
+ * New upstream release.
+ * Fix goto handling (by removing) (LP: #937441, LP: #937438)
+ * Tell accountsservice when user has messages for the benefit of
+ LightDM.
+ * Dropping debian/patches: Merged upstream
+
+ [ Ken VanDine ]
+ * debian/source/format
+ - dropped "3.0 (quilt), it doesn't play well with bzr maintained packages
+
+ -- Ken VanDine <ken.vandine@xxxxxxxxxxxxx> Thu, 23 Feb 2012 02:48:09 -0500
+
+indicator-messages (0.5.91-0ubuntu3) precise; urgency=low
+
+ * debian/source/format:
+ - Make "3.0 (quilt)"
+ * debian/patches/tell-accounts-service.patch:
+ - Tell accountsservice when user has messages for the benefit of
+ LightDM.
+
+ -- Michael Terry <mterry@xxxxxxxxxx> Wed, 15 Feb 2012 15:32:16 -0500
+
+indicator-messages (0.5.91-0ubuntu2) precise; urgency=low
+
+ * debian/control: build-depends on dh-autoreconf as well
+
+ -- Sebastien Bacher <seb128@xxxxxxxxxx> Tue, 14 Feb 2012 23:50:15 +0100
+
+indicator-messages (0.5.91-0ubuntu1) precise; urgency=low
+
+ * New upstream release.
+ * Better lozenges that look nice
+ * debian/rules: Adding autoreconf and running make check
+ * debian/compat: 5
+ * debian/source/format: Dropping
+
+ -- Ted Gould <ted@xxxxxxxxxx> Tue, 14 Feb 2012 15:29:52 -0600
+
+indicator-messages (0.5.90-0ubuntu1) precise; urgency=low
+
+ [ Ted Gould ]
+ * New upstream release.
+ * Adding code coverage targets
+ * Match libindicate 0.6.90
+ * Updating for Dbusmenu 0.5.90
+ * Plug leak in launcher_menu_item_new
+ * Fix memory leak: Free path string.
+ * Compare server and path for multi-server clients
+ * Using the new GTK3 box API to avoid deprecations
+ * Adding a name hint
+ * debian/control: Requiring libindicate 0.6.90 and dbusmenu 0.5.90
+
+ [ Ken VanDine ]
+ * debian/rules
+ - drop no-error=deprecated-declarations from CFLAGS
+
+ -- Ken VanDine <ken.vandine@xxxxxxxxxxxxx> Fri, 10 Feb 2012 14:29:59 -0500
+
+indicator-messages (0.5.0-1ubuntu1) precise; urgency=low
+
+ * rebuild for libindicator7
+ * debian/rules
+ - build with no-error=deprecated-declarations
+ * debian/control
+ - set ubuntu-desktop VCS and maintainer
+
+ -- Ken VanDine <ken.vandine@xxxxxxxxxxxxx> Wed, 25 Jan 2012 09:56:59 -0500
+
+indicator-messages (0.5.0-1) experimental; urgency=low
+
+ * Merge new upstream from Ubuntu.
+
+ -- Evgeni Golov <evgeni@xxxxxxxxxx> Wed, 19 Oct 2011 13:36:00 +0200
+
+indicator-messages (0.5.0-0ubuntu1) oneiric; urgency=low
+
+ * New upstream release.
+ * Fix memory leak (LP: #690668)
+ * Drop debian/patches/lp_690668.patch: Merged upstream
+
+ -- Ted Gould <ted@xxxxxxxxxx> Wed, 28 Sep 2011 10:39:26 -0500
+
+indicator-messages (0.4.95-0ubuntu1) oneiric; urgency=low
+
+ * New upstream release.
+ * Fix naming of "Clear" item
+ * Fix alignment of items to there is a consistent gutter
+ * debian/patches/lp_690668.patch: Updating
+
+ -- Ted Gould <ted@xxxxxxxxxx> Thu, 25 Aug 2011 09:09:20 -0500
+
+indicator-messages (0.4.94-0ubuntu1) oneiric; urgency=low
+
+ * New upstream release.
+ ∘ Fix drawing of triangles and capsules in GTK3
+ ∘ Fix Emesene statuses (LP: #817504)
+
+ -- Ted Gould <ted@xxxxxxxxxx> Thu, 18 Aug 2011 10:57:40 -0500
+
+indicator-messages (0.4.93-0ubuntu2) oneiric; urgency=low
+
+ * debian/rules
+ - run intltool-update to update the translations template
+
+ -- Ken VanDine <ken.vandine@xxxxxxxxxxxxx> Fri, 12 Aug 2011 10:05:01 -0400
+
+indicator-messages (0.4.93-0ubuntu1) oneiric; urgency=low
+
+ [ Ted Gould ]
+ * New upstream release.
+ * Add an item to clear the alert
+ * Choose mail applications based on the default application
+ * Clear based on middle click
+
+ [ Ken VanDine ]
+ * debian/control
+ - Bumped build depends for libindicate to >= 0.5.90
+ * debian/rules
+ - Fixed configure arg for gtk version
+
+ -- Ken VanDine <ken.vandine@xxxxxxxxxxxxx> Thu, 11 Aug 2011 14:18:05 -0400
+
+indicator-messages (0.4.92-0ubuntu4) oneiric; urgency=low
+
+ * debian/control
+ - Dropped recommends for gwibber now that it is seeded
+ * cherry picked r220 from trunk
+ - Make sure to insert in the right locations
+ * cherry picked r221 from trunk
+ - Making mail applications based on the default mail client not a
+ hardcoded desktop file.
+
+ -- Ken VanDine <ken.vandine@xxxxxxxxxxxxx> Fri, 05 Aug 2011 14:33:39 -0400
+
+indicator-messages (0.4.92-0ubuntu3) oneiric; urgency=low
+
+ * debian/control
+ - Added recommends for gwibber, it got missed when we dropped indicator-me
+ should get removed after we get it seeded properly
+
+ -- Ken VanDine <ken.vandine@xxxxxxxxxxxxx> Sun, 31 Jul 2011 16:36:09 -0400
+
+indicator-messages (0.4.92-0ubuntu2) oneiric; urgency=low
+
+ * debian/control:
+ - use conflicts against indicator-me
+
+ -- Michael Vogt <michael.vogt@xxxxxxxxxx> Fri, 29 Jul 2011 15:49:40 +0200
+
+indicator-messages (0.4.92-0ubuntu1) oneiric; urgency=low
+
+ * New upstream release.
+ * debian/control
+ - Added Replaces indicator-me
+ - Added build depends for libtelepathy-glib-dev
+ - Added new binary packages, libindicator-messages-status-provider-dev,
+ libindicator-messages-status-provider1, and each provider
+ - Make indicator-messages recommend indicator-status-provider-mc5
+ * debian/libindicator-messages-status-provider1.symbols
+ - Added symbols file
+
+ -- Ken VanDine <ken.vandine@xxxxxxxxxxxxx> Thu, 14 Jul 2011 16:28:23 -0400
+
+indicator-messages (0.4.91-0ubuntu1) oneiric; urgency=low
+
+ [ Ted Gould ]
+ * New upstream release.
+ * Update for libindicator 0.4
+
+ [ Ken VanDine ]
+ * debian/control
+ - Bumped build depends for libindicator to >= 0.3.90
+
+ -- Ken VanDine <ken.vandine@xxxxxxxxxxxxx> Fri, 08 Jul 2011 11:23:58 -0400
+
+indicator-messages (0.4.90-0ubuntu2) oneiric; urgency=low
+
+ * Rebuild for libdbusmenu-gtk3-4
+ * debian/control
+ - Removed duplicate build depends
+ - Dropped build depends on indicator-messages-gtk2
+
+ -- Ken VanDine <ken.vandine@xxxxxxxxxxxxx> Tue, 28 Jun 2011 09:01:12 -0400
+
+indicator-messages (0.4.90-0ubuntu1) oneiric; urgency=low
+
+ [ Ted Gould ]
+ * New upstream release.
+ * GTK 3
+
+ [ Ken VanDine ]
+ * debian/control
+ - Bumped standards version to 3.9.2
+ - Add new binary for indicator-messages-gtk2
+ - Make indicator-messages recommend indicator-messages-gtk2 (until unity
+ can load gtk3 indicators)
+ - indicator-messages-gtk2 replaces indicator-messages << 0.4.90
+ - Added build depends for libdbusmenu-gtk3-dev and libindicator3-dev
+ * debian/rules
+ - build for both gtk2 and gtk3
+
+ -- Ken VanDine <ken.vandine@xxxxxxxxxxxxx> Wed, 22 Jun 2011 12:34:43 -0400
+
+indicator-messages (0.4.0-1) unstable; urgency=low
+
+ * Merge new upstream from Ubuntu.
+ * Standards-Version: 3.9.2
+
+ -- Evgeni Golov <evgeni@xxxxxxxxxx> Sun, 05 Jun 2011 13:16:03 +0200
+
+indicator-messages (0.4.0-0ubuntu1) natty; urgency=low
+
+ * New upstream release.
+ ∘ Set the type before other variables to get default handling more
+ reliable (LP: #723873)
+ ∘ Add support for overriding the default icon with a specific one
+ for the messaging menu (LP: #741068)
+
+ -- Ted Gould <ted@xxxxxxxxxx> Thu, 07 Apr 2011 12:35:36 -0500
+
+indicator-messages (0.3.92-1) unstable; urgency=low
+
+ * Merge new upstream from Ubuntu.
+ * Fix 0.3.11-0ubuntu3 changelog entry (missed a space), so that
+ bzr builddeb won't go crazy (see Debian Bug #620242)
+ * Fix debian/copyright, was refering to libdbusmenu by mistake.
+
+ -- Evgeni Golov <evgeni@xxxxxxxxxx> Sun, 03 Apr 2011 13:37:33 +0200
+
+indicator-messages (0.3.92-0ubuntu3) natty; urgency=low
+
+ * debian/patches/lp_690668.patch
+ - Memory leak fixes (LP: #690668)
+ * debian/control
+ - Bump standards version to 3.9.1
+ * debian/source/format
+ - Use source format 3.0 (quilt)
+
+ -- Ken VanDine <ken.vandine@xxxxxxxxxxxxx> Thu, 24 Feb 2011 12:13:33 -0500
+
+indicator-messages (0.3.92-0ubuntu2) natty; urgency=low
+
+ * src/launcher-menu-item.c
+ - Make sure menu entries are displayed for launchers that aren't running (LP: #723873)
+
+ -- Ken VanDine <ken.vandine@xxxxxxxxxxxxx> Wed, 23 Feb 2011 16:06:37 -0500
+
+indicator-messages (0.3.92-0ubuntu1) natty; urgency=low
+
+ * New upstream release.
+ * Adding in accessible description support
+ * debian/control: libindicator version 0.3.19
+
+ -- Ted Gould <ted@xxxxxxxxxx> Thu, 17 Feb 2011 12:18:32 -0600
+
+indicator-messages (0.3.91-0ubuntu1) natty; urgency=low
+
+ * New upstream release.
+ * Fixing the service file
+ * Adding a log domain
+ * Fixing type handler for dbusmenu 0.3.94
+ * debian/control: dbusmenu to 0.3.94
+
+ -- Ted Gould <ted@xxxxxxxxxx> Thu, 27 Jan 2011 17:01:34 -0600
+
+indicator-messages (0.3.90-0ubuntu1) natty; urgency=low
+
+ [ Ted Gould ]
+ * New upstream release.
+ * GDBus Port
+ * New libindicate and dbusmenu
+
+ [ Ken VanDine ]
+ * debian/control
+ - Build depends on libindicate-dev to 0.4.91
+ - Build depends on dbusmenu to 0.3.91
+ - Set Vcs to ~ubuntu-desktop
+ * data/indicator-messages.service.in
+ - Fixed dbus interface name
+
+ -- Ken VanDine <ken.vandine@xxxxxxxxxxxxx> Fri, 14 Jan 2011 14:50:30 -0600
+
+indicator-messages (0.3.11-0ubuntu4) natty; urgency=low
+
+ * debian/control
+ - Bump build depends for libdbusmenu-* to >= 0.3.90
+
+ -- Ken VanDine <ken.vandine@xxxxxxxxxxxxx> Thu, 09 Dec 2010 11:39:40 -0500
+
+indicator-messages (0.3.11-0ubuntu3) UNRELEASED; urgency=low
+
+ * debian/control: package description spelling (LP: #658096)
+
+ -- Greg Auger <gregory.auger@xxxxxxxxxxxxxx> Tue, 09 Nov 2010 18:49:38 +0000
+
+indicator-messages (0.3.11-0ubuntu2) maverick; urgency=low
+
+ * Rebuild for libindicator ABI change (LP: #637692)
+ * debian/control: depends on latest libindicator-dev
+
+ -- Didier Roche <didrocks@xxxxxxxxxx> Wed, 22 Sep 2010 18:39:27 +0200
+
+indicator-messages (0.3.11-0ubuntu1) maverick; urgency=low
+
+ * New upstream release.
+ * Fixing triangles by passing data to callback (LP: #623453)
+
+ -- Ted Gould <ted@xxxxxxxxxx> Thu, 09 Sep 2010 13:24:13 -0500
+
+indicator-messages (0.3.10-0ubuntu1) maverick; urgency=low
+
+ * New upstream release.
+ * Shifting icons into the gutter and adjusting the arrow
+ padding.
+
+ -- Ted Gould <ted@xxxxxxxxxx> Thu, 26 Aug 2010 15:08:31 -0500
+
+indicator-messages (0.3.9-0ubuntu1) maverick; urgency=low
+
+ * New upstream release.
+ * Remove parens from counts
+
+ -- Ted Gould <ted@xxxxxxxxxx> Thu, 12 Aug 2010 13:10:10 -0500
+
+indicator-messages (0.3.8-0ubuntu1) maverick; urgency=low
+
+ * New upstream release.
+ - running apps triangle indicator overlay
+ - message counters are now rendered with a nice rounded background
+
+ -- Ken VanDine <ken.vandine@xxxxxxxxxxxxx> Thu, 29 Jul 2010 13:33:14 -0400
+
+indicator-messages (0.3.7-1) unstable; urgency=low
+
+ * Merge from Ubuntu.
+ Closes: #586132
+ * debian/control:
+ - Homepage is at LP/indicator-messages, not -applet.
+ - Update package description.
+ - Update Vcs-* fields.
+ - Standards-Version: 3.8.4.
+ * debian/copyright:
+ - Convert to DEP5 format.
+ - Add missing copyright holders of debian/.
+
+ -- Evgeni Golov <evgeni@xxxxxxxxxx> Thu, 17 Jun 2010 13:02:37 +0200
+
+indicator-messages (0.3.7-0ubuntu1~ppa1) lucid; urgency=low
+
+ * New upstream release.
+ * When loading desktop files check to see if they've
+ already been eclipsed by an app. (LP: #549096)
+ * Track better application shortcuts and ensure that they
+ get removed when the application is. (LP: #539167)
+ * Track blacklisted apps to ensure that the messaging menu
+ hides when there is no app. (LP: #533021)
+
+ -- Ted Gould <ted@xxxxxxxxxx> Fri, 21 May 2010 15:02:16 -0500
+
+indicator-messages (0.3.6-0ubuntu2) lucid; urgency=low
+
+ * Upstream Merge
+ * When loading desktop files check to see if they've
+ already been eclipsed by an app. (LP: #549096)
+ * Track better application shortcuts and ensure that they
+ get removed when the application is. (LP: #539167)
+
+ -- Ted Gould <ted@xxxxxxxxxx> Sat, 17 Apr 2010 13:10:42 -0500
+
+indicator-messages (0.3.6-0ubuntu1) lucid; urgency=low
+
+ * New upstream release.
+ * Fixing several bugs with regards to visibility and placement
+ if items and separators in the menu. (LP: #446914)
+ * Changing the service management over to using libindicator
+ services and service manager for robustness.
+
+ -- Ted Gould <ted@xxxxxxxxxx> Thu, 01 Apr 2010 10:13:38 -0500
+
+indicator-messages (0.3.5-0ubuntu2) lucid; urgency=low
+
+ * debian/control:
+ - change the indicator-applet depends to a recommends to let other
+ desktops use other options rather than having to trigger GNOME
+
+ -- Sebastien Bacher <seb128@xxxxxxxxxx> Tue, 30 Mar 2010 10:35:59 +0200
+
+indicator-messages (0.3.5-0ubuntu1) lucid; urgency=low
+
+ * Upstream release 0.3.5
+ * Show which applications are running with a small icon
+ next to their entry. (LP: #438526)
+ * Shift command items to line up with application names.
+ (LP: #537312)
+ * Track applications we've seen so that we can show "Set Up"
+ text if we've not seen the app before.
+ * Fix avatar spacing to match other menu items
+ * Use standard libindicator icon handling in panel
+ * Fix translation of non-running applications (LP: #540148)
+ * Handling bools for requesting attention from apps
+ * Changing microblogging to broadcast to match Me Menu (LP: #534952)
+ * debian/control:
+ - Updating requirement to libindicator 0.3.5
+ - Increasing dbusmenu-glib dep to 0.2.8
+
+ -- Ted Gould <ted@xxxxxxxxxx> Thu, 25 Mar 2010 10:53:01 -0500
+
+indicator-messages (0.3.4-0ubuntu1~ppa1) lucid; urgency=low
+
+ * Upstream release 0.3.4
+ * Fix avatar spacing to match other menu items
+ * Use standard libindicator icon handling in panel
+ * Fix translation of non-running applications (LP: #540148)
+ * Handling bools for requesting attention from apps
+ * Changing microblogging to broadcast to match Me Menu (LP: #534952)
+ * debian/control: Updating requirement to libindicator 0.3.5
+
+ -- Ted Gould <ted@xxxxxxxxxx> Thu, 18 Mar 2010 13:45:19 -0500
+
+indicator-messages (0.3.3-0ubuntu2) lucid; urgency=low
+
+ * src/default-applications.c
+ - string change for consistency (LP: #534952)
+
+ -- Ken VanDine <ken.vandine@xxxxxxxxxxxxx> Fri, 12 Mar 2010 11:44:46 -0500
+
+indicator-messages (0.3.3-0ubuntu1) lucid; urgency=low
+
+ * Upstream release 0.3.3
+ * Changing names of default applications to generic names
+ * Making icons of default applications match panel theme
+
+ -- Ted Gould <ted@xxxxxxxxxx> Thu, 04 Mar 2010 16:02:11 -0600
+
+indicator-messages (0.3.2-0ubuntu1) lucid; urgency=low
+
+ * Upstream release 0.3.2
+ * Removing extra ref
+ * Moving locally defined variable to use the one defined in
+ the function to fix a NULL pointer. (lp: #518547)
+ * Disconnect the count changed signal property
+ * Adding static desktop shortcuts to application items
+ * Adding dynamic application menuitems
+ * Switching application menu items to remove descriptions
+ and add in application icons
+ * debian/control:
+ * libindicator build dependency to 0.3.3
+ * dbusmenu build dependency to 0.2.5
+
+ -- Ted Gould <ted@xxxxxxxxxx> Thu, 18 Feb 2010 12:23:29 -0600
+
+indicator-messages (0.3.1-0ubuntu2) lucid; urgency=low
+
+ * Upstream Merge
+ * Removing extra ref
+ * Moving locally defined variable to use the one defined in
+ the function to fix a NULL pointer. (lp: #518547)
+
+ -- Ted Gould <ted@xxxxxxxxxx> Tue, 09 Feb 2010 09:30:10 -0600
+
+indicator-messages (0.3.1-0ubuntu1) lucid; urgency=low
+
+ * Upstream release 0.3.1
+ * Updates for dbusmenu 0.2.2
+ * Updates for libindicate 0.3.0
+ * debian/control:
+ * dbusmenu* depends to 0.2.2
+ * libindicate* depends to 0.3.0
+
+ -- Ted Gould <ted@xxxxxxxxxx> Thu, 04 Feb 2010 18:23:34 -0800
+
+indicator-messages (0.3.0-0ubuntu1) lucid; urgency=low
+
+ * Upstream release 0.3.0
+ - Disabling static builds.
+ - Porting to libindicator 0.3.0
+ - Adding translator comments from hours and minutes strings.
+ (LP: #456437)
+ - Upgrading to dbusmenu 0.2.0
+ * debian/control: Updating dbusmenu dependency to 0.2.0
+ * debian/control: Increasing libindicator-dev dependency to
+ 0.3.0
+
+ -- Ted Gould <ted@xxxxxxxxxx> Fri, 08 Jan 2010 12:05:25 -0600
+
+indicator-messages (0.2.6+r156-0ubuntu2) lucid; urgency=low
+
+ * debian/control
+ - add a Breaks for indicator-applet (<< 0.3.0)
+
+ -- Ken VanDine <ken.vandine@xxxxxxxxxxxxx> Tue, 15 Dec 2009 11:57:42 -0500
+
+indicator-messages (0.2.6+r156-0ubuntu1) lucid; urgency=low
+
+ * New snapshot for libindicator 0.3.0
+ * debian/control
+ - Build-Depends on libindicator >= 0.3.0
+
+ -- Ken VanDine <ken.vandine@xxxxxxxxxxxxx> Thu, 10 Dec 2009 14:35:46 -0500
+
+indicator-messages (0.2.6-0ubuntu1) karmic; urgency=low
+
+ * Upstream release 0.2.6 (LP: #446629)
+ * Building the menu after checking the blacklist so that the
+ separators are all correct.
+ * Small fix for a perspective memory leak.
+
+ -- Ted Gould <ted@xxxxxxxxxx> Fri, 09 Oct 2009 08:14:27 +0200
+
+indicator-messages (0.2.5-0ubuntu1) karmic; urgency=low
+
+ * Upstream release 0.2.5 (LP: #440217)
+ * Adding a check on addition of launchers to ensure icon is correctly
+ visible. (LP: #433274)
+ * Making it so that if applications don't set the time on an indicator
+ the time isn't shown in the menu. (LP: #438237)
+ * Putting icons in the right places. (LP: #436460)
+
+ -- Ted Gould <ted@xxxxxxxxxx> Thu, 01 Oct 2009 23:34:28 +0200
+
+indicator-messages (0.2.4-0ubuntu1) karmic; urgency=low
+
+ * Upstream release 0.2.4 (LP: #436093)
+ - Merging in the min menu width feature (LP: #428292)
+ - Merging in icon scaling branch from trunk. Now better icons (LP: #433143)
+ - Merging in updated trunk (LP: #434097 and LP: #435184)
+ - add i18n support
+ - Prevent null entries (LP: #435184)
+ - add a path for indicators in /usr/share (LP: #434097)
+
+ -- Ted Gould <ted@xxxxxxxxxx> Thu, 24 Sep 2009 13:07:46 -0500
+
+indicator-messages (0.2.2-0ubuntu2) karmic; urgency=low
+
+ * src/messages-service.c: initialise the translations
+
+ -- Sebastien Bacher <seb128@xxxxxxxxxx> Tue, 15 Sep 2009 16:41:03 +0200
+
+indicator-messages (0.2.2-0ubuntu1) karmic; urgency=low
+
+ * New release (LP: #427357)
+ * Adds in separators between application groups
+ * Merging in v2-api stuff which will become 0.2.1
+ * debian/control:
+ - Requiring > 0.2.0 of libindicate-*
+ - bump dbusmenu dependencies.
+
+ -- Ted Gould <ted@xxxxxxxxxx> Thu, 10 Sep 2009 09:11:57 -0500
+
+indicator-messages (0.2.0-0ubuntu2) karmic; urgency=low
+
+ * debian/control
+ - Bump build depends on dbusmenu to 0.1.0
+
+ -- Ken VanDine <ken.vandine@xxxxxxxxxxxxx> Thu, 27 Aug 2009 21:14:46 +0200
+
+indicator-messages (0.2.0-0ubuntu1) karmic; urgency=low
+
+ [ Ted Gould ]
+ * Upstream version 0.2.0
+ * debian/control: Adding dependency information for libdbusmenu
+ to say >= 0.0.2 to match upstream build system.
+ * debian/watch: Changing to use indicator-messages project.
+
+ [ Martin Pitt ]
+ * debian/control: Update Vcs-Bzr: for new branch location.
+
+ -- Ted Gould <ted@xxxxxxxxxx> Thu, 27 Aug 2009 20:46:27 +0200
+
+indicator-messages (0.2.0~bzr124-0ubuntu1) karmic; urgency=low
+
+ * Update to fix build issue
+
+ -- Sebastien Bacher <seb128@xxxxxxxxxx> Fri, 07 Aug 2009 17:12:40 +0100
+
+indicator-messages (0.2.0~bzr121-0ubuntu3) karmic; urgency=low
+
+ * Fix to dereference the application menu items correctly so that
+ the signal handlers are dropped as well. (lp: #410251)
+
+ -- Ted Gould <ted@xxxxxxxxxx> Wed, 05 Aug 2009 19:00:31 +0100
+
+indicator-messages (0.2.0~bzr121-0ubuntu2) karmic; urgency=low
+
+ * Run autogen.sh before upload
+
+ -- Jonathan Riddell <jriddell@xxxxxxxxxx> Wed, 05 Aug 2009 00:42:39 +0100
+
+indicator-messages (0.2.0~bzr121-0ubuntu1) karmic; urgency=low
+
+ [ Ted Gould ]
+ * debian/control: Adding in a build dep on libindicate-gtk-dev
+ * Changes for the changing libindicate stuff.
+ * Merge in the dbusmenu changes from the dbusmenu branch
+ * debian/control: Adding in a build dependency on libdbusmenu-glib and
+ libdbusmenu-gtk to catch up with the merge.
+
+ -- Jonathan Riddell <jriddell@xxxxxxxxxx> Wed, 05 Aug 2009 00:21:50 +0100
+
+indicator-messages (0.2.0~bzr120-0ubuntu1) jaunty; urgency=low
+
+ * Fix to track the timer. (LP: #365187)
+
+ -- Ted Gould <ted@xxxxxxxxxx> Wed, 13 May 2009 09:56:20 -0500
+
+indicator-messages (0.2.0~bzr119-0ubuntu1) jaunty; urgency=low
+
+ * Upstream update
+
+ -- Ted Gould <ted@xxxxxxxxxx> Wed, 22 Apr 2009 23:34:21 -0500
+
+indicator-messages (0.2.0~bzr116-0ubuntu3) jaunty; urgency=low
+
+ * debian/rules: Adding a rule to remove the .la/.a clutter
+
+ -- Ted Gould <ted@xxxxxxxxxx> Wed, 22 Apr 2009 16:46:59 -0500
+
+indicator-messages (0.2.0~bzr116-0ubuntu2) jaunty; urgency=low
+
+ * debian/control: libindicator-dev to ~bzr301
+
+ -- Ted Gould <ted@xxxxxxxxxx> Wed, 22 Apr 2009 15:58:45 -0500
+
+indicator-messages (0.2.0~bzr116-0ubuntu1) jaunty; urgency=low
+
+ * Upstream release
+ * Bug fixes
+ * Update API to new libindicator
+ * debian/control: Adding new dependency on libindicator-dev
+
+ -- Ted Gould <ted@xxxxxxxxxx> Wed, 22 Apr 2009 15:45:21 -0500
+
+indicator-messages (0.1.6-0ubuntu1) jaunty; urgency=low
+
+ * New upstream version
+ * Patch from Cody Russell to fix LP: #359018 by correctly implementing
+ the finalize functions.
+
+ -- Ted Gould <ted@xxxxxxxxxx> Tue, 14 Apr 2009 11:32:00 +0200
+
+indicator-messages (0.1.5-0ubuntu1) jaunty; urgency=low
+
+ * New upstream version
+ * Fixes the lifecycle of the various structures tracking the messages
+ and applications. Fixing bugs like (LP: #355616) (LP: #352881)
+ * Fixes the visual appearance by setting the widget name to grab the
+ style settings from the main applet. (LP: #351979)
+ * debian/control: Upgrading dependency on libindicate-dev to 0.1.5 or
+ higher as the new version requires that.
+
+ -- Ted Gould <ted@xxxxxxxxxx> Fri, 03 Apr 2009 16:32:49 -0500
+
+indicator-messages (0.1.4-0ubuntu1) jaunty; urgency=low
+
+ * New upstream version
+ * Adding the display of indicators that are login messages coming from
+ other applications. (LP: #345494)
+ * Making all times displayed for IM messages relative instead of
+ absolute. (LP: #346345)
+ * Cleaning up the server removal code. May fix (LP: #345599), I can't
+ recreate it anymore afterwards.
+
+ -- Ted Gould <ted@xxxxxxxxxx> Mon, 30 Mar 2009 09:40:40 +0200
+
+indicator-messages (0.1.3-0ubuntu1) jaunty; urgency=low
+
+ [ Ted Gould ]
+ * New upstream version.
+ - Now changes the icon based on non-IM indicators so that Evolution
+ works much better. (LP: #342480)
+ - Now the menu items are in a predictable order, alphabetical.
+ - The Messages for a particular client (i.e. Pidgin) are grouped with
+ the client they're associated with.
+ - Adjusting the icon size to match the new one in the Human theme.
+ - Adjusting the build so that all the different libraries are not
+ built in a versioned manner. Now it's just one .so, which is
+ what it should have been originally.
+
+ [ Martin Pitt ]
+ * Add debian/watch.
+ * Add bzr-builddeb configuration.
+ * debian/copyright: Fix download location.
+
+ -- Martin Pitt <martin.pitt@xxxxxxxxxx> Thu, 19 Mar 2009 12:23:17 +0100
+
+indicator-messages (0.1-0ubuntu1) jaunty; urgency=low
+
+ * Initial release, based on DX team's PPA packaging branch.
+ (lp:~indicator-applet-developers/indicator-applet/messages-packaging)
+ * debian/control: Add Homepage:, Vcs-Bzr:, and fix package
+ description.
+ * debian/copyright: Properly describe license.
+
+ -- Martin Pitt <martin.pitt@xxxxxxxxxx> Tue, 17 Feb 2009 11:35:38 +0100
+
=== added file 'debian/compat'
--- debian/compat 1970-01-01 00:00:00 +0000
+++ debian/compat 2013-06-07 21:39:23 +0000
@@ -0,0 +1,1 @@
+9
=== added file 'debian/control'
--- debian/control 1970-01-01 00:00:00 +0000
+++ debian/control 2013-06-07 21:39:23 +0000
@@ -0,0 +1,86 @@
+Source: indicator-messages
+Section: gnome
+Priority: optional
+Maintainer: Ubuntu Developers <ubuntu-devel-discuss@xxxxxxxxxxxxxxxx>
+XSBC-Original-Maintainer: The Ayatana Packagers <pkg-ayatana-devel@xxxxxxxxxxxxxxxxxxxxxxx>
+Uploaders: Evgeni Golov <evgeni@xxxxxxxxxx>
+Build-Depends: debhelper (>= 9),
+ dh-autoreconf,
+ dh-translations,
+ libglib2.0-dev (>= 2.35.4),
+ libgtk-3-dev (>= 3.5.12),
+ libdbus-glib-1-dev,
+ intltool,
+ libindicator3-dev,
+ libdbusmenu-glib-dev (>= 0.5.90),
+ libdbusmenu-gtk3-dev (>= 0.5.90),
+ libtelepathy-glib-dev (>= 0.9.0),
+ gobject-introspection (>= 0.9.12-4~),
+ libgirepository1.0-dev (>= 0.9.12),
+ gtk-doc-tools,
+ libgtest-dev,
+ python3-dbusmock,
+Standards-Version: 3.9.3
+Homepage: https://launchpad.net/indicator-messages
+# If you aren't a member of ~indicator-applet-developers but need to upload
+# packaging changes, just go ahead. ~indicator-applet-developers will notice
+# and sync up the code again.
+Vcs-Bzr: https://code.launchpad.net/~indicator-applet-developers/indicator-messages/trunk.13.04
+Vcs-Browser: https://bazaar.launchpad.net/~indicator-applet-developers/indicator-messages/trunk.13.04/files
+
+Package: indicator-messages
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Recommends: indicator-applet | indicator-renderer
+Replaces: libindicator-messages-status-provider1,
+ libindicator-messages-status-provider-dev,
+ indicator-status-provider-mc5,
+ indicator-status-provider-pidgin,
+ indicator-status-provider-telepathy,
+ indicator-status-provider-emesene,
+Conflicts: libindicator-messages-status-provider1,
+ libindicator-messages-status-provider-dev,
+ indicator-status-provider-mc5,
+ indicator-status-provider-pidgin,
+ indicator-status-provider-telepathy,
+ indicator-status-provider-emesene,
+Breaks: gwibber-services (<< 3.5.4-0ubuntu1~),
+ telepathy-indicator (<< 0.3.0-0ubuntu1~),
+ thunderbird (<< 15.0+build1-0ubuntu1~),
+ xchat-indicator (<< 0.3.11-0ubuntu2~),
+ xchat-gnome-indicator (<< 0.3.11-0ubuntu2~),
+Description: indicator that collects messages that need a response
+ A place on the user's desktop that collects messages that need a response.
+ This menu provides a condensed and collected view of all of those messages
+ for quick access, but without making them annoying in times that you want
+ to ignore them.
+
+Package: libmessaging-menu0
+Architecture: any
+Section: libs
+Depends: ${shlibs:Depends},
+ ${misc:Depends},
+Description: Messaging Menu - shared library
+ This library contains information to build status providers to go into
+ the messaging menu.
+
+Package: libmessaging-menu-dev
+Architecture: any
+Section: libdevel
+Depends: ${shlibs:Depends},
+ ${misc:Depends},
+ libmessaging-menu0 (=${binary:Version}),
+ libglib2.0-dev,
+Description: Messaging Menu - library development files
+ This library contains information to build status providers to go into
+ the messaging menu.
+
+Package: gir1.2-messagingmenu-1.0
+Section: libs
+Architecture: any
+Depends: ${misc:Depends},
+ ${gir:Depends},
+Description: Messaging Menu - gir bindings
+ .
+ This package can be used by other packages using the GIRepository format
+ to generate dynamic bindings.
=== added file 'debian/copyright'
--- debian/copyright 1970-01-01 00:00:00 +0000
+++ debian/copyright 2013-06-07 21:39:23 +0000
@@ -0,0 +1,19 @@
+Format-Specification: http://svn.debian.org/wsvn/dep/web/deps/dep5.mdwn?op=file&rev=135
+Name: indicator-messages
+Maintainer: Ted Gould <ted@xxxxxxxxxxxxx>
+Source: https://launchpad.net/indicator-messages
+
+Files: *
+Copyright: 2009-2010 Ted Gould <ted@xxxxxxxxxxxxx>, Canonical Ltd.
+License: GPL-3
+
+Files: debian/*
+Copyright: 2009-2010 Evgeni Golov <evgeni@xxxxxxxxxx>
+Copyright: 2009-2010 Ted Gould <ted@xxxxxxxxxxxxx>, Canonical Ltd.
+Copyright: 2009-2010 Sebastien Bacher <seb128@xxxxxxxxxx>
+Copyright: 2009-2010 Ken VanDine <ken.vandine@xxxxxxxxxxxxx>
+License: GPL-3
+
+License: GPL-3
+ On Debian systems, the complete text of the GNU General
+ Public License version 3 can be found in `/usr/share/common-licenses/GPL-3'.
=== added file 'debian/gir1.2-messagingmenu-1.0.install'
--- debian/gir1.2-messagingmenu-1.0.install 1970-01-01 00:00:00 +0000
+++ debian/gir1.2-messagingmenu-1.0.install 2013-06-07 21:39:23 +0000
@@ -0,0 +1,1 @@
+usr/lib/girepository-1.0/*.typelib
=== added file 'debian/indicator-messages.install'
--- debian/indicator-messages.install 1970-01-01 00:00:00 +0000
+++ debian/indicator-messages.install 2013-06-07 21:39:23 +0000
@@ -0,0 +1,5 @@
+usr/lib/indicators3
+usr/lib/indicator-messages/indicator-messages-service
+usr/share/dbus-1
+usr/share/glib-2.0
+usr/share/icons
=== added file 'debian/libmessaging-menu-dev.install'
--- debian/libmessaging-menu-dev.install 1970-01-01 00:00:00 +0000
+++ debian/libmessaging-menu-dev.install 2013-06-07 21:39:23 +0000
@@ -0,0 +1,5 @@
+usr/lib/libmessaging-menu.so
+usr/lib/pkgconfig
+usr/include /usr/
+usr/share/gir-1.0/
+usr/share/gtk-doc
=== added file 'debian/libmessaging-menu0.install'
--- debian/libmessaging-menu0.install 1970-01-01 00:00:00 +0000
+++ debian/libmessaging-menu0.install 2013-06-07 21:39:23 +0000
@@ -0,0 +1,1 @@
+usr/lib/libmessaging-menu.so.* /usr/lib/
=== added file 'debian/libmessaging-menu0.symbols'
--- debian/libmessaging-menu0.symbols 1970-01-01 00:00:00 +0000
+++ debian/libmessaging-menu0.symbols 2013-06-07 21:39:23 +0000
@@ -0,0 +1,23 @@
+libmessaging-menu.so.0 libmessaging-menu0 #MINVER#
+ messaging_menu_app_append_source@Base 12.10.0
+ messaging_menu_app_append_source_with_count@Base 12.10.0
+ messaging_menu_app_append_source_with_string@Base 12.10.0
+ messaging_menu_app_append_source_with_time@Base 12.10.0
+ messaging_menu_app_draw_attention@Base 12.10.0
+ messaging_menu_app_get_type@Base 12.10.0
+ messaging_menu_app_has_source@Base 12.10.0
+ messaging_menu_app_insert_source@Base 12.10.0
+ messaging_menu_app_insert_source_with_count@Base 12.10.0
+ messaging_menu_app_insert_source_with_string@Base 12.10.0
+ messaging_menu_app_insert_source_with_time@Base 12.10.0
+ messaging_menu_app_new@Base 12.10.0
+ messaging_menu_app_register@Base 12.10.0
+ messaging_menu_app_remove_attention@Base 12.10.0
+ messaging_menu_app_remove_source@Base 12.10.0
+ messaging_menu_app_set_source_count@Base 12.10.0
+ messaging_menu_app_set_source_icon@Base 12.10.2
+ messaging_menu_app_set_source_label@Base 12.10.2
+ messaging_menu_app_set_source_string@Base 12.10.0
+ messaging_menu_app_set_source_time@Base 12.10.0
+ messaging_menu_app_set_status@Base 12.10.0
+ messaging_menu_app_unregister@Base 12.10.0
=== added file 'debian/rules'
--- debian/rules 1970-01-01 00:00:00 +0000
+++ debian/rules 2013-06-07 21:39:23 +0000
@@ -0,0 +1,17 @@
+#!/usr/bin/make -f
+
+export DPKG_GENSYMBOLS_CHECK_LEVEL=4
+
+%:
+ dh $@ --with autoreconf,translations,gir
+
+override_dh_autoreconf:
+ NO_CONFIGURE=1 dh_autoreconf ./autogen.sh
+
+override_dh_auto_configure:
+ dh_auto_configure -- --libdir="\$${prefix}/lib" --libexecdir="\$${prefix}/lib/indicator-messages" --enable-gtk-doc
+
+override_dh_install:
+ find debian/tmp/usr/lib -name *.la -delete
+ dh_install --fail-missing
+
=== added file 'debian/watch'
--- debian/watch 1970-01-01 00:00:00 +0000
+++ debian/watch 2013-06-07 21:39:23 +0000
@@ -0,0 +1,2 @@
+version=3
+http://launchpad.net/indicator-messages/+download .*/indicator-messages-([0-9.]+)\.tar\.gz
=== added directory 'doc'
=== added file 'doc/Makefile.am'
--- doc/Makefile.am 1970-01-01 00:00:00 +0000
+++ doc/Makefile.am 2013-06-07 21:39:23 +0000
@@ -0,0 +1,1 @@
+SUBDIRS = reference
=== added directory 'doc/reference'
=== added file 'doc/reference/Makefile.am'
--- doc/reference/Makefile.am 1970-01-01 00:00:00 +0000
+++ doc/reference/Makefile.am 2013-06-07 21:39:23 +0000
@@ -0,0 +1,20 @@
+DOC_MODULE = messaging-menu
+
+DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.xml
+
+DOC_SOURCE_DIR = $(top_srcdir)/libmessaging-menu
+
+MKDB_OPTIONS=--xml-mode --output-format=xml
+
+# Used for dependencies. The docs will be rebuilt if any of these change.
+HFILE_GLOB = $(top_srcdir)/libmessaging-menu/*.h
+CFILE_GLOB = $(top_srcdir)/libmessaging-menu/*.c
+
+IGNORE_HFILES= \
+ indicator-messages-service.h \
+ gtupleaction.h
+
+INCLUDES=-I$(top_srcdir)/libmessaging-menu $(GIO_CFLAGS)
+GTKDOC_LIBS=$(top_builddir)/libmessaging-menu/libmessaging-menu.la
+
+include $(top_srcdir)/gtk-doc.make
=== added file 'doc/reference/messaging-menu-docs.xml.in'
--- doc/reference/messaging-menu-docs.xml.in 1970-01-01 00:00:00 +0000
+++ doc/reference/messaging-menu-docs.xml.in 2013-06-07 21:39:23 +0000
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<!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 "@PACKAGE_VERSION@">
+]>
+<book lang="en" id="messaging-menu" xmlns:xi="http://www.w3.org/2003/XInclude">
+<title>Messaging Menu Reference Manual</title>
+ <bookinfo>
+ <title>Messaging Menu Reference Manual</title>
+ <releaseinfo>for libmessaging-menu &version;</releaseinfo>
+
+ <copyright>
+ <year>2012</year>
+ <holder>Canonical Ltd.</holder>
+ </copyright>
+ </bookinfo>
+
+ <chapter>
+ <title>API Reference</title>
+ <xi:include href="xml/messaging-menu.xml"/>
+ </chapter>
+
+ <chapter id="object-tree">
+ <title>Object Hierarchy</title>
+ <xi:include href="xml/tree_index.sgml"/>
+ </chapter>
+ <index id="api-index-full">
+ <title>API Index</title>
+ <xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
+ </index>
+ <index id="deprecated-api-index" role="deprecated">
+ <title>Index of deprecated API</title>
+ <xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
+ </index>
+
+ <xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
+</book>
=== added directory 'libmessaging-menu'
=== added file 'libmessaging-menu/Makefile.am'
--- libmessaging-menu/Makefile.am 1970-01-01 00:00:00 +0000
+++ libmessaging-menu/Makefile.am 2013-06-07 21:39:23 +0000
@@ -0,0 +1,66 @@
+
+lib_LTLIBRARIES = libmessaging-menu.la
+
+libmessaging_menu_ladir = $(includedir)/messaging-menu
+
+libmessaging_menu_la_SOURCES = \
+ messaging-menu.c \
+ gtupleaction.c \
+ gtupleaction.h \
+ $(BUILT_SOURCES)
+
+libmessaging_menu_la_HEADERS = \
+ messaging-menu.h
+
+libmessaging_menu_la_LIBADD = $(GIO_LIBS)
+
+libmessaging_menu_la_CFLAGS = \
+ $(GIO_CFLAGS) \
+ -Wall
+
+libmessaging_menu_la_LDFLAGS = -export-symbols-regex "^messaging_menu_.*"
+
+BUILT_SOURCES = \
+ indicator-messages-service.c \
+ indicator-messages-service.h
+
+CLEANFILES = $(BUILT_SOURCES)
+
+indicator-messages-service.c: $(top_srcdir)/src/messages-service.xml
+ $(AM_V_GEN) gdbus-codegen \
+ --interface-prefix com.canonical.indicator.messages. \
+ --generate-c-code indicator-messages-service \
+ --c-namespace IndicatorMessages \
+ $^
+indicator-messages-service.h: indicator-messages-service.c
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = messaging-menu.pc
+
+
+-include $(INTROSPECTION_MAKEFILE)
+
+INTROSPECTION_GIRS =
+INTROSPECTION_SCANNER_ARGS = --add-include-path=$(srcdir) --warn-all
+INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir)
+
+if HAVE_INTROSPECTION
+
+MessagingMenu-1.0.gir: libmessaging-menu.la
+MessagingMenu_1_0_gir_NAMESPACE = MessagingMenu
+MessagingMenu_1_0_gir_INCLUDES = GObject-2.0 Gio-2.0
+MessagingMenu_1_0_gir_CFLAGS = $(INCLUDES) $(GIO_CFLAGS)
+MessagingMenu_1_0_gir_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
+gir_DATA = $(INTROSPECTION_GIRS)
+
+typelibdir = $(libdir)/girepository-1.0
+typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
+
+CLEANFILES +=$(gir_DATA) $(typelib_DATA)
+endif
=== added file 'libmessaging-menu/gtupleaction.c'
--- libmessaging-menu/gtupleaction.c 1970-01-01 00:00:00 +0000
+++ libmessaging-menu/gtupleaction.c 2013-06-07 21:39:23 +0000
@@ -0,0 +1,354 @@
+/*
+ * 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@xxxxxxxxxxxxx>
+ */
+
+#include "gtupleaction.h"
+
+typedef GObjectClass GTupleActionClass;
+
+struct _GTupleAction
+{
+ GObject parent;
+
+ gchar *name;
+ GVariantType *type;
+ gboolean enabled;
+
+ gsize n_children;
+ GVariant **children;
+};
+
+static void action_interface_init (GActionInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GTupleAction, g_tuple_action, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_ACTION, action_interface_init));
+
+enum
+{
+ PROP_0,
+ PROP_NAME,
+ PROP_PARAMETER_TYPE,
+ PROP_ENABLED,
+ PROP_STATE_TYPE,
+ PROP_STATE,
+ N_PROPERTIES
+};
+
+enum
+{
+ SIGNAL_ACTIVATE,
+ N_SIGNALS
+};
+
+static GParamSpec *properties[N_PROPERTIES];
+static guint signal_ids[N_SIGNALS];
+
+static const gchar *
+g_tuple_action_get_name (GAction *action)
+{
+ GTupleAction *tuple = G_TUPLE_ACTION (action);
+
+ return tuple->name;
+}
+
+static const GVariantType *
+g_tuple_action_get_parameter_type (GAction *action)
+{
+ return NULL;
+}
+
+static const GVariantType *
+g_tuple_action_get_state_type (GAction *action)
+{
+ GTupleAction *tuple = G_TUPLE_ACTION (action);
+
+ return tuple->type;
+}
+
+static GVariant *
+g_tuple_action_get_state_hint (GAction *action)
+{
+ return NULL;
+}
+
+static gboolean
+g_tuple_action_get_enabled (GAction *action)
+{
+ GTupleAction *tuple = G_TUPLE_ACTION (action);
+
+ return tuple->enabled;
+}
+
+static GVariant *
+g_tuple_action_get_state (GAction *action)
+{
+ GTupleAction *tuple = G_TUPLE_ACTION (action);
+ GVariant *result;
+
+ result = g_variant_new_tuple (tuple->children, tuple->n_children);
+ return g_variant_ref_sink (result);
+}
+
+static void
+g_tuple_action_set_state (GTupleAction *tuple,
+ GVariant *state)
+{
+ int i;
+
+ g_return_if_fail (g_variant_type_is_tuple (g_variant_get_type (state)));
+
+ if (tuple->type == NULL)
+ {
+ tuple->type = g_variant_type_copy (g_variant_get_type (state));
+ tuple->n_children = g_variant_n_children (state);
+ tuple->children = g_new0 (GVariant *, tuple->n_children);
+ }
+
+ for (i = 0; i < tuple->n_children; i++)
+ {
+ if (tuple->children[i])
+ g_variant_unref (tuple->children[i]);
+ tuple->children[i] = g_variant_get_child_value (state, i);
+ }
+
+ g_object_notify_by_pspec (G_OBJECT (tuple), properties[PROP_STATE]);
+}
+
+static void
+g_tuple_action_change_state (GAction *action,
+ GVariant *value)
+{
+ GTupleAction *tuple = G_TUPLE_ACTION (action);
+
+ g_return_if_fail (value != NULL);
+ g_return_if_fail (g_variant_is_of_type (value, tuple->type));
+
+ g_variant_ref_sink (value);
+
+ /* TODO add a change-state signal similar to GSimpleAction */
+ g_tuple_action_set_state (tuple, value);
+
+ g_variant_unref (value);
+}
+
+static void
+g_tuple_action_activate (GAction *action,
+ GVariant *parameter)
+{
+ GTupleAction *tuple = G_TUPLE_ACTION (action);
+
+ g_return_if_fail (parameter == NULL);
+
+ if (tuple->enabled)
+ g_signal_emit (tuple, signal_ids[SIGNAL_ACTIVATE], 0, NULL);
+}
+
+static void
+g_tuple_action_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GAction *action = G_ACTION (object);
+
+ switch (prop_id)
+ {
+ case PROP_NAME:
+ g_value_set_string (value, g_tuple_action_get_name (action));
+ break;
+
+ case PROP_PARAMETER_TYPE:
+ g_value_set_boxed (value, g_tuple_action_get_parameter_type (action));
+ break;
+
+ case PROP_ENABLED:
+ g_value_set_boolean (value, g_tuple_action_get_enabled (action));
+ break;
+
+ case PROP_STATE_TYPE:
+ g_value_set_boxed (value, g_tuple_action_get_state_type (action));
+ break;
+
+ case PROP_STATE:
+ g_value_take_variant (value, g_tuple_action_get_state (action));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+g_tuple_action_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GTupleAction *tuple = G_TUPLE_ACTION (object);
+
+ switch (prop_id)
+ {
+ case PROP_NAME:
+ tuple->name = g_value_dup_string (value);
+ g_object_notify_by_pspec (object, properties[PROP_NAME]);
+ break;
+
+ case PROP_ENABLED:
+ tuple->enabled = g_value_get_boolean (value);
+ g_object_notify_by_pspec (object, properties[PROP_ENABLED]);
+ break;
+
+ case PROP_STATE:
+ g_tuple_action_set_state (tuple, g_value_get_variant (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+g_tuple_action_finalize (GObject *object)
+{
+ GTupleAction *tuple = G_TUPLE_ACTION (object);
+ int i;
+
+ g_free (tuple->name);
+ g_variant_type_free (tuple->type);
+
+ for (i = 0; i < tuple->n_children; i++)
+ g_variant_unref (tuple->children[i]);
+
+ g_free (tuple->children);
+
+ G_OBJECT_CLASS (g_tuple_action_parent_class)->finalize (object);
+}
+
+static void
+action_interface_init (GActionInterface *iface)
+{
+ iface->get_name = g_tuple_action_get_name;
+ iface->get_parameter_type = g_tuple_action_get_parameter_type;
+ iface->get_state_type = g_tuple_action_get_state_type;
+ iface->get_state_hint = g_tuple_action_get_state_hint;
+ iface->get_enabled = g_tuple_action_get_enabled;
+ iface->get_state = g_tuple_action_get_state;
+ iface->change_state = g_tuple_action_change_state;
+ iface->activate = g_tuple_action_activate;
+}
+
+static void
+g_tuple_action_class_init (GTupleActionClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ object_class->get_property = g_tuple_action_get_property;
+ object_class->set_property = g_tuple_action_set_property;
+ object_class->finalize = g_tuple_action_finalize;
+
+ properties[PROP_NAME] = g_param_spec_string ("name",
+ "Name",
+ "The name of the action",
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_PARAMETER_TYPE] = g_param_spec_boxed ("parameter-type",
+ "Parameter Type",
+ "The variant type passed to activate",
+ G_TYPE_VARIANT_TYPE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_ENABLED] = g_param_spec_boolean ("enabled",
+ "Enabled",
+ "Whether the action can be activated",
+ TRUE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_STATE_TYPE] = g_param_spec_boxed ("state-type",
+ "State Type",
+ "The variant type of the state, must be a tuple",
+ G_TYPE_VARIANT_TYPE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_STATE] = g_param_spec_variant ("state",
+ "State",
+ "The state of the action",
+ G_VARIANT_TYPE_TUPLE,
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
+
+ signal_ids[SIGNAL_ACTIVATE] = g_signal_new ("activate",
+ G_TYPE_TUPLE_ACTION,
+ G_SIGNAL_RUN_LAST | G_SIGNAL_MUST_COLLECT,
+ 0, NULL, NULL,
+ g_cclosure_marshal_VOID__VARIANT,
+ G_TYPE_NONE, 1,
+ G_TYPE_VARIANT);
+}
+
+static void
+g_tuple_action_init (GTupleAction *action)
+{
+ action->enabled = TRUE;
+}
+
+GTupleAction *
+g_tuple_action_new (const gchar *name,
+ GVariant *initial_state)
+{
+ const GVariantType *type;
+
+ g_return_val_if_fail (name != NULL, NULL);
+ g_return_val_if_fail (initial_state != NULL, NULL);
+
+ type = g_variant_get_type (initial_state);
+ g_return_val_if_fail (g_variant_type_is_tuple (type), NULL);
+
+ return g_object_new (G_TYPE_TUPLE_ACTION,
+ "name", name,
+ "state", initial_state,
+ NULL);
+}
+
+void
+g_tuple_action_set_child (GTupleAction *action,
+ gsize index,
+ GVariant *value)
+{
+ const GVariantType *type;
+
+ g_return_if_fail (G_IS_TUPLE_ACTION (action));
+ g_return_if_fail (index < action->n_children);
+ g_return_if_fail (value != NULL);
+
+ type = g_variant_get_type (value);
+ g_return_if_fail (g_variant_is_of_type (value, type));
+
+ g_variant_unref (action->children[index]);
+ action->children[index] = g_variant_ref_sink (value);
+
+ g_object_notify_by_pspec (G_OBJECT (action), properties[PROP_STATE]);
+}
=== added file 'libmessaging-menu/gtupleaction.h'
--- libmessaging-menu/gtupleaction.h 1970-01-01 00:00:00 +0000
+++ libmessaging-menu/gtupleaction.h 2013-06-07 21:39:23 +0000
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2012 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Lars Uebernickel <lars.uebernickel@xxxxxxxxxxxxx>
+ */
+
+#ifndef __g_tuple_action_h__
+#define __g_tuple_action_h__
+
+#include <gio/gio.h>
+
+#define G_TYPE_TUPLE_ACTION (g_tuple_action_get_type ())
+#define G_TUPLE_ACTION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_TUPLE_ACTION, GTupleAction))
+#define G_IS_TUPLE_ACTION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_TUPLE_ACTION))
+
+typedef struct _GTupleAction GTupleAction;
+
+GType g_tuple_action_get_type (void) G_GNUC_CONST;
+
+GTupleAction * g_tuple_action_new (const gchar *name,
+ GVariant *initial_state);
+
+void g_tuple_action_set_child (GTupleAction *action,
+ gsize index,
+ GVariant *value);
+
+#endif
=== added file 'libmessaging-menu/messaging-menu.c'
--- libmessaging-menu/messaging-menu.c 1970-01-01 00:00:00 +0000
+++ libmessaging-menu/messaging-menu.c 2013-06-07 21:39:23 +0000
@@ -0,0 +1,1199 @@
+/*
+ * 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@xxxxxxxxxxxxx>
+ */
+
+#include "messaging-menu.h"
+#include "indicator-messages-service.h"
+
+#include <gio/gdesktopappinfo.h>
+
+/**
+ * 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
+ * application through a desktop file id, which must be passed to
+ * messaging_menu_app_new().
+ *
+ * To register the application with the Messaging Menu, call
+ * messaging_menu_app_register(). This signifies that the application
+ * should be present in the menu and be marked as "running".
+ *
+ * The first menu item in an application section represents the
+ * application itself, using the name and icon found in the associated
+ * desktop file. Activating this item starts the application.
+ *
+ * Following the application item, the Messaging Menu inserts all
+ * 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.) An application cannot add, remove, or change
+ * these shortcut items while it is running.
+ *
+ * Next, an application section contains menu items for message sources.
+ * What exactly constitutes a message source depends on the type of
+ * application: an email client's message sources are folders
+ * containing new messages, while those of a chat program are persons
+ * that have contacted the user.
+ *
+ * A message source is represented in the menu by a label and optionally
+ * also an icon. It can be associated with either a count, a time, or
+ * an arbitrary string, which will appear on the right side of the menu
+ * item.
+ *
+ * When the user activates a source, the source is immediately removed
+ * from the menu and the "activate-source" signal is emitted.
+ *
+ * Applications should always expose all the message sources available.
+ * However, the Messaging Menu might limit the amount of sources it
+ * displays to the user.
+ *
+ * The Messaging Menu offers users a way to set their chat status
+ * (available, away, busy, invisible, or offline) for multiple
+ * applications at once. Applications that appear in the Messaging Menu
+ * can integrate with this by setting the
+ * "X-MessagingMenu-UsesChatSection" key in their desktop file to True.
+ * Use messaging_menu_app_set_status() to signify that the application's
+ * chat status has changed. When the user changes status through the
+ * Messaging Menu, the ::status-changed signal will be emitted.
+ *
+ * If the application stops running without calling
+ * messaging_menu_app_unregister(), it will be marked as "not running".
+ * Its application and shortcut items stay in the menu, but all message
+ * sources are removed. If messaging_menu_app_unregister() is called,
+ * the application section is removed completely.
+ *
+ * More information about the design and recommended usage of the
+ * Messaging Menu is available at <ulink
+ * url="https://wiki.ubuntu.com/MessagingMenu">https://wiki.ubuntu.com/MessagingMenu</ulink>.
+ */
+
+/**
+ * MessagingMenuApp:
+ *
+ * #MessagingMenuApp is an opaque structure.
+ */
+struct _MessagingMenuApp
+{
+ GObject parent_instance;
+
+ GDesktopAppInfo *appinfo;
+ int registered; /* -1 for unknown */
+ MessagingMenuStatus status;
+ gboolean status_set;
+ GSimpleActionGroup *source_actions;
+ GMenu *menu;
+ GDBusConnection *bus;
+
+ IndicatorMessagesService *messages_service;
+ guint watch_id;
+ guint action_export_id;
+ guint menu_export_id;
+
+ GCancellable *cancellable;
+};
+
+G_DEFINE_TYPE (MessagingMenuApp, messaging_menu_app, G_TYPE_OBJECT);
+
+enum {
+ PROP_0,
+ PROP_DESKTOP_ID,
+ N_PROPERTIES
+};
+
+enum {
+ ACTIVATE_SOURCE,
+ STATUS_CHANGED,
+ N_SIGNALS
+};
+
+static GParamSpec *properties[N_PROPERTIES];
+static guint signals[N_SIGNALS];
+
+static const gchar *status_ids[] = { "available", "away", "busy", "invisible", "offline" };
+
+static void global_status_changed (IndicatorMessagesService *service,
+ const gchar *status_str,
+ gpointer user_data);
+
+static gchar *
+messaging_menu_app_get_dbus_object_path (MessagingMenuApp *app)
+{
+ gchar *path;
+
+ if (!app->appinfo)
+ return NULL;
+
+ path = g_strconcat ("/com/canonical/indicator/messages/",
+ g_app_info_get_id (G_APP_INFO (app->appinfo)),
+ NULL);
+
+ g_strcanon (path, "/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", '_');
+
+ return path;
+}
+
+static void
+export_menus_and_actions (GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ MessagingMenuApp *app = user_data;
+ GError *error = NULL;
+ gchar *object_path;
+
+ object_path = messaging_menu_app_get_dbus_object_path (app);
+ if (!object_path)
+ return;
+
+ app->bus = g_bus_get_finish (res, &error);
+ if (app->bus == NULL)
+ {
+ g_warning ("unable to connect to session bus: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ app->action_export_id = g_dbus_connection_export_action_group (app->bus,
+ object_path,
+ G_ACTION_GROUP (app->source_actions),
+ &error);
+ if (!app->action_export_id)
+ {
+ g_warning ("unable to export action group: %s", error->message);
+ g_clear_error (&error);
+ }
+
+ app->menu_export_id = g_dbus_connection_export_menu_model (app->bus,
+ object_path,
+ G_MENU_MODEL (app->menu),
+ &error);
+ if (!app->menu_export_id)
+ {
+ g_warning ("unable to export menu: %s", error->message);
+ g_clear_error (&error);
+ }
+
+ g_free (object_path);
+}
+
+static void
+messaging_menu_app_set_desktop_id (MessagingMenuApp *app,
+ const gchar *desktop_id)
+{
+ g_return_if_fail (desktop_id != NULL);
+
+ /* no need to clean up, it's construct only */
+ app->appinfo = g_desktop_app_info_new (desktop_id);
+ if (app->appinfo == NULL)
+ {
+ g_warning ("could not find the desktop file for '%s'",
+ desktop_id);
+ }
+
+ g_bus_get (G_BUS_TYPE_SESSION,
+ app->cancellable,
+ export_menus_and_actions,
+ app);
+}
+
+static void
+messaging_menu_app_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ MessagingMenuApp *app = MESSAGING_MENU_APP (object);
+
+ switch (prop_id)
+ {
+ case PROP_DESKTOP_ID:
+ messaging_menu_app_set_desktop_id (app, g_value_get_string (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+messaging_menu_app_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (messaging_menu_app_parent_class)->finalize (object);
+}
+
+static void
+messaging_menu_app_dispose (GObject *object)
+{
+ MessagingMenuApp *app = MESSAGING_MENU_APP (object);
+
+ if (app->bus)
+ {
+ if (app->action_export_id > 0)
+ g_dbus_connection_unexport_action_group (app->bus, app->action_export_id);
+
+ if (app->menu_export_id > 0)
+ g_dbus_connection_unexport_menu_model (app->bus, app->menu_export_id);
+
+ app->action_export_id = 0;
+ app->menu_export_id = 0;
+ g_object_unref (app->bus);
+ app->bus = NULL;
+ }
+
+ if (app->watch_id > 0)
+ {
+ g_bus_unwatch_name (app->watch_id);
+ app->watch_id = 0;
+ }
+
+ if (app->cancellable)
+ {
+ g_cancellable_cancel (app->cancellable);
+ g_object_unref (app->cancellable);
+ app->cancellable = NULL;
+ }
+
+ if (app->messages_service)
+ {
+ indicator_messages_service_call_application_stopped_running (app->messages_service,
+ g_app_info_get_id (G_APP_INFO (app->appinfo)),
+ NULL, NULL, NULL);
+
+ g_signal_handlers_disconnect_by_func (app->messages_service,
+ global_status_changed,
+ app);
+ g_clear_object (&app->messages_service);
+ }
+
+ g_clear_object (&app->appinfo);
+ g_clear_object (&app->source_actions);
+ g_clear_object (&app->menu);
+
+ G_OBJECT_CLASS (messaging_menu_app_parent_class)->dispose (object);
+}
+
+static void
+messaging_menu_app_class_init (MessagingMenuAppClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ object_class->set_property = messaging_menu_app_set_property;
+ object_class->finalize = messaging_menu_app_finalize;
+ object_class->dispose = messaging_menu_app_dispose;
+
+ /**
+ * MessagingMenuApp:desktop-id:
+ *
+ * The desktop id of the application associated with this application
+ * section. Must be given when the #MessagingMenuApp is created.
+ */
+ properties[PROP_DESKTOP_ID] = g_param_spec_string ("desktop-id",
+ "Desktop Id",
+ "The desktop id of the associated application",
+ NULL,
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, N_PROPERTIES, properties);
+
+ /**
+ * MessagingMenuApp::activate-source:
+ * @mmapp: the #MessagingMenuApp
+ * @source_id: the source id that was activated
+ *
+ * Emitted when the user has activated the message source with id
+ * @source_id. The source is immediately removed from the menu,
+ * handlers of this signal do not need to call
+ * messaging_menu_app_remove_source().
+ */
+ signals[ACTIVATE_SOURCE] = g_signal_new ("activate-source",
+ MESSAGING_MENU_TYPE_APP,
+ G_SIGNAL_RUN_FIRST |
+ G_SIGNAL_DETAILED,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1, G_TYPE_STRING);
+
+ /**
+ * MessagingMenuApp::status-changed:
+ * @mmapp: the #MessagingMenuApp
+ * @status: a #MessagingMenuStatus
+ *
+ * Emitted when the chat status is changed through the messaging menu.
+ *
+ * Applications which are registered to use the chat status should
+ * change their status to @status upon receiving this signal. Call
+ * messaging_menu_app_set_status() to acknowledge that the application
+ * changed its status.
+ */
+ signals[STATUS_CHANGED] = g_signal_new ("status-changed",
+ MESSAGING_MENU_TYPE_APP,
+ G_SIGNAL_RUN_FIRST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__INT,
+ G_TYPE_NONE, 1, G_TYPE_INT);
+}
+
+static void
+created_messages_service (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ MessagingMenuApp *app = user_data;
+ GError *error = NULL;
+
+ app->messages_service = indicator_messages_service_proxy_new_finish (result, &error);
+ if (!app->messages_service)
+ {
+ g_warning ("unable to connect to the mesaging menu service: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ g_signal_connect (app->messages_service, "status-changed",
+ G_CALLBACK (global_status_changed), app);
+
+ /* sync current status */
+ if (app->registered == TRUE)
+ messaging_menu_app_register (app);
+ else if (app->registered == FALSE)
+ messaging_menu_app_unregister (app);
+ if (app->status_set)
+ messaging_menu_app_set_status (app, app->status);
+}
+
+static void
+indicator_messages_appeared (GDBusConnection *bus,
+ const gchar *name,
+ const gchar *name_owner,
+ gpointer user_data)
+{
+ MessagingMenuApp *app = user_data;
+
+ indicator_messages_service_proxy_new (bus,
+ G_DBUS_PROXY_FLAGS_NONE,
+ "com.canonical.indicator.messages",
+ "/com/canonical/indicator/messages/service",
+ app->cancellable,
+ created_messages_service,
+ app);
+}
+
+static void
+indicator_messages_vanished (GDBusConnection *bus,
+ const gchar *name,
+ gpointer user_data)
+{
+ MessagingMenuApp *app = user_data;
+
+ if (app->messages_service)
+ {
+ g_signal_handlers_disconnect_by_func (app->messages_service,
+ global_status_changed,
+ app);
+ g_clear_object (&app->messages_service);
+ }
+}
+
+static void
+messaging_menu_app_init (MessagingMenuApp *app)
+{
+ app->registered = -1;
+ app->status_set = FALSE;
+ app->bus = NULL;
+
+ app->action_export_id = 0;
+ app->menu_export_id = 0;
+
+ app->cancellable = g_cancellable_new ();
+
+ app->source_actions = g_simple_action_group_new ();
+ app->menu = g_menu_new ();
+
+ app->cancellable = g_cancellable_new ();
+
+ app->watch_id = g_bus_watch_name (G_BUS_TYPE_SESSION,
+ "com.canonical.indicator.messages",
+ G_BUS_NAME_WATCHER_FLAGS_NONE,
+ indicator_messages_appeared,
+ indicator_messages_vanished,
+ app,
+ NULL);
+}
+
+/**
+ * messaging_menu_new:
+ * @desktop_id: a desktop file id. See g_desktop_app_info_new()
+ *
+ * Creates a new #MessagingMenuApp for the application associated with
+ * @desktop_id.
+ *
+ * The application will not show up (nor be marked as "running") in the
+ * Messaging Menu before messaging_menu_app_register() has been called.
+ *
+ * Returns: (transfer full): a new #MessagingMenuApp
+ */
+MessagingMenuApp *
+messaging_menu_app_new (const gchar *desktop_id)
+{
+ return g_object_new (MESSAGING_MENU_TYPE_APP,
+ "desktop-id", desktop_id,
+ NULL);
+}
+
+/**
+ * messaging_menu_app_register:
+ * @app: a #MessagingMenuApp
+ *
+ * Registers @app with the Messaging Menu.
+ *
+ * If the application doesn't already have a section in the Messaging
+ * Menu, one will be created for it. The application will also be
+ * marked as "running".
+ *
+ * The application will be marked as "not running" as soon as @app is
+ * destroyed. The application launcher as well as shortcut actions will
+ * remain in the menu. To completely remove the application section
+ * from the Messaging Menu, call messaging_menu_app_unregister().
+ */
+void
+messaging_menu_app_register (MessagingMenuApp *app)
+{
+ gchar *object_path;
+
+ g_return_if_fail (MESSAGING_MENU_IS_APP (app));
+
+ app->registered = TRUE;
+
+ /* state will be synced right after connecting to the service */
+ if (!app->messages_service)
+ 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)),
+ object_path,
+ app->cancellable,
+ NULL, NULL);
+
+ g_free (object_path);
+}
+
+/**
+ * messaging_menu_app_unregister:
+ * @app: a #MessagingMenuApp
+ *
+ * Completely removes the @app from the Messaging Menu. If the
+ * application's launcher and shortcut actions should remain in the
+ * menu, destroying @app with g_object_unref() suffices.
+ *
+ * Note: @app will remain valid and usable after this call.
+ */
+void
+messaging_menu_app_unregister (MessagingMenuApp *app)
+{
+ g_return_if_fail (MESSAGING_MENU_IS_APP (app));
+
+ app->registered = FALSE;
+
+ /* state will be synced right after connecting to the service */
+ 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,
+ NULL, NULL);
+}
+
+/**
+ * messaging_menu_app_set_status:
+ * @app: a #MessagingMenuApp
+ * @status: a #MessagingMenuStatus
+ *
+ * Notify the Messaging Menu that the chat status of @app has changed to
+ * @status.
+ *
+ * Connect to the ::status-changed signal to receive notification about
+ * the user changing their global chat status through the Messaging
+ * Menu.
+ *
+ * This function does nothing for applications whose desktop file does
+ * not include X-MessagingMenu-UsesChatSection.
+ */
+void
+messaging_menu_app_set_status (MessagingMenuApp *app,
+ MessagingMenuStatus status)
+{
+ g_return_if_fail (MESSAGING_MENU_IS_APP (app));
+ g_return_if_fail (status >= MESSAGING_MENU_STATUS_AVAILABLE &&
+ status <= MESSAGING_MENU_STATUS_OFFLINE);
+
+ app->status = status;
+ 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);
+}
+
+static int
+status_from_string (const gchar *s)
+{
+ int i;
+
+ if (!s)
+ return -1;
+
+ for (i = 0; i <= MESSAGING_MENU_STATUS_OFFLINE; i++)
+ {
+ if (g_str_equal (s, status_ids[i]))
+ return i;
+ }
+
+ return -1;
+}
+
+static void
+global_status_changed (IndicatorMessagesService *service,
+ const gchar *status_str,
+ gpointer user_data)
+{
+ MessagingMenuApp *app = user_data;
+ int status;
+
+ status = status_from_string (status_str);
+ g_return_if_fail (status >= 0);
+
+ g_signal_emit (app, signals[STATUS_CHANGED], 0, status);
+}
+
+static void
+source_action_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ MessagingMenuApp *app = user_data;
+ const gchar *name = g_action_get_name (G_ACTION (action));
+ GQuark q = g_quark_from_string (name);
+
+ messaging_menu_app_remove_source (app, name);
+
+ g_signal_emit (app, signals[ACTIVATE_SOURCE], q, name);
+}
+
+static void
+messaging_menu_app_insert_source_action (MessagingMenuApp *app,
+ gint position,
+ const gchar *id,
+ GIcon *icon,
+ const gchar *label,
+ GVariant *state)
+{
+ GSimpleAction *action;
+ GMenuItem *menuitem;
+
+ g_return_if_fail (MESSAGING_MENU_IS_APP (app));
+ g_return_if_fail (id != NULL);
+
+ if (g_simple_action_group_lookup (app->source_actions, id))
+ {
+ g_warning ("a source with id '%s' already exists", id);
+ return;
+ }
+
+ action = g_simple_action_new_stateful (id, NULL, state);
+ g_signal_connect (action, "activate",
+ G_CALLBACK (source_action_activated), app);
+ g_simple_action_group_insert (app->source_actions, G_ACTION (action));
+ g_object_unref (action);
+
+ menuitem = g_menu_item_new (label, id);
+ g_menu_item_set_attribute (menuitem, "x-canonical-type", "s", "ImSourceMenuItem");
+ if (icon)
+ {
+ gchar *iconstr = g_icon_to_string (icon);
+ g_menu_item_set_attribute (menuitem, "x-canonical-icon", "s", iconstr);
+ g_free (iconstr);
+ }
+ g_menu_insert_item (app->menu, position, menuitem);
+ g_object_unref (menuitem);
+}
+
+static GSimpleAction *
+messaging_menu_app_get_source_action (MessagingMenuApp *app,
+ const gchar *source_id)
+
+{
+ GAction *action;
+
+ g_return_val_if_fail (MESSAGING_MENU_IS_APP (app), NULL);
+ g_return_val_if_fail (source_id != NULL, NULL);
+
+ action = g_simple_action_group_lookup (app->source_actions, source_id);
+ if (action == NULL)
+ g_warning ("a source with id '%s' doesn't exist", source_id);
+
+ return G_SIMPLE_ACTION (action);
+}
+
+static void
+messaging_menu_app_set_source_action (MessagingMenuApp *app,
+ const gchar *source_id,
+ guint count,
+ gint64 time,
+ const gchar *string)
+{
+ GSimpleAction *action;
+ GVariant *state;
+ gboolean draws_attention;
+ GVariant *new_state;
+
+ action = messaging_menu_app_get_source_action (app, source_id);
+ if (!action)
+ return;
+
+ state = g_action_get_state (G_ACTION (action));
+ g_variant_get_child (state, 3, "b", &draws_attention);
+
+ new_state = g_variant_new ("(uxsb)", count, time, string, draws_attention);
+ g_simple_action_set_state (action, new_state);
+
+ g_variant_unref (state);
+}
+
+static void
+messaging_menu_app_set_draws_attention (MessagingMenuApp *app,
+ const gchar *source_id,
+ gboolean draws_attention)
+{
+ GSimpleAction *action;
+ GVariant *state;
+ guint count;
+ gint64 time;
+ const gchar *string;
+ GVariant *new_state;
+
+ action = messaging_menu_app_get_source_action (app, source_id);
+ if (!action)
+ return;
+
+ state = g_action_get_state (G_ACTION (action));
+ g_variant_get (state, "(ux&sb)", &count, &time, &string, NULL);
+
+ new_state = g_variant_new ("(uxsb)", count, time, string, TRUE);
+ g_simple_action_set_state (action, new_state);
+
+ g_variant_unref (state);
+}
+
+/**
+ * messaging_menu_app_insert_source:
+ * @app: a #MessagingMenuApp
+ * @position: the position at which to insert the source
+ * @id: a unique identifier for the source to be added
+ * @icon: the icon associated with the source
+ * @label: a user-visible string best describing the source
+ *
+ * Inserts a new message source into the section representing @app. Equivalent
+ * to calling messaging_menu_app_insert_source_with_time() with the current
+ * time.
+ *
+ * It is an error to insert a source with an @id which already exists. Use
+ * messaging_menu_app_has_source() to find out whether there is such a source.
+ */
+void
+messaging_menu_app_insert_source (MessagingMenuApp *app,
+ gint position,
+ const gchar *id,
+ GIcon *icon,
+ const gchar *label)
+{
+ messaging_menu_app_insert_source_with_time (app, position, id, icon, label,
+ g_get_real_time ());
+}
+
+/**
+ * messaging_menu_app_append_source:
+ * @app: a #MessagingMenuApp
+ * @id: a unique identifier for the source to be added
+ * @icon: (allow-none): the icon associated with the source
+ * @label: a user-visible string best describing the source
+ *
+ * Appends a new message source to the end of the section representing @app.
+ * Equivalent to calling messaging_menu_app_append_source_with_time() with the
+ * current time.
+ *
+ * It is an error to add a source with an @id which already exists. Use
+ * messaging_menu_app_has_source() to find out whether there is such a source.
+ */
+void
+messaging_menu_app_append_source (MessagingMenuApp *app,
+ const gchar *id,
+ GIcon *icon,
+ const gchar *label)
+{
+ messaging_menu_app_insert_source (app, -1, id, icon, label);
+}
+
+/**
+ * messaging_menu_app_insert_source_with_count:
+ * @app: a #MessagingMenuApp
+ * @position: the position at which to insert the source
+ * @id: a unique identifier for the source to be added
+ * @icon: (allow-none): the icon associated with the source
+ * @label: a user-visible string best describing the source
+ * @count: the count for the source
+ *
+ * Inserts a new message source into the section representing @app and
+ * initializes it with @count.
+ *
+ * To update the count, use messaging_menu_app_set_source_count().
+ *
+ * It is an error to insert a source with an @id which already exists. Use
+ * messaging_menu_app_has_source() to find out whether there is such a source.
+ */
+void
+messaging_menu_app_insert_source_with_count (MessagingMenuApp *app,
+ gint position,
+ const gchar *id,
+ GIcon *icon,
+ const gchar *label,
+ guint count)
+{
+ messaging_menu_app_insert_source_action (app, position, id, icon, label,
+ g_variant_new ("(uxsb)", count, 0, "", FALSE));
+}
+
+/**
+ * messaging_menu_app_append_source_with_count:
+ * @app: a #MessagingMenuApp
+ * @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
+ * @count: the count for the source
+ *
+ * Appends a new message source to the end of the section representing @app and
+ * initializes it with @count.
+ *
+ * To update the count, use messaging_menu_app_set_source_count().
+ *
+ * It is an error to add a source with an @id which already exists. Use
+ * messaging_menu_app_has_source() to find out whether there is such a source.
+ */
+void messaging_menu_app_append_source_with_count (MessagingMenuApp *app,
+ const gchar *id,
+ GIcon *icon,
+ const gchar *label,
+ guint count)
+{
+ messaging_menu_app_insert_source_with_count (app, -1, id, icon, label, count);
+}
+
+/**
+ * messaging_menu_app_insert_source_with_time:
+ * @app: a #MessagingMenuApp
+ * @position: the position at which to insert the source
+ * @id: a unique identifier for the source to be added
+ * @icon: (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, in microseconds
+ *
+ * Inserts a new message source into the section representing @app and
+ * 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().
+ *
+ * It is an error to insert a source with an @id which already exists. Use
+ * messaging_menu_app_has_source() to find out whether there is such a source.
+ */
+void
+messaging_menu_app_insert_source_with_time (MessagingMenuApp *app,
+ gint position,
+ const gchar *id,
+ GIcon *icon,
+ const gchar *label,
+ gint64 time)
+{
+ messaging_menu_app_insert_source_action (app, position, id, icon, label,
+ g_variant_new ("(uxsb)", 0, time, "", FALSE));
+}
+
+/**
+ * messaging_menu_app_append_source_with_time:
+ * @app: a #MessagingMenuApp
+ * @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, in microseconds
+ *
+ * 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().
+ *
+ * It is an error to insert a source with an @id which already exists. Use
+ * messaging_menu_app_has_source() to find out whether there is such a source.
+ */
+void
+messaging_menu_app_append_source_with_time (MessagingMenuApp *app,
+ const gchar *id,
+ GIcon *icon,
+ const gchar *label,
+ gint64 time)
+{
+ messaging_menu_app_insert_source_with_time (app, -1, id, icon, label, time);
+}
+
+/**
+ * messaging_menu_app_insert_source_with_string:
+ * @app: a #MessagingMenuApp
+ * @position: the position at which to insert the source
+ * @id: a unique identifier for the source to be added
+ * @icon: (allow-none): the icon associated with the source
+ * @label: a user-visible string best describing the source
+ * @str: a string associated with the source
+ *
+ * Inserts a new message source into the section representing @app and
+ * initializes it with @str.
+ *
+ * To update the string, use messaging_menu_app_set_source_string().
+ *
+ * It is an error to insert a source with an @id which already exists. Use
+ * messaging_menu_app_has_source() to find out whether there is such a source.
+ */
+void
+messaging_menu_app_insert_source_with_string (MessagingMenuApp *app,
+ gint position,
+ const gchar *id,
+ GIcon *icon,
+ const gchar *label,
+ const gchar *str)
+{
+ messaging_menu_app_insert_source_action (app, position, id, icon, label,
+ g_variant_new ("(uxsb)", 0, 0, str, FALSE));
+}
+
+/**
+ * messaging_menu_app_append_source_with_string:
+ * @app: a #MessagingMenuApp
+ * @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
+ * @str: a string associated with the source
+ *
+ * Appends a new message source to the end of the section representing @app and
+ * initializes it with @str.
+ *
+ * To update the string, use messaging_menu_app_set_source_string().
+ *
+ * It is an error to insert a source with an @id which already exists. Use
+ * messaging_menu_app_has_source() to find out whether there is such a source.
+ */
+void
+messaging_menu_app_append_source_with_string (MessagingMenuApp *app,
+ const gchar *id,
+ GIcon *icon,
+ const gchar *label,
+ const gchar *str)
+{
+ messaging_menu_app_insert_source_with_string (app, -1, id, icon, label, str);
+}
+
+/**
+ * messaging_menu_app_remove_source:
+ * @app: a #MessagingMenuApp
+ * @source_id: the id of the source to remove
+ *
+ * Removes the source corresponding to @source_id from the menu.
+ */
+void
+messaging_menu_app_remove_source (MessagingMenuApp *app,
+ const gchar *source_id)
+{
+ int n_items;
+ int i;
+
+ g_return_if_fail (MESSAGING_MENU_IS_APP (app));
+ g_return_if_fail (source_id != NULL);
+
+ if (g_simple_action_group_lookup (app->source_actions, source_id) == NULL)
+ return;
+
+ n_items = g_menu_model_get_n_items (G_MENU_MODEL (app->menu));
+ for (i = 0; i < n_items; i++)
+ {
+ gchar *action;
+
+ if (g_menu_model_get_item_attribute (G_MENU_MODEL (app->menu), i,
+ "action", "s", &action))
+ {
+ if (!g_strcmp0 (action, source_id))
+ {
+ g_menu_remove (app->menu, i);
+ break;
+ }
+
+ g_free (action);
+ }
+ }
+
+ g_simple_action_group_remove (app->source_actions, source_id);
+}
+
+/**
+ * messaging_menu_app_has_source:
+ * @app: a #MessagingMenuApp
+ * @source_id: a source id
+ *
+ * Returns: TRUE if there is a source associated with @source_id
+ */
+gboolean
+messaging_menu_app_has_source (MessagingMenuApp *app,
+ const gchar *source_id)
+{
+ g_return_val_if_fail (MESSAGING_MENU_IS_APP (app), FALSE);
+ g_return_val_if_fail (source_id != NULL, FALSE);
+
+ return g_simple_action_group_lookup (app->source_actions, source_id) != NULL;
+}
+
+static GMenuItem *
+g_menu_find_item_with_action (GMenu *menu,
+ const gchar *action,
+ gint *out_pos)
+{
+ gint i;
+ gint n_elements;
+ GMenuItem *item = NULL;
+
+ n_elements = g_menu_model_get_n_items (G_MENU_MODEL (menu));
+
+ for (i = 0; i < n_elements && item == NULL; i++)
+ {
+ GVariant *attr;
+
+ item = g_menu_item_new_from_model (G_MENU_MODEL (menu), i);
+ attr = g_menu_item_get_attribute_value (item, G_MENU_ATTRIBUTE_ACTION, G_VARIANT_TYPE_STRING);
+
+ if (!g_str_equal (action, g_variant_get_string (attr, NULL)))
+ g_clear_object (&item);
+
+ g_variant_unref (attr);
+ }
+
+ if (item && out_pos)
+ *out_pos = i - 1;
+
+ return item;
+}
+
+static void
+g_menu_replace_item (GMenu *menu,
+ gint pos,
+ GMenuItem *item)
+{
+ g_menu_remove (menu, pos);
+ g_menu_insert_item (menu, pos, item);
+}
+
+/**
+ * messaging_menu_app_set_source_label:
+ * @app: a #MessagingMenuApp
+ * @source_id: a source id
+ * @label: the new label for the source
+ *
+ * Changes the label of @source_id to @label.
+ */
+void
+messaging_menu_app_set_source_label (MessagingMenuApp *app,
+ const gchar *source_id,
+ const gchar *label)
+{
+ gint pos;
+ GMenuItem *item;
+
+ g_return_if_fail (MESSAGING_MENU_IS_APP (app));
+ g_return_if_fail (source_id != NULL);
+ g_return_if_fail (label != NULL);
+
+ item = g_menu_find_item_with_action (app->menu, source_id, &pos);
+ if (item == NULL)
+ return;
+
+ g_menu_item_set_attribute (item, G_MENU_ATTRIBUTE_LABEL, "s", label);
+ g_menu_replace_item (app->menu, pos, item);
+
+ g_object_unref (item);
+}
+
+/**
+ * messaging_menu_app_set_source_icon:
+ * @app: a #MessagingMenuApp
+ * @source_id: a source id
+ * @icon: (allow-none): the new icon for the source
+ *
+ * Changes the icon of @source_id to @icon.
+ */
+void
+messaging_menu_app_set_source_icon (MessagingMenuApp *app,
+ const gchar *source_id,
+ GIcon *icon)
+{
+ gint pos;
+ GMenuItem *item;
+
+ g_return_if_fail (MESSAGING_MENU_IS_APP (app));
+ g_return_if_fail (source_id != NULL);
+
+ item = g_menu_find_item_with_action (app->menu, source_id, &pos);
+ if (item == NULL)
+ return;
+
+ if (icon)
+ {
+ gchar *iconstr;
+
+ iconstr = g_icon_to_string (icon);
+ g_menu_item_set_attribute (item, "x-canonical-icon", "s", iconstr);
+
+ g_free (iconstr);
+ }
+ else
+ {
+ g_menu_item_set_attribute_value (item, "x-canonical-icon", NULL);
+ }
+
+ g_menu_replace_item (app->menu, pos, item);
+
+ g_object_unref (item);
+}
+
+/**
+ * messaging_menu_app_set_source_count:
+ * @app: a #MessagingMenuApp
+ * @source_id: a source id
+ * @count: the new count for the source
+ *
+ * Updates the count of @source_id to @count.
+ */
+void messaging_menu_app_set_source_count (MessagingMenuApp *app,
+ const gchar *source_id,
+ guint count)
+{
+ messaging_menu_app_set_source_action (app, source_id, count, 0, "");
+}
+
+/**
+ * messaging_menu_app_set_source_time:
+ * @app: a #MessagingMenuApp
+ * @source_id: a source id
+ * @time: the new time for the source, in microseconds
+ *
+ * Updates the time of @source_id to @time.
+ */
+void
+messaging_menu_app_set_source_time (MessagingMenuApp *app,
+ const gchar *source_id,
+ gint64 time)
+{
+ messaging_menu_app_set_source_action (app, source_id, 0, time, "");
+}
+
+/**
+ * messaging_menu_app_set_source_string:
+ * @app: a #MessagingMenuApp
+ * @source_id: a source id
+ * @str: the new string for the source
+ *
+ * Updates the string displayed next to @source_id to @str.
+ */
+void
+messaging_menu_app_set_source_string (MessagingMenuApp *app,
+ const gchar *source_id,
+ const gchar *str)
+{
+ messaging_menu_app_set_source_action (app, source_id, 0, 0, str);
+}
+
+/**
+ * messaging_menu_app_draw_attention:
+ * @app: a #MessagingMenuApp
+ * @source_id: a source id
+ *
+ * Indicates that @source_id has important unread messages. Currently, this
+ * means that the messaging menu's envelope icon will turn blue.
+ *
+ * Use messaging_menu_app_remove_attention() to stop indicating that the source
+ * needs attention.
+ */
+void
+messaging_menu_app_draw_attention (MessagingMenuApp *app,
+ const gchar *source_id)
+{
+ messaging_menu_app_set_draws_attention (app, source_id, TRUE);
+}
+
+/**
+ * messaging_menu_app_remove_attention:
+ * @app: a #MessagingMenuApp
+ * @source_id: a source id
+ *
+ * Stop indicating that @source_id needs attention.
+ *
+ * This function does not need to be called when the source is removed
+ * with messaging_menu_app_remove_source() or the user has activated the
+ * source.
+ *
+ * Use messaging_menu_app_draw_attention() to make @source_id draw attention
+ * again.
+ */
+void
+messaging_menu_app_remove_attention (MessagingMenuApp *app,
+ const gchar *source_id)
+{
+ messaging_menu_app_set_draws_attention (app, source_id, TRUE);
+}
=== added file 'libmessaging-menu/messaging-menu.h'
--- libmessaging-menu/messaging-menu.h 1970-01-01 00:00:00 +0000
+++ libmessaging-menu/messaging-menu.h 2013-06-07 21:39:23 +0000
@@ -0,0 +1,148 @@
+/*
+ * 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@xxxxxxxxxxxxx>
+ */
+
+#ifndef __messaging_menu_h__
+#define __messaging_menu_h__
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define MESSAGING_MENU_TYPE_APP messaging_menu_app_get_type()
+#define MESSAGING_MENU_APP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), MESSAGING_MENU_TYPE_APP, MessagingMenuApp))
+#define MESSAGING_MENU_APP_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), MESSAGING_MENU_TYPE_APP, MessagingMenuAppClass))
+#define MESSAGING_MENU_IS_APP(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), MESSAGING_MENU_TYPE_APP))
+
+/**
+ * MessagingMenuStatus:
+ * @MESSAGING_MENU_STATUS_AVAILABLE: available
+ * @MESSAGING_MENU_STATUS_AWAY: away
+ * @MESSAGING_MENU_STATUS_BUSY: busy
+ * @MESSAGING_MENU_STATUS_INVISIBLE: invisible
+ * @MESSAGING_MENU_STATUS_OFFLINE: offline
+ *
+ * An enumeration for the possible chat statuses the messaging menu can be in.
+ */
+typedef enum {
+ MESSAGING_MENU_STATUS_AVAILABLE,
+ MESSAGING_MENU_STATUS_AWAY,
+ MESSAGING_MENU_STATUS_BUSY,
+ MESSAGING_MENU_STATUS_INVISIBLE,
+ MESSAGING_MENU_STATUS_OFFLINE
+} MessagingMenuStatus;
+
+
+typedef GObjectClass MessagingMenuAppClass;
+typedef struct _MessagingMenuApp MessagingMenuApp;
+
+GType messaging_menu_app_get_type (void) G_GNUC_CONST;
+
+MessagingMenuApp * messaging_menu_app_new (const gchar *desktop_id);
+
+void messaging_menu_app_register (MessagingMenuApp *app);
+void messaging_menu_app_unregister (MessagingMenuApp *app);
+
+void messaging_menu_app_set_status (MessagingMenuApp *app,
+ MessagingMenuStatus status);
+
+void messaging_menu_app_insert_source (MessagingMenuApp *app,
+ gint position,
+ const gchar *id,
+ GIcon *icon,
+ const gchar *label);
+
+void messaging_menu_app_append_source (MessagingMenuApp *app,
+ const gchar *id,
+ GIcon *icon,
+ const gchar *label);
+
+void messaging_menu_app_insert_source_with_count (MessagingMenuApp *app,
+ gint position,
+ const gchar *id,
+ GIcon *icon,
+ const gchar *label,
+ guint count);
+
+void messaging_menu_app_append_source_with_count (MessagingMenuApp *app,
+ const gchar *id,
+ GIcon *icon,
+ const gchar *label,
+ guint count);
+
+void messaging_menu_app_insert_source_with_time (MessagingMenuApp *app,
+ gint position,
+ const gchar *id,
+ GIcon *icon,
+ const gchar *label,
+ gint64 time);
+
+void messaging_menu_app_append_source_with_time (MessagingMenuApp *app,
+ const gchar *id,
+ GIcon *icon,
+ const gchar *label,
+ gint64 time);
+
+void messaging_menu_app_append_source_with_string (MessagingMenuApp *app,
+ const gchar *id,
+ GIcon *icon,
+ const gchar *label,
+ const gchar *str);
+
+void messaging_menu_app_insert_source_with_string (MessagingMenuApp *app,
+ gint position,
+ const gchar *id,
+ GIcon *icon,
+ const gchar *label,
+ const gchar *str);
+
+void messaging_menu_app_remove_source (MessagingMenuApp *app,
+ const gchar *source_id);
+
+gboolean messaging_menu_app_has_source (MessagingMenuApp *app,
+ const gchar *source_id);
+
+void messaging_menu_app_set_source_label (MessagingMenuApp *app,
+ const gchar *source_id,
+ const gchar *label);
+
+void messaging_menu_app_set_source_icon (MessagingMenuApp *app,
+ const gchar *source_id,
+ GIcon *icon);
+
+void messaging_menu_app_set_source_count (MessagingMenuApp *app,
+ const gchar *source_id,
+ guint count);
+
+void messaging_menu_app_set_source_time (MessagingMenuApp *app,
+ const gchar *source_id,
+ gint64 time);
+
+void messaging_menu_app_set_source_string (MessagingMenuApp *app,
+ const gchar *source_id,
+ const gchar *str);
+
+void messaging_menu_app_draw_attention (MessagingMenuApp *app,
+ const gchar *source_id);
+
+void messaging_menu_app_remove_attention (MessagingMenuApp *app,
+ const gchar *source_id);
+
+G_END_DECLS
+
+#endif
=== added file 'libmessaging-menu/messaging-menu.pc.in'
--- libmessaging-menu/messaging-menu.pc.in 1970-01-01 00:00:00 +0000
+++ libmessaging-menu/messaging-menu.pc.in 2013-06-07 21:39:23 +0000
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@/messaging-menu
+
+Name: Messaging Menu Library
+Description: Messaging Menu client library
+Version: @VERSION@
+Requires: gio-unix-2.0
+Libs: -L${libdir} -lmessaging-menu
+Cflags: -I${includedir}
=== added directory 'm4'
=== added file 'm4/ax_python_module.m4'
--- m4/ax_python_module.m4 1970-01-01 00:00:00 +0000
+++ m4/ax_python_module.m4 2013-06-07 21:39:23 +0000
@@ -0,0 +1,49 @@
+# ===========================================================================
+# http://www.gnu.org/software/autoconf-archive/ax_python_module.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_PYTHON_MODULE(modname[, fatal])
+#
+# DESCRIPTION
+#
+# Checks for Python module.
+#
+# If fatal is non-empty then absence of a module will trigger an error.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Andrew Collier <colliera@xxxxxxxxxx>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 5
+
+AU_ALIAS([AC_PYTHON_MODULE], [AX_PYTHON_MODULE])
+AC_DEFUN([AX_PYTHON_MODULE],[
+ if test -z $PYTHON;
+ then
+ PYTHON="python"
+ fi
+ PYTHON_NAME=`basename $PYTHON`
+ AC_MSG_CHECKING($PYTHON_NAME module: $1)
+ $PYTHON -c "import $1" 2>/dev/null
+ if test $? -eq 0;
+ then
+ AC_MSG_RESULT(yes)
+ eval AS_TR_CPP(HAVE_PYMOD_$1)=yes
+ else
+ AC_MSG_RESULT(no)
+ eval AS_TR_CPP(HAVE_PYMOD_$1)=no
+ #
+ if test -n "$2"
+ then
+ AC_MSG_ERROR(failed to find required module $1)
+ exit 1
+ fi
+ fi
+])
=== added file 'm4/gcov.m4'
--- m4/gcov.m4 1970-01-01 00:00:00 +0000
+++ m4/gcov.m4 2013-06-07 21:39:23 +0000
@@ -0,0 +1,86 @@
+# Checks for existence of coverage tools:
+# * gcov
+# * lcov
+# * genhtml
+# * gcovr
+#
+# Sets ac_cv_check_gcov to yes if tooling is present
+# and reports the executables to the variables LCOV, GCOVR and GENHTML.
+AC_DEFUN([AC_TDD_GCOV],
+[
+ AC_ARG_ENABLE(gcov,
+ AS_HELP_STRING([--enable-gcov],
+ [enable coverage testing with gcov]),
+ [use_gcov=$enableval], [use_gcov=no])
+
+ if test "x$use_gcov" = "xyes"; then
+ # we need gcc:
+ if test "$GCC" != "yes"; then
+ AC_MSG_ERROR([GCC is required for --enable-gcov])
+ fi
+
+ # Check if ccache is being used
+ AC_CHECK_PROG(SHTOOL, shtool, shtool)
+ case `$SHTOOL path $CC` in
+ *ccache*[)] gcc_ccache=yes;;
+ *[)] gcc_ccache=no;;
+ esac
+
+ if test "$gcc_ccache" = "yes" && (test -z "$CCACHE_DISABLE" || test "$CCACHE_DISABLE" != "1"); then
+ AC_MSG_ERROR([ccache must be disabled when --enable-gcov option is used. You can disable ccache by setting environment variable CCACHE_DISABLE=1.])
+ fi
+
+ lcov_version_list="1.6 1.7 1.8 1.9"
+ AC_CHECK_PROG(LCOV, lcov, lcov)
+ AC_CHECK_PROG(GENHTML, genhtml, genhtml)
+
+ if test "$LCOV"; then
+ AC_CACHE_CHECK([for lcov version], glib_cv_lcov_version, [
+ glib_cv_lcov_version=invalid
+ lcov_version=`$LCOV -v 2>/dev/null | $SED -e 's/^.* //'`
+ for lcov_check_version in $lcov_version_list; do
+ if test "$lcov_version" = "$lcov_check_version"; then
+ glib_cv_lcov_version="$lcov_check_version (ok)"
+ fi
+ done
+ ])
+ else
+ lcov_msg="To enable code coverage reporting you must have one of the following lcov versions installed: $lcov_version_list"
+ AC_MSG_ERROR([$lcov_msg])
+ fi
+
+ case $glib_cv_lcov_version in
+ ""|invalid[)]
+ lcov_msg="You must have one of the following versions of lcov: $lcov_version_list (found: $lcov_version)."
+ AC_MSG_ERROR([$lcov_msg])
+ LCOV="exit 0;"
+ ;;
+ esac
+
+ if test -z "$GENHTML"; then
+ AC_MSG_ERROR([Could not find genhtml from the lcov package])
+ fi
+
+ ac_cv_check_gcov=yes
+ ac_cv_check_lcov=yes
+
+ # Remove all optimization flags from CFLAGS
+ changequote({,})
+ CFLAGS=`echo "$CFLAGS" | $SED -e 's/-O[0-9]*//g'`
+ changequote([,])
+
+ # Add the special gcc flags
+ COVERAGE_CFLAGS="-O0 -fprofile-arcs -ftest-coverage"
+ COVERAGE_CXXFLAGS="-O0 -fprofile-arcs -ftest-coverage"
+ COVERAGE_LDFLAGS="-lgcov"
+
+ # Check availability of gcovr
+ AC_CHECK_PROG(GCOVR, gcovr, gcovr)
+ if test -z "$GCOVR"; then
+ ac_cv_check_gcovr=no
+ else
+ ac_cv_check_gcovr=yes
+ fi
+
+fi
+]) # AC_TDD_GCOV
=== added file 'm4/gtest.m4'
--- m4/gtest.m4 1970-01-01 00:00:00 +0000
+++ m4/gtest.m4 2013-06-07 21:39:23 +0000
@@ -0,0 +1,63 @@
+# Copyright (C) 2012 Canonical, Ltd.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+# Checks whether the gtest source is available on the system. Allows for
+# adjusting the include and source path. Sets have_gtest=yes if the source is
+# present. Sets GTEST_CPPFLAGS and GTEST_SOURCE to the preprocessor flags and
+# source location respectively.
+AC_DEFUN([CHECK_GTEST],
+[
+ AC_ARG_WITH([gtest-include-path],
+ [AS_HELP_STRING([--with-gtest-include-path],
+ [location of the Google test headers])],
+ [GTEST_CPPFLAGS="-I$withval"])
+
+ AC_ARG_WITH([gtest-source-path],
+ [AS_HELP_STRING([--with-gtest-source-path],
+ [location of the Google test sources, defaults to /usr/src/gtest])],
+ [GTEST_SOURCE="$withval"],
+ [GTEST_SOURCE="/usr/src/gtest"])
+
+ GTEST_CPPFLAGS="$GTEST_CPPFLAGS -I$GTEST_SOURCE"
+
+ AC_LANG_PUSH([C++])
+
+ tmp_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $GTEST_CPPFLAGS"
+
+ AC_CHECK_HEADER([gtest/gtest.h])
+
+ CPPFLAGS="$tmp_CPPFLAGS"
+
+ AC_LANG_POP
+
+ AC_CHECK_FILES([$GTEST_SOURCE/src/gtest-all.cc]
+ [$GTEST_SOURCE/src/gtest_main.cc],
+ [have_gtest_source=yes],
+ [have_gtest_source=no])
+
+ AS_IF([test "x$ac_cv_header_gtest_gtest_h" = xyes -a \
+ "x$have_gtest_source" = xyes],
+ [have_gtest=yes]
+ [AC_SUBST(GTEST_CPPFLAGS)]
+ [AC_SUBST(GTEST_SOURCE)],
+ [have_gtest=no])
+]) # CHECK_GTEST
=== modified file 'po/POTFILES.in'
--- po/POTFILES.in 2011-07-02 14:42:05 +0000
+++ po/POTFILES.in 2013-06-07 21:39:23 +0000
@@ -1,9 +1,3 @@
[encoding: UTF-8]
-src/messages-service-dbus.c
src/indicator-messages.c
src/messages-service.c
-src/default-applications.c
-src/launcher-menu-item.c
-src/im-menu-item.c
-src/app-menu-item.c
-src/status-items.c
=== added file 'po/indicator-messages.pot'
--- po/indicator-messages.pot 1970-01-01 00:00:00 +0000
+++ po/indicator-messages.pot 2013-06-07 21:39:23 +0000
@@ -0,0 +1,46 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-11-16 14:53+0100\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@xxxxxx>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../src/messages-service.c:329
+msgid "Messages"
+msgstr ""
+
+#: ../src/messages-service.c:552
+msgid "Available"
+msgstr ""
+
+#: ../src/messages-service.c:553
+msgid "Away"
+msgstr ""
+
+#: ../src/messages-service.c:554
+msgid "Busy"
+msgstr ""
+
+#: ../src/messages-service.c:555
+msgid "Invisible"
+msgstr ""
+
+#: ../src/messages-service.c:556
+msgid "Offline"
+msgstr ""
+
+#: ../src/messages-service.c:659
+msgid "Clear"
+msgstr ""
=== modified file 'src/Makefile.am'
--- src/Makefile.am 2011-07-08 19:46:06 +0000
+++ src/Makefile.am 2013-06-07 21:39:23 +0000
@@ -15,262 +15,80 @@
messaginglib_LTLIBRARIES = libmessaging.la
libmessaging_la_SOURCES = \
indicator-messages.c \
- gen-messages-service.xml.h \
- gen-messages-service.xml.c \
+ ido-menu-item.c \
+ ido-menu-item.h \
+ im-app-menu-item.c \
+ 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
libmessaging_la_CFLAGS = \
$(APPLET_CFLAGS) \
+ $(COVERAGE_CFLAGS) \
-Wall \
-Wl,-Bsymbolic-functions \
-Wl,-z,defs \
-Wl,--as-needed \
-Werror \
-DG_LOG_DOMAIN=\"Indicator-Messages\"
-libmessaging_la_LIBADD = $(APPLET_LIBS)
-libmessaging_la_LDFLAGS = -module -avoid-version
+libmessaging_la_LIBADD = $(APPLET_LIBS) -lm
+libmessaging_la_LDFLAGS = \
+ $(COVERAGE_LDFLAGS) \
+ -module -avoid-version
######################################
# Building the messages service
######################################
indicator_messages_service_SOURCES = \
- default-applications.h \
- default-applications.c \
messages-service.c \
- messages-service-dbus.c \
- messages-service-dbus.h \
- gen-messages-service.xml.h \
- gen-messages-service.xml.c \
- im-menu-item.c \
- im-menu-item.h \
- app-menu-item.c \
- app-menu-item.h \
- launcher-menu-item.c \
- launcher-menu-item.h \
- seen-db.c \
- seen-db.h \
- dirs.h \
+ indicator-messages-service.c \
+ indicator-messages-service.h \
+ app-section.c \
+ app-section.h \
dbus-data.h \
- \
- status-items.c \
- status-items.h
+ gactionmuxer.c \
+ gactionmuxer.h \
+ gsettingsstrv.c \
+ gsettingsstrv.h \
+ gmenuutils.c \
+ gmenuutils.h
indicator_messages_service_CFLAGS = \
$(APPLET_CFLAGS) \
+ $(COVERAGE_CFLAGS) \
-Wall \
-Wl,-Bsymbolic-functions \
-Wl,-z,defs \
-Wl,--as-needed \
-Werror \
- -DG_LOG_DOMAIN=\"Indicator-Messages\" \
- -DSTATUS_PROVIDER_DIR=\"$(STATUS_PROVIDER_DIR)\"
+ -DG_LOG_DOMAIN=\"Indicator-Messages\"
indicator_messages_service_LDADD = \
- $(APPLET_LIBS) \
- libindicator-messages-status-provider.la
-
-gen-%.xml.h: %.xml
- @echo "Building $@ from $<"
- @echo "extern const char * _$(subst -,_,$(subst .,_,$(basename $(notdir $<))));" > $@
-
-gen-%.xml.c: %.xml
- @echo "Building $@ from $<"
- echo "const char * _$(subst -,_,$(subst .,_,$(basename $(notdir $<)))) = " > $@
- @sed -e "s:\":\\\\\":g" -e s:^:\": -e s:\$$:\\\\n\": $< >> $@
- @echo ";" >> $@
+ $(APPLET_LIBS)
+
+indicator_messages_service_LDFLAGS = \
+ $(COVERAGE_LDFLAGS)
+
+indicator-messages-service.c: $(top_srcdir)/src/messages-service.xml
+ $(AM_V_GEN) gdbus-codegen \
+ --interface-prefix com.canonical.indicator.messages. \
+ --generate-c-code indicator-messages-service \
+ --c-namespace IndicatorMessages \
+ $^
+indicator-messages-service.h: indicator-messages-service.c
BUILT_SOURCES += \
- gen-messages-service.xml.h \
- gen-messages-service.xml.c
+ indicator-messages-service.c \
+ indicator-messages-service.h
EXTRA_DIST += \
messages-service.xml
-######################################
-# Status Provider Library
-######################################
-
-STATUS_PROVIDER_API_VERSION = 1
-STATUS_PROVIDER_DIR = $(libexecdir)/status-providers/$(STATUS_PROVIDER_API_VERSION)
-statusprovidersdir = $(STATUS_PROVIDER_DIR)
-statusproviders_LTLIBRARIES =
-
-EXTRA_DIST += \
- indicator-messages-status-provider-0.5.pc.in.in
-CLEANFILES += \
- indicator-messages-status-provider-0.5.pc
-
-pkgconfig_DATA = indicator-messages-status-provider-0.5.pc
-pkgconfigdir = $(libdir)/pkgconfig
-
-%.pc: %.pc.in
- sed \
- -e "s|\@status_provider_dir\@|$(STATUS_PROVIDER_DIR)|" \
- -e "s|\@status_provider_api_version\@|$(STATUS_PROVIDER_API_VERSION)|" \
- $< > $@
-
-lib_LTLIBRARIES = \
- libindicator-messages-status-provider.la
-
-libindicator_messages_status_provider_la_HEADERS = \
- status-provider.h
-
-libindicator_messages_status_provider_la_SOURCES = \
- $(libindicator_messages_status_provider_HEADERS) \
- status-provider.c
-
-libindicator_messages_status_provider_ladir = \
- $(includedir)/libindicator-messages-status-provider-$(STATUS_PROVIDER_API_VERSION)/
-
-libindicator_messages_status_provider_la_LDFLAGS = \
- -version-info $(STATUS_PROVIDER_API_VERSION):0:0 \
- -no-undefined \
- -export-symbols-regex "^[^_].*"
-
-libindicator_messages_status_provider_la_LIBADD = \
- $(APPLET_LIBS)
-
-libindicator_messages_status_provider_la_CFLAGS = \
- $(APPLET_CFLAGS) \
- -Wall -Werror
-
-######################################
-# Status provider: Pidgin
-######################################
-
-statusproviders_LTLIBRARIES += libpidgin.la
-libpidgin_la_SOURCES = \
- status-provider-pidgin.h \
- status-provider-pidgin.c \
- status-provider-pidgin-marshal.h \
- status-provider-pidgin-marshal.c
-libpidgin_la_CFLAGS = \
- $(APPLET_CFLAGS) \
- $(STATUS_PROVIDER_PIDGIN_CFLAGS) \
- -Wall -Werror \
- -DG_LOG_DOMAIN=\"Status-Provider-Pidgin\"
-libpidgin_la_LIBADD = \
- libindicator-messages-status-provider.la \
- $(APPLET_LIBS) \
- $(STATUS_PROVIDER_PIDGIN_LIBS)
-libpidgin_la_LDFLAGS = -module -avoid-version
-
-status-provider-pidgin-marshal.h: $(srcdir)/status-provider-pidgin.list
- glib-genmarshal --header \
- --prefix=_status_provider_pidgin_marshal $(srcdir)/status-provider-pidgin.list \
- > status-provider-pidgin-marshal.h
-
-status-provider-pidgin-marshal.c: $(srcdir)/status-provider-pidgin.list
- glib-genmarshal --body \
- --prefix=_status_provider_pidgin_marshal $(srcdir)/status-provider-pidgin.list \
- > status-provider-pidgin-marshal.c
-
-BUILT_SOURCES += \
- status-provider-pidgin-marshal.h \
- status-provider-pidgin-marshal.c
-
-EXTRA_DIST += \
- status-provider-pidgin.list
-
-######################################
-# Status provider: Mission Control 4
-######################################
-
-statusproviders_LTLIBRARIES += libtelepathy.la
-libtelepathy_la_SOURCES = \
- status-provider-telepathy.h \
- status-provider-telepathy.c \
- status-provider-telepathy-marshal.h \
- status-provider-telepathy-marshal.c
-libtelepathy_la_CFLAGS = \
- $(APPLET_CFLAGS) \
- $(STATUS_PROVIDER_TELEPATHY_CFLAGS) \
- -Wall -Werror \
- -DG_LOG_DOMAIN=\"Status-Provider-Telepathy\"
-libtelepathy_la_LIBADD = \
- libindicator-messages-status-provider.la \
- $(APPLET_LIBS) \
- $(STATUS_PROVIDER_TELEPATHY_LIBS)
-libtelepathy_la_LDFLAGS = -module -avoid-version
-
-status-provider-telepathy-marshal.h: $(srcdir)/status-provider-telepathy.list
- glib-genmarshal --header \
- --prefix=_status_provider_telepathy_marshal $(srcdir)/status-provider-telepathy.list \
- > status-provider-telepathy-marshal.h
-
-status-provider-telepathy-marshal.c: $(srcdir)/status-provider-telepathy.list
- glib-genmarshal --body \
- --prefix=_status_provider_telepathy_marshal $(srcdir)/status-provider-telepathy.list \
- > status-provider-telepathy-marshal.c
-
-BUILT_SOURCES += \
- status-provider-telepathy-marshal.h \
- status-provider-telepathy-marshal.c
-
-EXTRA_DIST += \
- status-provider-telepathy.list
-
-######################################
-# Status provider: Mission Control 5
-######################################
-
-statusproviders_LTLIBRARIES += libmc5.la
-libmc5_la_SOURCES = \
- status-provider-mc5.h \
- status-provider-mc5.c \
- status-provider-mc5-marshal.h \
- status-provider-mc5-marshal.c
-libmc5_la_CFLAGS = \
- $(APPLET_CFLAGS) \
- $(STATUS_PROVIDER_MC5_CFLAGS) \
- -Wall -Werror \
- -DG_LOG_DOMAIN=\"Status-Provider-MC5\"
-libmc5_la_LIBADD = \
- libindicator-messages-status-provider.la \
- $(APPLET_LIBS) \
- $(STATUS_PROVIDER_MC5_LIBS)
-libmc5_la_LDFLAGS = -module -avoid-version
-
-status-provider-mc5-marshal.h: $(srcdir)/status-provider-mc5.list
- glib-genmarshal --header \
- --prefix=_status_provider_mc5_marshal $(srcdir)/status-provider-mc5.list \
- > status-provider-mc5-marshal.h
-
-status-provider-mc5-marshal.c: $(srcdir)/status-provider-mc5.list
- glib-genmarshal --body \
- --prefix=_status_provider_mc5_marshal $(srcdir)/status-provider-mc5.list \
- > status-provider-mc5-marshal.c
-
-BUILT_SOURCES += \
- status-provider-mc5-marshal.h \
- status-provider-mc5-marshal.c
-
-EXTRA_DIST += \
- status-provider-mc5.list
-
-######################################
-# Status provider: Emesene
-######################################
-
-statusproviders_LTLIBRARIES += libemesene.la
-libemesene_la_SOURCES = \
- status-provider-emesene.h \
- status-provider-emesene.c
-libemesene_la_CFLAGS = \
- $(APPLET_CFLAGS) \
- $(STATUS_PROVIDER_EMESENE_CFLAGS) \
- -Wall -Werror \
- -DG_LOG_DOMAIN=\"Status-Provider-Emesene\"
-libemesene_la_LIBADD = \
- libindicator-messages-status-provider.la \
- $(APPLET_LIBS) \
- $(STATUS_PROVIDER_EMESENE_LIBS)
-libemesene_la_LDFLAGS = -module -avoid-version
-
-######################################
-# Extras
-######################################
-
CLEANFILES += \
$(BUILT_SOURCES)
=== renamed file 'src/app-menu-item.c' => 'src/app-section.c'
--- src/app-menu-item.c 2011-04-06 16:24:05 +0000
+++ src/app-section.c 2013-06-07 21:39:23 +0000
@@ -2,9 +2,10 @@
An indicator to show information that is in messaging applications
that the user is using.
-Copyright 2009 Canonical Ltd.
+Copyright 2012 Canonical Ltd.
Authors:
+ Lars Uebernickel <lars.uebernickel@xxxxxxxxxxxxx>
Ted Gould <ted@xxxxxxxxxxxxx>
This program is free software: you can redistribute it and/or modify it
@@ -26,554 +27,790 @@
#include <glib/gi18n.h>
#include <gio/gdesktopappinfo.h>
-#include <libdbusmenu-glib/client.h>
-#include <libdbusmenu-glib/menuitem-proxy.h>
-#include "app-menu-item.h"
+#include <gio/gio.h>
+#include <libindicator/indicator-desktop-shortcuts.h>
+#include "app-section.h"
#include "dbus-data.h"
-#include "default-applications.h"
-#include "seen-db.h"
+#include "gmenuutils.h"
+#include "gactionmuxer.h"
+
+struct _AppSectionPrivate
+{
+ GDesktopAppInfo * appinfo;
+ GFileMonitor *desktop_file_monitor;
+
+ IndicatorDesktopShortcuts * ids;
+
+ GMenu *menu;
+ GMenuModel *source_menu;
+
+ GSimpleActionGroup *static_shortcuts;
+ GActionGroup *source_actions;
+ GActionMuxer *muxer;
+
+ gboolean draws_attention;
+ gboolean uses_chat_status;
+ gchar *chat_status;
+
+ guint name_watch_id;
+};
enum {
- COUNT_CHANGED,
- NAME_CHANGED,
- SHORTCUT_ADDED,
- SHORTCUT_REMOVED,
- LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL] = { 0 };
-
-typedef struct _AppMenuItemPrivate AppMenuItemPrivate;
-
-struct _AppMenuItemPrivate
-{
- IndicateListener * listener;
- IndicateListenerServer * server;
-
- gchar * type;
- GAppInfo * appinfo;
- GKeyFile * keyfile;
- gchar * desktop;
- guint unreadcount;
-
- DbusmenuClient * client;
- DbusmenuMenuitem * root;
- GList * shortcuts;
-};
-
-#define APP_MENU_ITEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), APP_MENU_ITEM_TYPE, AppMenuItemPrivate))
+ PROP_0,
+ PROP_APPINFO,
+ 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_menu_item_class_init (AppMenuItemClass *klass);
-static void app_menu_item_init (AppMenuItem *self);
-static void app_menu_item_dispose (GObject *object);
-static void app_menu_item_finalize (GObject *object);
-static void activate_cb (AppMenuItem * self, guint timestamp, gpointer data);
-static void count_changed (IndicateListener * listener, IndicateListenerServer * server, guint count, gpointer data);
-static void count_cb (IndicateListener * listener, IndicateListenerServer * server, guint value, gpointer data);
-static void menu_cb (IndicateListener * listener, IndicateListenerServer * server, const gchar * menupath, gpointer data);
-static void desktop_cb (IndicateListener * listener, IndicateListenerServer * server, const gchar * value, gpointer data);
-static void update_label (AppMenuItem * self);
+static void app_section_class_init (AppSectionClass *klass);
+static void app_section_init (AppSection *self);
+static void app_section_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void app_section_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void app_section_dispose (GObject *object);
+static void app_section_finalize (GObject *object);
+static void activate_cb (GSimpleAction *action,
+ GVariant *param,
+ gpointer userdata);
+static void launch_action_change_state (GSimpleAction *action,
+ GVariant *value,
+ gpointer user_data);
+static void app_section_set_app_info (AppSection *self,
+ GDesktopAppInfo *appinfo);
+static gboolean any_action_draws_attention (GActionGroup *group,
+ const gchar *ignored_action);
+static void action_added (GActionGroup *group,
+ const gchar *action_name,
+ gpointer user_data);
+static void action_state_changed (GActionGroup *group,
+ const gchar *action_name,
+ GVariant *value,
+ gpointer user_data);
+static void action_removed (GActionGroup *group,
+ const gchar *action_name,
+ gpointer user_data);
+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 (AppMenuItem, app_menu_item, DBUSMENU_TYPE_MENUITEM);
+G_DEFINE_TYPE (AppSection, app_section, G_TYPE_OBJECT);
static void
-app_menu_item_class_init (AppMenuItemClass *klass)
+app_section_class_init (AppSectionClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
- g_type_class_add_private (klass, sizeof (AppMenuItemPrivate));
-
- object_class->dispose = app_menu_item_dispose;
- object_class->finalize = app_menu_item_finalize;
-
- signals[COUNT_CHANGED] = g_signal_new(APP_MENU_ITEM_SIGNAL_COUNT_CHANGED,
- G_TYPE_FROM_CLASS(klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (AppMenuItemClass, count_changed),
- NULL, NULL,
- g_cclosure_marshal_VOID__UINT,
- G_TYPE_NONE, 1, G_TYPE_UINT);
- signals[NAME_CHANGED] = g_signal_new(APP_MENU_ITEM_SIGNAL_NAME_CHANGED,
- G_TYPE_FROM_CLASS(klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (AppMenuItemClass, name_changed),
- NULL, NULL,
- g_cclosure_marshal_VOID__STRING,
- G_TYPE_NONE, 1, G_TYPE_STRING);
- signals[SHORTCUT_ADDED] = g_signal_new(APP_MENU_ITEM_SIGNAL_SHORTCUT_ADDED,
- G_TYPE_FROM_CLASS(klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (AppMenuItemClass, shortcut_added),
- NULL, NULL,
- g_cclosure_marshal_VOID__OBJECT,
- G_TYPE_NONE, 1, G_TYPE_OBJECT);
- signals[SHORTCUT_REMOVED] = g_signal_new(APP_MENU_ITEM_SIGNAL_SHORTCUT_REMOVED,
- G_TYPE_FROM_CLASS(klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (AppMenuItemClass, shortcut_removed),
- NULL, NULL,
- g_cclosure_marshal_VOID__OBJECT,
- G_TYPE_NONE, 1, G_TYPE_OBJECT);
-
- return;
+ g_type_class_add_private (klass, sizeof (AppSectionPrivate));
+
+ object_class->get_property = app_section_get_property;
+ object_class->set_property = app_section_set_property;
+ object_class->dispose = app_section_dispose;
+ object_class->finalize = app_section_finalize;
+
+ properties[PROP_APPINFO] = g_param_spec_object ("app-info",
+ "AppInfo",
+ "The GAppInfo for the app that this menu represents",
+ G_TYPE_APP_INFO,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+
+ properties[PROP_ACTIONS] = g_param_spec_object ("actions",
+ "Actions",
+ "The actions exported by this application",
+ G_TYPE_ACTION_GROUP,
+ G_PARAM_READABLE);
+
+ properties[PROP_DRAWS_ATTENTION] = g_param_spec_boolean ("draws-attention",
+ "Draws attention",
+ "Whether the section currently draws attention",
+ FALSE,
+ G_PARAM_READABLE);
+
+ properties[PROP_USES_CHAT_STATUS] = g_param_spec_boolean ("uses-chat-status",
+ "Uses chat status",
+ "Whether the section uses the global chat status",
+ FALSE,
+ G_PARAM_READABLE);
+
+ 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
-app_menu_item_init (AppMenuItem *self)
+app_section_init (AppSection *self)
{
- g_debug("Building new App Menu Item");
- AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self);
-
- priv->listener = NULL;
- priv->server = NULL;
- priv->type = NULL;
+ AppSectionPrivate *priv;
+
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ APP_SECTION_TYPE,
+ AppSectionPrivate);
+ priv = self->priv;
+
priv->appinfo = NULL;
- priv->keyfile = NULL;
- priv->desktop = NULL;
- priv->unreadcount = 0;
-
- priv->client = NULL;
- priv->root = NULL;
- priv->shortcuts = NULL;
-
- dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
-
- return;
-}
-
-/* A wrapper to make the prototypes work for GFunc */
-static void
-func_unref (gpointer data, gpointer user_data)
-{
- g_signal_emit(user_data, signals[SHORTCUT_REMOVED], 0, data, TRUE);
- g_object_unref(G_OBJECT(data));
- return;
-}
-
-/* Disconnect the count_changed signal and unref the listener */
-static void
-app_menu_item_dispose (GObject *object)
-{
- AppMenuItem * self = APP_MENU_ITEM(object);
- AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self);
-
- if (priv->listener != NULL) {
- g_signal_handlers_disconnect_by_func(G_OBJECT(priv->listener), count_changed, self);
- g_object_unref(priv->listener);
- priv->listener = NULL;
- }
-
- if (priv->shortcuts != NULL) {
- g_list_foreach(priv->shortcuts, func_unref, object);
- g_list_free(priv->shortcuts);
- priv->shortcuts = NULL;
- }
-
- if (priv->root != NULL) {
- g_object_unref(priv->root);
- priv->root = NULL;
- }
-
- if (priv->client != NULL) {
- g_object_unref(priv->client);
- priv->client = NULL;
- }
-
- if (priv->appinfo != NULL) {
- g_object_unref(priv->appinfo);
- priv->appinfo = NULL;
- }
-
- if (priv->keyfile != NULL) {
- g_object_unref(priv->keyfile);
- priv->keyfile = NULL;
- }
-
- G_OBJECT_CLASS (app_menu_item_parent_class)->dispose (object);
-}
-
-/* Free the memory used by our type, desktop file and application
- info structures. */
-static void
-app_menu_item_finalize (GObject *object)
-{
- AppMenuItem * self = APP_MENU_ITEM(object);
- AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self);
-
- if (priv->type != NULL) {
- g_free(priv->type);
- priv->type = NULL;
- }
-
- if (priv->desktop != NULL) {
- g_free(priv->desktop);
- priv->desktop = NULL;
- }
-
- G_OBJECT_CLASS (app_menu_item_parent_class)->finalize (object);
-
- return;
-}
-
-AppMenuItem *
-app_menu_item_new (IndicateListener * listener, IndicateListenerServer * server)
-{
- AppMenuItem * self = g_object_new(APP_MENU_ITEM_TYPE, NULL);
-
- AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self);
-
- /* Copy the listener so we can use it later */
- priv->listener = listener;
- g_object_ref(G_OBJECT(listener));
-
- /* Can not ref as not real GObject */
- priv->server = server;
-
- dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_TYPE, APPLICATION_MENUITEM_TYPE);
-
- /* Set up listener signals */
- g_signal_connect(G_OBJECT(listener), INDICATE_LISTENER_SIGNAL_SERVER_COUNT_CHANGED, G_CALLBACK(count_changed), self);
-
- /* Get the values we care about from the server */
- indicate_listener_server_get_desktop(listener, server, desktop_cb, self);
- indicate_listener_server_get_count(listener, server, count_cb, self);
- indicate_listener_server_get_menu(listener, server, menu_cb, self);
-
- g_signal_connect(G_OBJECT(self), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(activate_cb), NULL);
-
- indicate_listener_server_show_interest(listener, server, INDICATE_INTEREST_SERVER_DISPLAY);
- indicate_listener_server_show_interest(listener, server, INDICATE_INTEREST_SERVER_SIGNAL);
- indicate_listener_server_show_interest(listener, server, INDICATE_INTEREST_INDICATOR_COUNT);
- indicate_listener_server_show_interest(listener, server, INDICATE_INTEREST_INDICATOR_DISPLAY);
- indicate_listener_server_show_interest(listener, server, INDICATE_INTEREST_INDICATOR_SIGNAL);
- indicate_listener_set_server_max_indicators(listener, server, MAX_NUMBER_OF_INDICATORS);
-
- return self;
-}
-
-static void
-update_label (AppMenuItem * self)
-{
- AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self);
- const gchar * name = get_default_name(priv->desktop);
-
- if (name == NULL) {
- name = app_menu_item_get_name(self);
- }
-
- if (priv->unreadcount > 0) {
- /* TRANSLATORS: This is the name of the program and the number of indicators. So it
- would read something like "Mail Client (5)" */
- gchar * label = g_strdup_printf(_("%s (%d)"), _(name), priv->unreadcount);
- dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), APPLICATION_MENUITEM_PROP_NAME, label);
- g_free(label);
- } else {
- dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), APPLICATION_MENUITEM_PROP_NAME, _(name));
- }
-
- return;
-}
-
-/* Callback to the signal that the server count
- has changed to a new value. This checks to see if
- it's actually changed and if so signals everyone and
- updates the label. */
-static void
-count_changed (IndicateListener * listener, IndicateListenerServer * server, guint count, gpointer data)
-{
- g_return_if_fail(IS_APP_MENU_ITEM(data));
- AppMenuItem * self = APP_MENU_ITEM(data);
- AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self);
-
- if (priv->unreadcount != count) {
- priv->unreadcount = count;
- update_label(self);
- g_signal_emit(G_OBJECT(self), signals[COUNT_CHANGED], 0, priv->unreadcount, TRUE);
- }
-
- return;
-}
-
-/* Callback for getting the count property off
- of the server. */
-static void
-count_cb (IndicateListener * listener, IndicateListenerServer * server, guint value, gpointer data)
-{
- count_changed(listener, server, value, data);
- return;
-}
-
-/* Callback for when we ask the server for the path
- to it's desktop file. We then turn it into an
- app structure and start sucking data out of it.
- Mostly the name. And the icon. */
-static void
-desktop_cb (IndicateListener * listener, IndicateListenerServer * server, const gchar * value, gpointer data)
-{
- g_return_if_fail(IS_APP_MENU_ITEM(data));
- AppMenuItem * self = APP_MENU_ITEM(data);
- AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self);
-
- if (priv->appinfo != NULL) {
- g_object_unref(G_OBJECT(priv->appinfo));
- priv->appinfo = NULL;
- }
-
- if (priv->desktop != NULL) {
- g_free(priv->desktop);
- priv->desktop = NULL;
- }
-
- if (value == NULL || value[0] == '\0') {
- return;
- }
-
- seen_db_add(value);
-
- priv->appinfo = G_APP_INFO(g_desktop_app_info_new_from_filename(value));
- g_return_if_fail(priv->appinfo != NULL);
-
- priv->keyfile = g_key_file_new();
- g_key_file_load_from_file(priv->keyfile, value, G_KEY_FILE_NONE, NULL);
-
- priv->desktop = g_strdup(value);
-
- dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
- dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(self), APPLICATION_MENUITEM_PROP_RUNNING, TRUE);
-
- update_label(self);
-
- const gchar * def_icon = get_default_icon(priv->desktop);
- if (def_icon == NULL) {
- gchar * iconstr = NULL;
-
- /* Check for the over ride key and see if we should be using that
- icon. If we can't get it, then go back to the app info */
- if (g_key_file_has_key(priv->keyfile, G_KEY_FILE_DESKTOP_GROUP, ICON_KEY, NULL) && iconstr == NULL) {
- GError * error = NULL;
-
- iconstr = g_key_file_get_string(priv->keyfile, G_KEY_FILE_DESKTOP_GROUP, ICON_KEY, &error);
-
- if (error != NULL) {
- /* Can't figure out why this would happen, but sure, let's print something */
- g_warning("Error getting '" ICON_KEY "' from desktop file: %s", error->message);
- g_error_free(error);
- }
- }
-
- /* For some reason that didn't work, let's try the app info */
- if (iconstr == NULL) {
- GIcon * icon = g_app_info_get_icon(priv->appinfo);
- iconstr = g_icon_to_string(icon);
- }
-
- dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), APPLICATION_MENUITEM_PROP_ICON, iconstr);
- g_free(iconstr);
- } else {
- dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), APPLICATION_MENUITEM_PROP_ICON, def_icon);
- }
-
- g_signal_emit(G_OBJECT(self), signals[NAME_CHANGED], 0, app_menu_item_get_name(self), TRUE);
-
- return;
-}
-
-/* Relay this signal into causing a rebuild of the shortcuts
- from those above us. */
-static void
-child_added_cb (DbusmenuMenuitem * root, DbusmenuMenuitem * child, guint position, gpointer data)
-{
- g_return_if_fail(IS_APP_MENU_ITEM(data));
- AppMenuItem * self = APP_MENU_ITEM(data);
- AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self);
- DbusmenuMenuitemProxy * mip = dbusmenu_menuitem_proxy_new(child);
-
- priv->shortcuts = g_list_insert(priv->shortcuts, mip, position);
-
- g_signal_emit(G_OBJECT(data), signals[SHORTCUT_ADDED], 0, mip, TRUE);
- return;
-}
-
-/* Relay this signal into causing a rebuild of the shortcuts
- from those above us. */
-static void
-child_removed_cb (DbusmenuMenuitem * root, DbusmenuMenuitem * child, gpointer data)
-{
- g_return_if_fail(IS_APP_MENU_ITEM(data));
- AppMenuItem * self = APP_MENU_ITEM(data);
- AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self);
-
- GList * pitems = priv->shortcuts;
- while (pitems != NULL) {
- DbusmenuMenuitemProxy * mip = DBUSMENU_MENUITEM_PROXY(pitems->data);
-
- if (dbusmenu_menuitem_proxy_get_wrapped(mip) == child) {
- break;
- }
-
- pitems = g_list_next(pitems);
- }
-
- if (pitems != NULL) {
- DbusmenuMenuitemProxy * mip = DBUSMENU_MENUITEM_PROXY(pitems->data);
- priv->shortcuts = g_list_remove(priv->shortcuts, mip);
-
- g_signal_emit(G_OBJECT(data), signals[SHORTCUT_REMOVED], 0, mip, TRUE);
- g_object_unref(mip);
- }
-
- return;
-}
-
-/* Relay this signal into causing a rebuild of the shortcuts
- from those above us. */
-static void
-child_moved_cb (DbusmenuMenuitem * root, DbusmenuMenuitem * child, guint newpos, guint oldpos, gpointer data)
-{
- g_return_if_fail(IS_APP_MENU_ITEM(data));
- AppMenuItem * self = APP_MENU_ITEM(data);
- AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self);
-
- DbusmenuMenuitemProxy * mip = DBUSMENU_MENUITEM_PROXY(g_list_nth_data(priv->shortcuts, oldpos));
-
- if (mip != NULL) {
- if (dbusmenu_menuitem_proxy_get_wrapped(mip) != child) {
- mip = NULL;
- }
- }
-
- if (mip != NULL) {
- priv->shortcuts = g_list_remove(priv->shortcuts, mip);
- priv->shortcuts = g_list_insert(priv->shortcuts, mip, newpos);
- g_signal_emit(G_OBJECT(data), signals[SHORTCUT_ADDED], 0, NULL, TRUE);
- }
-
- return;
-}
-
-/* We've got a new root. We need to proxy it and handle it's children
- if that's a relevant thing to do. */
-static void
-root_changed (DbusmenuClient * client, DbusmenuMenuitem * newroot, gpointer data)
-{
- g_debug("Root Changed");
- AppMenuItem * self = APP_MENU_ITEM(data);
- AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self);
-
- if (priv->root != NULL) {
- if (dbusmenu_menuitem_get_children(DBUSMENU_MENUITEM(priv->root)) != NULL) {
- g_list_foreach(priv->shortcuts, func_unref, data);
- g_list_free(priv->shortcuts);
- priv->shortcuts = NULL;
- }
- g_object_unref(priv->root);
- priv->root = NULL;
- }
-
- /* We need to proxy the new root across to the old
- world of indicator land. */
- priv->root = newroot;
-
- if (priv->root != NULL) {
- g_object_ref(priv->root);
- g_signal_connect(G_OBJECT(priv->root), DBUSMENU_MENUITEM_SIGNAL_CHILD_ADDED, G_CALLBACK(child_added_cb), self);
- g_signal_connect(G_OBJECT(priv->root), DBUSMENU_MENUITEM_SIGNAL_CHILD_REMOVED, G_CALLBACK(child_removed_cb), self);
- g_signal_connect(G_OBJECT(priv->root), DBUSMENU_MENUITEM_SIGNAL_CHILD_MOVED, G_CALLBACK(child_moved_cb), self);
-
- /* See if we have any menuitems to worry about,
- otherwise we'll just move along. */
- GList * children = dbusmenu_menuitem_get_children(DBUSMENU_MENUITEM(priv->root));
- if (children != NULL) {
- g_debug("\tProcessing %d children", g_list_length(children));
- while (children != NULL) {
- DbusmenuMenuitemProxy * mip = dbusmenu_menuitem_proxy_new(DBUSMENU_MENUITEM(children->data));
- priv->shortcuts = g_list_append(priv->shortcuts, mip);
- g_signal_emit(G_OBJECT(self), signals[SHORTCUT_ADDED], 0, mip, TRUE);
- children = g_list_next(children);
- }
- }
- }
-
- return;
-}
-
-/* Gets the path to menuitems if there are some. Now we need to
- make them special. */
-static void
-menu_cb (IndicateListener * listener, IndicateListenerServer * server, const gchar * menupath, gpointer data)
-{
- g_debug("Got Menu: %s", menupath);
- g_return_if_fail(IS_APP_MENU_ITEM(data));
- AppMenuItem * self = APP_MENU_ITEM(data);
- AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self);
-
- priv->client = dbusmenu_client_new(indicate_listener_server_get_dbusname(server), menupath);
- g_signal_connect(G_OBJECT(priv->client), DBUSMENU_CLIENT_SIGNAL_ROOT_CHANGED, G_CALLBACK(root_changed), self);
-
- DbusmenuMenuitem * root = dbusmenu_client_get_root(priv->client);
- if (root != NULL) {
- root_changed(priv->client, root, self);
- }
-
- return;
-}
-
-static void
-activate_cb (AppMenuItem * self, guint timestamp, gpointer data)
-{
- AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self);
-
- indicate_listener_display(priv->listener, priv->server, NULL, timestamp);
-
- return;
-}
-
-guint
-app_menu_item_get_count (AppMenuItem * appitem)
-{
- g_return_val_if_fail(IS_APP_MENU_ITEM(appitem), 0);
- AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(appitem);
-
- return priv->unreadcount;
-}
-
-IndicateListenerServer *
-app_menu_item_get_server (AppMenuItem * appitem) {
- g_return_val_if_fail(IS_APP_MENU_ITEM(appitem), NULL);
- AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(appitem);
-
- return priv->server;
-}
-
-const gchar *
-app_menu_item_get_name (AppMenuItem * appitem)
-{
- g_return_val_if_fail(IS_APP_MENU_ITEM(appitem), NULL);
- AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(appitem);
-
- if (priv->appinfo == NULL) {
- return INDICATE_LISTENER_SERVER_DBUS_NAME(priv->server);
- } else {
- return g_app_info_get_name(priv->appinfo);
- }
-}
-
-const gchar *
-app_menu_item_get_desktop (AppMenuItem * appitem)
-{
- g_return_val_if_fail(IS_APP_MENU_ITEM(appitem), NULL);
- AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(appitem);
- return priv->desktop;
-}
-
-/* Get the dynamic items added onto the end of
- and app entry. */
-GList *
-app_menu_item_get_items (AppMenuItem * appitem)
-{
- g_return_val_if_fail(IS_APP_MENU_ITEM(appitem), NULL);
- AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(appitem);
- return priv->shortcuts;
+
+ priv->menu = g_menu_new ();
+ priv->static_shortcuts = g_simple_action_group_new ();
+
+ priv->muxer = g_action_muxer_new ();
+ g_action_muxer_insert (priv->muxer, NULL, G_ACTION_GROUP (priv->static_shortcuts));
+
+ priv->draws_attention = FALSE;
+
+ return;
+}
+
+static void
+app_section_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ AppSection *self = APP_SECTION (object);
+
+ switch (property_id)
+ {
+ case PROP_APPINFO:
+ g_value_set_object (value, app_section_get_app_info (self));
+ break;
+
+ case PROP_DRAWS_ATTENTION:
+ g_value_set_boolean (value, app_section_get_draws_attention (self));
+ break;
+
+ case PROP_USES_CHAT_STATUS:
+ g_value_set_boolean (value, app_section_get_uses_chat_status (self));
+ break;
+
+ 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);
+ }
+}
+
+static void
+app_section_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ AppSection *self = APP_SECTION (object);
+
+ switch (property_id)
+ {
+ case PROP_APPINFO:
+ app_section_set_app_info (self, g_value_get_object (value));
+ break;
+
+ 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);
+
+ if (priv->name_watch_id) {
+ g_bus_unwatch_name (priv->name_watch_id);
+ priv->name_watch_id = 0;
+ }
+
+ if (priv->source_actions) {
+ g_action_muxer_remove (priv->muxer, "source");
+ g_object_disconnect (priv->source_actions,
+ "any_signal::action-added", action_added, self,
+ "any_signal::action-state-changed", action_state_changed, self,
+ "any_signal::action-removed", action_removed, self,
+ NULL);
+ g_clear_object (&priv->source_actions);
+ }
+
+ g_clear_object (&priv->muxer);
+
+ g_clear_object (&priv->source_menu);
+ g_clear_object (&priv->ids);
+ g_clear_object (&priv->appinfo);
+
+ 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,
+ GVariant *param,
+ gpointer userdata)
+{
+ const gchar * nick = g_action_get_name (G_ACTION (action));
+ AppSection * mi = APP_SECTION (userdata);
+ AppSectionPrivate * priv = mi->priv;
+
+ g_return_if_fail(priv->ids != NULL);
+
+ if (!indicator_desktop_shortcuts_nick_exec(priv->ids, nick)) {
+ g_warning("Unable to execute nick '%s' for desktop file '%s'",
+ nick, g_desktop_app_info_get_filename (priv->appinfo));
+ }
+}
+
+static void
+keyfile_loaded (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ AppSection *self = user_data;
+ gchar *contents;
+ gsize length;
+ GKeyFile *keyfile;
+ GError *error = NULL;
+
+ if (!g_file_load_contents_finish (G_FILE (source_object), result,
+ &contents, &length, NULL, &error)) {
+ g_warning ("could not read key file: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ keyfile = g_key_file_new ();
+ if (!g_key_file_load_from_data (keyfile, contents, length, 0, &error)) {
+ g_warning ("could not read key file: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ self->priv->uses_chat_status = g_key_file_get_boolean (keyfile,
+ G_KEY_FILE_DESKTOP_GROUP,
+ "X-MessagingMenu-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",
+ error->message);
+ }
+ g_error_free (error);
+ goto out;
+ }
+
+out:
+ g_key_file_free (keyfile);
+ g_free (contents);
+}
+
+static void
+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_menu_clear (priv->menu);
+ g_simple_action_group_clear (priv->static_shortcuts);
+
+ 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));
+
+ item = g_menu_item_new (g_app_info_get_name (G_APP_INFO (priv->appinfo)), "launch");
+ g_menu_item_set_attribute (item, "x-canonical-type", "s", "ImAppMenuItem");
+ iconstr = g_icon_to_string (g_app_info_get_icon (G_APP_INFO (priv->appinfo)));
+ g_menu_item_set_attribute (item, "x-canonical-icon", "s", iconstr);
+ g_free (iconstr);
+
+ g_menu_append_item (priv->menu, item);
+ g_object_unref (item);
+
+ /* Start to build static shortcuts */
+ priv->ids = indicator_desktop_shortcuts_new(g_desktop_app_info_get_filename (priv->appinfo), "Messaging Menu");
+ const gchar ** nicks = indicator_desktop_shortcuts_get_nicks(priv->ids);
+ gint i;
+ for (i = 0; nicks[i] != NULL; i++) {
+ gchar *name;
+ GSimpleAction *action;
+ GMenuItem *item;
+
+ name = indicator_desktop_shortcuts_nick_get_name(priv->ids, nicks[i]);
+
+ action = g_simple_action_new (nicks[i], NULL);
+ g_signal_connect(action, "activate", G_CALLBACK (nick_activate_cb), self);
+ g_simple_action_group_insert (priv->static_shortcuts, G_ACTION (action));
+ g_object_unref (action);
+
+ item = g_menu_item_new (name, nicks[i]);
+ g_menu_item_set_attribute (item, "x-canonical-type", "s", "IdoMenuItem");
+ g_menu_item_set_attribute (item, "x-canonical-icon", "s", ""); /* empty to get indentation */
+ g_menu_append_item (priv->menu, item);
+
+ g_object_unref (item);
+ g_free(name);
+ }
+
+ 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_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)
+{
+ return g_object_new (APP_SECTION_TYPE,
+ "app-info", appinfo,
+ NULL);
+}
+
+static void
+activate_cb (GSimpleAction *action,
+ GVariant *param,
+ gpointer userdata)
+{
+ AppSection * mi = APP_SECTION (userdata);
+ AppSectionPrivate * priv = mi->priv;
+ GError *error = NULL;
+
+ if (!g_app_info_launch (G_APP_INFO (priv->appinfo), NULL, NULL, &error)) {
+ g_warning("Unable to execute application for desktop file '%s': %s",
+ g_desktop_app_info_get_filename (priv->appinfo),
+ error->message);
+ g_error_free (error);
+ }
+}
+
+static void
+launch_action_change_state (GSimpleAction *action,
+ GVariant *value,
+ gpointer user_data)
+{
+ g_simple_action_set_state (action, value);
+}
+
+const gchar *
+app_section_get_desktop (AppSection * self)
+{
+ AppSectionPrivate * priv = self->priv;
+ if (priv->appinfo)
+ return g_desktop_app_info_get_filename (priv->appinfo);
+ else
+ return NULL;
+}
+
+GActionGroup *
+app_section_get_actions (AppSection *self)
+{
+ AppSectionPrivate * priv = self->priv;
+ return G_ACTION_GROUP (priv->muxer);
+}
+
+GMenuModel *
+app_section_get_menu (AppSection *self)
+{
+ AppSectionPrivate * priv = self->priv;
+ return G_MENU_MODEL (priv->menu);
+}
+
+GAppInfo *
+app_section_get_app_info (AppSection *self)
+{
+ AppSectionPrivate * priv = self->priv;
+ return G_APP_INFO (priv->appinfo);
+}
+
+gboolean
+app_section_get_draws_attention (AppSection *self)
+{
+ AppSectionPrivate * priv = self->priv;
+ return priv->draws_attention;
+}
+
+void
+app_section_clear_draws_attention (AppSection *self)
+{
+ AppSectionPrivate * priv = self->priv;
+ gchar **action_names;
+ gchar **it;
+
+ if (priv->source_actions == NULL)
+ return;
+
+ action_names = g_action_group_list_actions (priv->source_actions);
+
+ for (it = action_names; *it; it++) {
+ GVariant *state;
+
+ state = g_action_group_get_action_state (priv->source_actions, *it);
+ if (!state)
+ continue;
+
+ /* clear draws-attention while preserving other state */
+ if (action_draws_attention (state)) {
+ guint32 count;
+ gint64 time;
+ const gchar *str;
+ GVariant *new_state;
+
+ g_variant_get (state, "(ux&sb)", &count, &time, &str, NULL);
+
+ new_state = g_variant_new ("(uxsb)", count, time, str, FALSE);
+ g_action_group_change_action_state (priv->source_actions, *it, new_state);
+ }
+
+ g_variant_unref (state);
+ }
+
+ g_strfreev (action_names);
+}
+
+static void
+application_vanished (GDBusConnection *bus,
+ const gchar *name,
+ gpointer user_data)
+{
+ AppSection *self = user_data;
+
+ app_section_unset_object_path (self);
+}
+
+/*
+ * app_section_set_object_path:
+ * @self: an #AppSection
+ * @bus: a #GDBusConnection
+ * @bus_name: the bus name of the application
+ * @object_path: the object path on which the app exports its actions and menus
+ *
+ * Sets the D-Bus object path exported by an instance of the application
+ * associated with @self. Actions and menus exported on that path will be
+ * shown in the section.
+ */
+void
+app_section_set_object_path (AppSection *self,
+ GDBusConnection *bus,
+ const gchar *bus_name,
+ const gchar *object_path)
+{
+ AppSectionPrivate *priv = self->priv;
+ GMenuItem *item;
+
+ g_object_freeze_notify (G_OBJECT (self));
+ app_section_unset_object_path (self);
+
+ priv->source_actions = G_ACTION_GROUP (g_dbus_action_group_get (bus, bus_name, object_path));
+ g_action_muxer_insert (priv->muxer, "source", priv->source_actions);
+
+ priv->draws_attention = any_action_draws_attention (priv->source_actions, NULL);
+ g_object_connect (priv->source_actions,
+ "signal::action-added", action_added, self,
+ "signal::action-state-changed", action_state_changed, self,
+ "signal::action-removed", action_removed, self,
+ NULL);
+
+ priv->source_menu = G_MENU_MODEL (g_dbus_menu_model_get (bus, bus_name, object_path));
+
+ item = g_menu_item_new_section (NULL, priv->source_menu);
+ g_menu_item_set_attribute (item, "action-namespace", "s", "source");
+ g_menu_append_item (priv->menu, item);
+ g_object_unref (item);
+
+ priv->name_watch_id = g_bus_watch_name_on_connection (bus, bus_name, 0,
+ NULL, application_vanished,
+ self, NULL);
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACTIONS]);
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]);
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_USES_CHAT_STATUS]);
+ g_object_thaw_notify (G_OBJECT (self));
+
+ g_action_group_change_action_state (G_ACTION_GROUP (priv->static_shortcuts),
+ "launch", g_variant_new_boolean (TRUE));
+}
+
+/*
+ * app_section_unset_object_path:
+ * @self: an #AppSection
+ *
+ * Unsets the object path set with app_section_set_object_path(). The section
+ * will return to only showing application name and static shortcuts in the
+ * menu.
+ */
+void
+app_section_unset_object_path (AppSection *self)
+{
+ AppSectionPrivate *priv = self->priv;
+
+ if (priv->name_watch_id) {
+ g_bus_unwatch_name (priv->name_watch_id);
+ priv->name_watch_id = 0;
+ }
+
+ if (priv->source_actions) {
+ g_object_disconnect (priv->source_actions,
+ "any_signal::action-added", action_added, self,
+ "any_signal::action-state-changed", action_state_changed, self,
+ "any_signal::action-removed", action_removed, self,
+ NULL);
+ g_clear_object (&priv->source_actions);
+ }
+
+ if (priv->source_menu) {
+ /* the last menu item points is linked to the app's menumodel */
+ gint n_items = g_menu_model_get_n_items (G_MENU_MODEL (priv->menu));
+ g_menu_remove (priv->menu, n_items -1);
+ g_clear_object (&priv->source_menu);
+ }
+
+ 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));
+}
+
+static gboolean
+action_draws_attention (GVariant *state)
+{
+ gboolean attention;
+
+ if (state && g_variant_is_of_type (state, G_VARIANT_TYPE ("(uxsb)")))
+ g_variant_get_child (state, 3, "b", &attention);
+ else
+ attention = FALSE;
+
+ return attention;
+}
+
+static gboolean
+any_action_draws_attention (GActionGroup *group,
+ const gchar *ignored_action)
+{
+ gchar **actions;
+ gchar **it;
+ gboolean attention = FALSE;
+
+ actions = g_action_group_list_actions (group);
+
+ for (it = actions; *it && !attention; it++) {
+ GVariant *state;
+
+ if (ignored_action && g_str_equal (ignored_action, *it))
+ continue;
+
+ state = g_action_group_get_action_state (group, *it);
+ if (state) {
+ attention = action_draws_attention (state);
+ g_variant_unref (state);
+ }
+ }
+
+ g_strfreev (actions);
+ return attention;
+}
+
+static void
+action_added (GActionGroup *group,
+ const gchar *action_name,
+ gpointer user_data)
+{
+ AppSection *self = user_data;
+ GVariant *state;
+
+ state = g_action_group_get_action_state (group, action_name);
+ if (state) {
+ self->priv->draws_attention |= action_draws_attention (state);
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]);
+ g_variant_unref (state);
+ }
+}
+
+static void
+action_state_changed (GActionGroup *group,
+ const gchar *action_name,
+ GVariant *value,
+ gpointer user_data)
+{
+ AppSection *self = user_data;
+
+ self->priv->draws_attention = any_action_draws_attention (group, NULL);
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]);
+}
+
+static void
+action_removed (GActionGroup *group,
+ const gchar *action_name,
+ gpointer user_data)
+{
+ AppSection *self = user_data;
+
+ self->priv->draws_attention = any_action_draws_attention (group, action_name);
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DRAWS_ATTENTION]);
+}
+
+gboolean
+app_section_get_uses_chat_status (AppSection *self)
+{
+ AppSectionPrivate * priv = self->priv;
+
+ 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]);
}
=== renamed file 'src/app-menu-item.h' => 'src/app-section.h'
--- src/app-menu-item.h 2010-04-16 14:52:41 +0000
+++ src/app-section.h 2013-06-07 21:39:23 +0000
@@ -2,9 +2,10 @@
An indicator to show information that is in messaging applications
that the user is using.
-Copyright 2009 Canonical Ltd.
+Copyright 2012 Canonical Ltd.
Authors:
+ Lars Uebernickel <lars.uebernickel@xxxxxxxxxxxxx>
Ted Gould <ted@xxxxxxxxxxxxx>
This program is free software: you can redistribute it and/or modify it
@@ -19,54 +20,54 @@
You should have received a copy of the GNU General Public License along
with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef __APP_MENU_ITEM_H__
-#define __APP_MENU_ITEM_H__
-
-#include <glib.h>
-#include <glib-object.h>
-
-#include <libdbusmenu-glib/menuitem.h>
-#include <libindicate/listener.h>
+#ifndef __APP_SECTION_H__
+#define __APP_SECTION_H__
+
+#include <gio/gio.h>
+#include <gio/gdesktopappinfo.h>
G_BEGIN_DECLS
-#define APP_MENU_ITEM_TYPE (app_menu_item_get_type ())
-#define APP_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), APP_MENU_ITEM_TYPE, AppMenuItem))
-#define APP_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), APP_MENU_ITEM_TYPE, AppMenuItemClass))
-#define IS_APP_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), APP_MENU_ITEM_TYPE))
-#define IS_APP_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), APP_MENU_ITEM_TYPE))
-#define APP_MENU_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), APP_MENU_ITEM_TYPE, AppMenuItemClass))
-
-#define APP_MENU_ITEM_SIGNAL_COUNT_CHANGED "count-changed"
-#define APP_MENU_ITEM_SIGNAL_NAME_CHANGED "name-changed"
-#define APP_MENU_ITEM_SIGNAL_SHORTCUT_ADDED "shortcut-added"
-#define APP_MENU_ITEM_SIGNAL_SHORTCUT_REMOVED "shortcut-removed"
-
-typedef struct _AppMenuItem AppMenuItem;
-typedef struct _AppMenuItemClass AppMenuItemClass;
-
-struct _AppMenuItemClass {
- DbusmenuMenuitemClass parent_class;
-
- void (* count_changed) (guint count);
- void (* name_changed) (gchar * name);
- void (* shortcut_added) (DbusmenuMenuitem * mi);
- void (* shortcut_removed) (DbusmenuMenuitem * mi);
-};
-
-struct _AppMenuItem {
- DbusmenuMenuitem parent;
-};
-
-GType app_menu_item_get_type (void);
-AppMenuItem * app_menu_item_new (IndicateListener * listener, IndicateListenerServer * server);
-guint app_menu_item_get_count (AppMenuItem * appitem);
-IndicateListenerServer * app_menu_item_get_server (AppMenuItem * appitem);
-const gchar * app_menu_item_get_name (AppMenuItem * appitem);
-const gchar * app_menu_item_get_desktop (AppMenuItem * appitem);
-GList * app_menu_item_get_items (AppMenuItem * appitem);
+#define APP_SECTION_TYPE (app_section_get_type ())
+#define APP_SECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), APP_SECTION_TYPE, AppSection))
+#define APP_SECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), APP_SECTION_TYPE, AppSectionClass))
+#define IS_APP_SECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), APP_SECTION_TYPE))
+#define IS_APP_SECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), APP_SECTION_TYPE))
+#define APP_SECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), APP_SECTION_TYPE, AppSectionClass))
+
+typedef struct _AppSection AppSection;
+typedef struct _AppSectionClass AppSectionClass;
+typedef struct _AppSectionPrivate AppSectionPrivate;
+
+
+struct _AppSectionClass {
+ GObjectClass parent_class;
+};
+
+struct _AppSection {
+ GObject parent;
+ AppSectionPrivate *priv;
+};
+
+GType app_section_get_type (void);
+AppSection * app_section_new (GDesktopAppInfo *appinfo);
+const gchar * app_section_get_desktop (AppSection * appitem);
+GActionGroup * app_section_get_actions (AppSection *self);
+GMenuModel * app_section_get_menu (AppSection *appitem);
+GAppInfo * app_section_get_app_info (AppSection *appitem);
+gboolean app_section_get_draws_attention (AppSection *appitem);
+void app_section_clear_draws_attention (AppSection *appitem);
+void app_section_set_object_path (AppSection *self,
+ GDBusConnection *bus,
+ const gchar *bus_name,
+ const gchar *object_path);
+void app_section_unset_object_path (AppSection *self);
+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
-#endif /* __APP_MENU_ITEM_H__ */
+#endif /* __APP_SECTION_H__ */
=== modified file 'src/dbus-data.h'
--- src/dbus-data.h 2011-01-14 20:19:48 +0000
+++ src/dbus-data.h 2013-06-07 21:39:23 +0000
@@ -8,16 +8,4 @@
#define INDICATOR_MESSAGES_DBUS_SERVICE_OBJECT "/com/canonical/indicator/messages/service"
#define INDICATOR_MESSAGES_DBUS_SERVICE_INTERFACE "com.canonical.indicator.messages.service"
-#define APPLICATION_MENUITEM_TYPE "application-item"
-#define APPLICATION_MENUITEM_PROP_NAME "label"
-#define APPLICATION_MENUITEM_PROP_ICON "icon-name"
-#define APPLICATION_MENUITEM_PROP_RUNNING "app-running"
-
-#define INDICATOR_MENUITEM_TYPE "indicator-item"
-#define INDICATOR_MENUITEM_PROP_LABEL "indicator-label"
-#define INDICATOR_MENUITEM_PROP_ICON "indicator-icon"
-#define INDICATOR_MENUITEM_PROP_RIGHT "right-side-text"
-
-#define MAX_NUMBER_OF_INDICATORS 7
-
#endif /* __DBUS_DATA_H__ */
=== removed file 'src/default-applications.c'
--- src/default-applications.c 2011-07-22 16:49:14 +0000
+++ src/default-applications.c 1970-01-01 00:00:00 +0000
@@ -1,116 +0,0 @@
-/*
-Looking for the default applications. A quick lookup.
-
-Copyright 2010 Canonical Ltd.
-
-Authors:
- Ted Gould <ted@xxxxxxxxxxxxx>
-
-This program is free software: you can redistribute it and/or modify it
-under the terms of the GNU General Public License version 3, as published
-by the Free Software Foundation.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranties of
-MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
-PURPOSE. See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along
-with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <glib.h>
-#include <glib/gi18n.h>
-#include <gio/gio.h>
-#include <gio/gdesktopappinfo.h>
-#include "default-applications.h"
-
-struct default_db_t {
- const gchar * desktop_file;
- const gchar * uri_scheme;
- const gchar * name;
- const gchar * setupname;
- const gchar * icon;
-};
-
-struct default_db_t default_db[] = {
- {NULL, "mailto", N_("Mail"), N_("Set Up Mail..."), "applications-email-panel"},
- {"empathy.desktop", NULL, N_("Chat"), N_("Set Up Chat..."), "applications-chat-panel"},
- {"gwibber.desktop", NULL, N_("Broadcast"), N_("Set Up Broadcast Account..."), "applications-microblogging-panel"},
-};
-
-static struct default_db_t *
-get_default_helper (const gchar * desktop_path)
-{
- g_return_val_if_fail(desktop_path != NULL, NULL);
- gchar * basename = g_path_get_basename(desktop_path);
- g_return_val_if_fail(basename != NULL, NULL);
-
- gboolean found = FALSE;
- gint i;
- gint length = G_N_ELEMENTS(default_db);
- for (i = 0; i < length && !found; i++) {
- if (default_db[i].desktop_file) {
- if (g_strcmp0(default_db[i].desktop_file, basename) == 0) {
- found = TRUE;
- }
- } else if (default_db[i].uri_scheme) {
- GAppInfo *info = g_app_info_get_default_for_uri_scheme(default_db[i].uri_scheme);
- if (!info) {
- continue;
- }
-
- const gchar * filename = g_desktop_app_info_get_filename(G_DESKTOP_APP_INFO(info));
- if (!filename) {
- g_object_unref(info);
- continue;
- }
-
- gchar * default_basename = g_path_get_basename(filename);
- g_object_unref(info);
- if (g_strcmp0(default_basename, basename) == 0) {
- found = TRUE;
- }
-
- g_free(default_basename);
- }
- }
-
- g_free(basename);
-
- if (found) {
- return &default_db[i - 1];
- }
-
- return NULL;
-}
-
-const gchar *
-get_default_name (const gchar * desktop_path)
-{
- struct default_db_t * db = get_default_helper(desktop_path);
-
- if (db == NULL)
- return NULL;
- return db->name;
-}
-
-const gchar *
-get_default_setup (const gchar * desktop_path)
-{
- struct default_db_t * db = get_default_helper(desktop_path);
-
- if (db == NULL)
- return NULL;
- return db->setupname;
-}
-
-const gchar *
-get_default_icon (const gchar * desktop_path)
-{
- struct default_db_t * db = get_default_helper(desktop_path);
-
- if (db == NULL)
- return NULL;
- return db->icon;
-}
=== removed file 'src/default-applications.h'
--- src/default-applications.h 2011-04-06 16:20:08 +0000
+++ src/default-applications.h 1970-01-01 00:00:00 +0000
@@ -1,34 +0,0 @@
-/*
-Looking for the default applications. A quick lookup.
-
-Copyright 2010 Canonical Ltd.
-
-Authors:
- Ted Gould <ted@xxxxxxxxxxxxx>
-
-This program is free software: you can redistribute it and/or modify it
-under the terms of the GNU General Public License version 3, as published
-by the Free Software Foundation.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranties of
-MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
-PURPOSE. See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along
-with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef DEFAULT_APPLICATIONS_H__
-#define DEFAULT_APPLICATIONS_H__ 1
-
-/* Used for override icons in the normal case, but didn't
- have a better place to put it. */
-#define ICON_KEY "X-Ayatana-Messaging-Menu-Icon"
-
-const gchar * get_default_name (const gchar * desktop_path);
-const gchar * get_default_setup (const gchar * desktop_path);
-const gchar * get_default_icon (const gchar * desktop_path);
-
-#endif /* DEFAULT_APPLICATIONS_H__ */
-
=== removed file 'src/dirs.h'
--- src/dirs.h 2009-09-23 16:06:01 +0000
+++ src/dirs.h 1970-01-01 00:00:00 +0000
@@ -1,4 +0,0 @@
-#define SYSTEM_APPS_DIR "/usr/share/indicators/messages/applications"
-#define SYSTEM_APPS_DIR_OLD "/etc/indicators/messages/applications"
-#define USER_APPS_DIR "indicators/messages/applications"
-#define USER_BLACKLIST_DIR "indicators/messages/applications-blacklist"
=== added file 'src/gactionmuxer.c'
--- src/gactionmuxer.c 1970-01-01 00:00:00 +0000
+++ src/gactionmuxer.c 2013-06-07 21:39:23 +0000
@@ -0,0 +1,485 @@
+/*
+ * 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@xxxxxxxxxxxxx>
+ * Ryan Lortie <desrt@xxxxxxxx>
+ */
+
+#include "gactionmuxer.h"
+
+#include <string.h>
+
+/*
+ * SECTION:gactionmuxer
+ * @short_description: Aggregate several action groups
+ *
+ * #GActionMuxer is a #GActionGroup that is capable of containing other
+ * #GActionGroup instances.
+ *
+ * The typical use is aggregating all of the actions applicable to a
+ * particular context into a single action group, with namespacing.
+ *
+ * Consider the case of two action groups -- one containing actions
+ * applicable to an entire application (such as 'quit') and one
+ * containing actions applicable to a particular window in the
+ * application (such as 'fullscreen').
+ *
+ * In this case, each of these action groups could be added to a
+ * #GActionMuxer with the prefixes "app" and "win", respectively. This
+ * would expose the actions as "app.quit" and "win.fullscreen" on the
+ * #GActionGroup interface presented by the #GActionMuxer.
+ *
+ * Activations and state change requests on the #GActionMuxer are wired
+ * through to the underlying action group in the expected way.
+ */
+
+typedef GObjectClass GActionMuxerClass;
+
+struct _GActionMuxer
+{
+ GObject parent;
+ GActionGroup *global_actions;
+ GHashTable *groups; /* prefix -> subgroup */
+ GHashTable *reverse; /* subgroup -> prefix */
+};
+
+
+static void g_action_muxer_group_init (GActionGroupInterface *iface);
+static void g_action_muxer_dispose (GObject *object);
+static void g_action_muxer_finalize (GObject *object);
+static void g_action_muxer_disconnect_group (GActionMuxer *muxer,
+ GActionGroup *subgroup);
+static gchar ** g_action_muxer_list_actions (GActionGroup *group);
+static void g_action_muxer_activate_action (GActionGroup *group,
+ const gchar *action_name,
+ GVariant *parameter);
+static void g_action_muxer_change_action_state (GActionGroup *group,
+ const gchar *action_name,
+ GVariant *value);
+static gboolean g_action_muxer_query_action (GActionGroup *group,
+ const gchar *action_name,
+ gboolean *enabled,
+ const GVariantType **parameter_type,
+ const GVariantType **state_type,
+ GVariant **state_hint,
+ GVariant **state);
+static void g_action_muxer_action_added (GActionGroup *group,
+ gchar *action_name,
+ gpointer user_data);
+static void g_action_muxer_action_removed (GActionGroup *group,
+ gchar *action_name,
+ gpointer user_data);
+static void g_action_muxer_action_state_changed (GActionGroup *group,
+ gchar *action_name,
+ GVariant *value,
+ gpointer user_data);
+static void g_action_muxer_action_enabled_changed (GActionGroup *group,
+ gchar *action_name,
+ gboolean enabled,
+ gpointer user_data);
+
+G_DEFINE_TYPE_WITH_CODE (GActionMuxer, g_action_muxer, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP, g_action_muxer_group_init));
+
+
+static void
+g_action_muxer_class_init (GObjectClass *klass)
+{
+ klass->dispose = g_action_muxer_dispose;
+ klass->finalize = g_action_muxer_finalize;
+}
+
+static void
+g_action_muxer_init (GActionMuxer *muxer)
+{
+ muxer->global_actions = NULL;
+ muxer->groups = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+ muxer->reverse = g_hash_table_new (g_direct_hash, g_direct_equal);
+}
+
+static void
+g_action_muxer_group_init (GActionGroupInterface *iface)
+{
+ iface->list_actions = g_action_muxer_list_actions;
+ iface->activate_action = g_action_muxer_activate_action;
+ iface->change_action_state = g_action_muxer_change_action_state;
+ iface->query_action = g_action_muxer_query_action;
+}
+
+static void
+g_action_muxer_dispose (GObject *object)
+{
+ GActionMuxer *muxer = G_ACTION_MUXER (object);
+ GHashTableIter it;
+ GActionGroup *subgroup;
+
+ if (muxer->global_actions)
+ {
+ g_action_muxer_disconnect_group (muxer, muxer->global_actions);
+ g_clear_object (&muxer->global_actions);
+ }
+
+ g_hash_table_iter_init (&it, muxer->groups);
+ while (g_hash_table_iter_next (&it, NULL, (gpointer *) &subgroup))
+ g_action_muxer_disconnect_group (muxer, subgroup);
+
+ g_hash_table_remove_all (muxer->groups);
+ g_hash_table_remove_all (muxer->reverse);
+}
+
+static void
+g_action_muxer_finalize (GObject *object)
+{
+ GActionMuxer *muxer = G_ACTION_MUXER (object);
+
+ g_hash_table_unref (muxer->groups);
+ g_hash_table_unref (muxer->reverse);
+
+ G_OBJECT_CLASS (g_action_muxer_parent_class)->finalize (object);
+}
+
+static GActionGroup *
+g_action_muxer_lookup_group (GActionMuxer *muxer,
+ const gchar *full_name,
+ const gchar **action_name)
+{
+ const gchar *sep;
+ GActionGroup *group;
+
+ sep = strchr (full_name, '.');
+
+ if (sep)
+ {
+ gchar *prefix;
+ prefix = g_strndup (full_name, sep - full_name);
+ group = g_hash_table_lookup (muxer->groups, prefix);
+ g_free (prefix);
+ if (action_name)
+ *action_name = sep + 1;
+ }
+ else
+ {
+ group = muxer->global_actions;
+ if (action_name)
+ *action_name = full_name;
+ }
+
+ return group;
+}
+
+static gchar *
+g_action_muxer_lookup_full_name (GActionMuxer *muxer,
+ GActionGroup *subgroup,
+ const gchar *action_name)
+{
+ gpointer prefix;
+
+ if (subgroup == muxer->global_actions)
+ return g_strdup (action_name);
+
+ if (g_hash_table_lookup_extended (muxer->reverse, subgroup, NULL, &prefix))
+ return g_strdup_printf ("%s.%s", (gchar *) prefix, action_name);
+
+ return NULL;
+}
+
+static void
+g_action_muxer_disconnect_group (GActionMuxer *muxer,
+ GActionGroup *subgroup)
+{
+ gchar **actions;
+ gchar **action;
+
+ actions = g_action_group_list_actions (subgroup);
+ for (action = actions; *action; action++)
+ g_action_muxer_action_removed (subgroup, *action, muxer);
+ g_strfreev (actions);
+
+ g_signal_handlers_disconnect_by_func (subgroup, g_action_muxer_action_added, muxer);
+ g_signal_handlers_disconnect_by_func (subgroup, g_action_muxer_action_removed, muxer);
+ g_signal_handlers_disconnect_by_func (subgroup, g_action_muxer_action_enabled_changed, muxer);
+ g_signal_handlers_disconnect_by_func (subgroup, g_action_muxer_action_state_changed, muxer);
+}
+
+static gchar **
+g_action_muxer_list_actions (GActionGroup *group)
+{
+ GActionMuxer *muxer = G_ACTION_MUXER (group);
+ GHashTableIter it;
+ GArray *all_actions;
+ gchar *prefix;
+ GActionGroup *subgroup;
+ gchar **actions;
+ gchar **a;
+
+ all_actions = g_array_sized_new (TRUE, FALSE, sizeof (gchar *), 8);
+
+ if (muxer->global_actions)
+ {
+ actions = g_action_group_list_actions (muxer->global_actions);
+ for (a = actions; *a; a++)
+ {
+ gchar *name = g_strdup (*a);
+ g_array_append_val (all_actions, name);
+ }
+ g_strfreev (actions);
+ }
+
+ g_hash_table_iter_init (&it, muxer->groups);
+ while (g_hash_table_iter_next (&it, (gpointer *) &prefix, (gpointer *) &subgroup))
+ {
+ actions = g_action_group_list_actions (subgroup);
+ for (a = actions; *a; a++)
+ {
+ gchar *full_name = g_strdup_printf ("%s.%s", prefix, *a);
+ g_array_append_val (all_actions, full_name);
+ }
+ g_strfreev (actions);
+ }
+
+ return (gchar **) g_array_free (all_actions, FALSE);
+}
+
+static void
+g_action_muxer_activate_action (GActionGroup *group,
+ const gchar *action_name,
+ GVariant *parameter)
+{
+ GActionMuxer *muxer = G_ACTION_MUXER (group);
+ GActionGroup *subgroup;
+ const gchar *action;
+
+ g_return_if_fail (action_name != NULL);
+
+ subgroup = g_action_muxer_lookup_group (muxer, action_name, &action);
+
+ if (subgroup)
+ g_action_group_activate_action (subgroup, action, parameter);
+}
+
+static void
+g_action_muxer_change_action_state (GActionGroup *group,
+ const gchar *action_name,
+ GVariant *value)
+{
+ GActionMuxer *muxer = G_ACTION_MUXER (group);
+ GActionGroup *subgroup;
+ const gchar *action;
+
+ g_return_if_fail (action_name != NULL);
+
+ subgroup = g_action_muxer_lookup_group (muxer, action_name, &action);
+
+ if (subgroup)
+ g_action_group_change_action_state (subgroup, action, value);
+}
+
+static gboolean
+g_action_muxer_query_action (GActionGroup *group,
+ const gchar *action_name,
+ gboolean *enabled,
+ const GVariantType **parameter_type,
+ const GVariantType **state_type,
+ GVariant **state_hint,
+ GVariant **state)
+{
+ GActionMuxer *muxer = G_ACTION_MUXER (group);
+ GActionGroup *subgroup;
+ const gchar *action;
+
+ g_return_val_if_fail (action_name != NULL, FALSE);
+
+ subgroup = g_action_muxer_lookup_group (muxer, action_name, &action);
+
+ if (!subgroup)
+ return FALSE;
+
+ return g_action_group_query_action (subgroup, action, enabled, parameter_type,
+ state_type, state_hint, state);
+}
+
+static void
+g_action_muxer_action_added (GActionGroup *group,
+ gchar *action_name,
+ gpointer user_data)
+{
+ GActionMuxer *muxer = user_data;
+ gchar *full_name;
+
+ full_name = g_action_muxer_lookup_full_name (muxer, group, action_name);
+
+ if (full_name)
+ {
+ g_action_group_action_added (G_ACTION_GROUP (muxer), full_name);
+ g_free (full_name);
+ }
+}
+
+static void
+g_action_muxer_action_removed (GActionGroup *group,
+ gchar *action_name,
+ gpointer user_data)
+{
+ GActionMuxer *muxer = user_data;
+ gchar *full_name;
+
+ full_name = g_action_muxer_lookup_full_name (muxer, group, action_name);
+
+ if (full_name)
+ {
+ g_action_group_action_removed (G_ACTION_GROUP (muxer), full_name);
+ g_free (full_name);
+ }
+}
+
+static void
+g_action_muxer_action_state_changed (GActionGroup *group,
+ gchar *action_name,
+ GVariant *value,
+ gpointer user_data)
+{
+ GActionMuxer *muxer = user_data;
+ gchar *full_name;
+
+ full_name = g_action_muxer_lookup_full_name (muxer, group, action_name);
+
+ if (full_name)
+ {
+ g_action_group_action_state_changed (G_ACTION_GROUP (muxer), full_name, value);
+ g_free (full_name);
+ }
+}
+
+static void
+g_action_muxer_action_enabled_changed (GActionGroup *group,
+ gchar *action_name,
+ gboolean enabled,
+ gpointer user_data)
+{
+ GActionMuxer *muxer = user_data;
+ gchar *full_name;
+
+ full_name = g_action_muxer_lookup_full_name (muxer, group, action_name);
+
+ if (full_name)
+ {
+ g_action_group_action_enabled_changed (G_ACTION_GROUP (muxer), full_name, enabled);
+ g_free (full_name);
+ }
+}
+
+/*
+ * g_action_muxer_new:
+ *
+ * Creates a new #GActionMuxer.
+ */
+GActionMuxer *
+g_action_muxer_new (void)
+{
+ return g_object_new (G_TYPE_ACTION_MUXER, NULL);
+}
+
+/*
+ * g_action_muxer_insert:
+ * @muxer: a #GActionMuxer
+ * @prefix: (allow-none): the prefix string for the action group, or NULL
+ * @group: (allow-none): a #GActionGroup, or NULL
+ *
+ * Adds the actions in @group to the list of actions provided by @muxer.
+ * @prefix is prefixed to each action name, such that for each action
+ * <varname>x</varname> in @group, there is an equivalent action
+ * @prefix<literal>.</literal><varname>x</varname> in @muxer.
+ *
+ * For example, if @prefix is "<literal>app</literal>" and @group contains an
+ * action called "<literal>quit</literal>", then @muxer will now contain an
+ * action called "<literal>app.quit</literal>".
+ *
+ * If @prefix is <literal>NULL</literal>, the actions in @group will be added
+ * to @muxer without prefix.
+ *
+ * If @group is <literal>NULL</literal>, this function has the same effect as
+ * calling g_action_muxer_remove() with @prefix.
+ *
+ * There may only be one group per prefix (including the
+ * <literal>NULL</literal>-prefix). If a group has been added with @prefix in
+ * a previous call to this function, it will be removed.
+ *
+ * @prefix must not contain a dot ('.').
+ */
+void
+g_action_muxer_insert (GActionMuxer *muxer,
+ const gchar *prefix,
+ GActionGroup *group)
+{
+ gchar *prefix_copy;
+ gchar **actions;
+ gchar **action;
+
+ g_return_if_fail (G_IS_ACTION_MUXER (muxer));
+ g_return_if_fail (G_IS_ACTION_GROUP (group));
+
+ g_action_muxer_remove (muxer, prefix);
+
+ if (prefix)
+ {
+ prefix_copy = g_strdup (prefix);
+ g_hash_table_insert (muxer->groups, prefix_copy, g_object_ref (group));
+ g_hash_table_insert (muxer->reverse, group, prefix_copy);
+ }
+ else
+ muxer->global_actions = g_object_ref (group);
+
+ actions = g_action_group_list_actions (group);
+ for (action = actions; *action; action++)
+ g_action_muxer_action_added (group, *action, muxer);
+ g_strfreev (actions);
+
+ g_signal_connect (group, "action-added", G_CALLBACK (g_action_muxer_action_added), muxer);
+ g_signal_connect (group, "action-removed", G_CALLBACK (g_action_muxer_action_removed), muxer);
+ g_signal_connect (group, "action-enabled-changed", G_CALLBACK (g_action_muxer_action_enabled_changed), muxer);
+ g_signal_connect (group, "action-state-changed", G_CALLBACK (g_action_muxer_action_state_changed), muxer);
+}
+
+/*
+ * g_action_muxer_remove:
+ * @muxer: a #GActionMuxer
+ * @prefix: (allow-none): the prefix of the action group to remove, or NULL
+ *
+ * Removes a #GActionGroup from the #GActionMuxer.
+ */
+void
+g_action_muxer_remove (GActionMuxer *muxer,
+ const gchar *prefix)
+{
+ GActionGroup *subgroup;
+
+ g_return_if_fail (G_IS_ACTION_MUXER (muxer));
+
+ subgroup = prefix ? g_hash_table_lookup (muxer->groups, prefix) : muxer->global_actions;
+ if (!subgroup)
+ return;
+
+ g_action_muxer_disconnect_group (muxer, subgroup);
+
+ if (prefix)
+ {
+ g_hash_table_remove (muxer->groups, prefix);
+ g_hash_table_remove (muxer->reverse, subgroup);
+ }
+ else
+ g_clear_object (&muxer->global_actions);
+}
+
=== added file 'src/gactionmuxer.h'
--- src/gactionmuxer.h 1970-01-01 00:00:00 +0000
+++ src/gactionmuxer.h 2013-06-07 21:39:23 +0000
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2012 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Lars Uebernickel <lars.uebernickel@xxxxxxxxxxxxx>
+ * Ryan Lortie <desrt@xxxxxxxx>
+ */
+
+#ifndef __G_ACTION_MUXER_H__
+#define __G_ACTION_MUXER_H__
+
+#include <gio/gio.h>
+
+#define G_TYPE_ACTION_MUXER (g_action_muxer_get_type ())
+#define G_ACTION_MUXER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_ACTION_MUXER, GActionMuxer))
+#define G_IS_ACTION_MUXER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_ACTION_MUXER))
+
+typedef struct _GActionMuxer GActionMuxer;
+
+GType g_action_muxer_get_type (void) G_GNUC_CONST;
+
+GActionMuxer * g_action_muxer_new (void);
+
+void g_action_muxer_insert (GActionMuxer *muxer,
+ const gchar *prefix,
+ GActionGroup *group);
+
+void g_action_muxer_remove (GActionMuxer *muxer,
+ const gchar *prefix);
+
+#endif
+
=== added file 'src/gmenuutils.c'
--- src/gmenuutils.c 1970-01-01 00:00:00 +0000
+++ src/gmenuutils.c 2013-06-07 21:39:23 +0000
@@ -0,0 +1,87 @@
+/*
+ * 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@xxxxxxxxxxxxx>
+ */
+
+#include "gmenuutils.h"
+#include "dbus-data.h"
+
+/* g_menu_find_section:
+ * @menu: a #GMenu
+ * @section: the section to be found in @menu
+ *
+ * @Returns the index of the first menu item that is linked to #section, or -1
+ * if there's no such item.
+ */
+int
+g_menu_find_section (GMenu *menu,
+ GMenuModel *section)
+{
+ GMenuModel *model = G_MENU_MODEL (menu);
+ int n_items;
+ int i;
+
+ g_return_val_if_fail (G_IS_MENU_MODEL (section), -1);
+
+ n_items = g_menu_model_get_n_items (model);
+ for (i = 0; i < n_items; i++)
+ {
+ GMenuModel *link;
+ gboolean found;
+
+ link = g_menu_model_get_item_link (model, i, G_MENU_LINK_SECTION);
+ found = section == link;
+
+ g_object_unref (link);
+
+ if (found)
+ return i;
+ }
+
+ return -1;
+}
+
+
+void
+g_menu_append_with_icon (GMenu *menu,
+ const gchar *label,
+ GIcon *icon,
+ const gchar *detailed_action)
+{
+ gchar *iconstr;
+
+ iconstr = g_icon_to_string (icon);
+ g_menu_append_with_icon_name (menu, label, iconstr, detailed_action);
+
+ g_free (iconstr);
+}
+
+void
+g_menu_append_with_icon_name (GMenu *menu,
+ const gchar *label,
+ const gchar *icon_name,
+ const gchar *detailed_action)
+{
+ GMenuItem *item;
+
+ item = g_menu_item_new (label, detailed_action);
+ g_menu_item_set_attribute (item, "x-canonical-icon", "s", icon_name);
+
+ g_menu_append_item (menu, item);
+
+ g_object_unref (item);
+}
=== added file 'src/gmenuutils.h'
--- src/gmenuutils.h 1970-01-01 00:00:00 +0000
+++ src/gmenuutils.h 2013-06-07 21:39:23 +0000
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2012 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Lars Uebernickel <lars.uebernickel@xxxxxxxxxxxxx>
+ */
+
+#ifndef __G_MENU_UTILS_H__
+#define __G_MENU_UTILS_H__
+
+#include <gio/gio.h>
+
+int g_menu_find_section (GMenu *menu,
+ GMenuModel *section);
+
+void g_menu_append_with_icon (GMenu *menu,
+ const gchar *label,
+ GIcon *icon,
+ const gchar *detailed_action);
+
+void g_menu_append_with_icon_name (GMenu *menu,
+ const gchar *label,
+ const gchar *icon_name,
+ const gchar *detailed_action);
+
+#endif
=== added file 'src/gsettingsstrv.c'
--- src/gsettingsstrv.c 1970-01-01 00:00:00 +0000
+++ src/gsettingsstrv.c 2013-06-07 21:39:23 +0000
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2012 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Lars Uebernickel <lars.uebernickel@xxxxxxxxxxxxx>
+ */
+
+#include "gsettingsstrv.h"
+
+/**
+ * g_settings_strv_append_unique:
+ * @settings: a #GSettings object
+ * @key: the key at which @settings contains a string array
+ * @item: the string to append
+ *
+ * Appends @item to the string array at @key if that string array doesn't
+ * contain @item yet.
+ *
+ * Returns: TRUE if @item was added to the list, FALSE if it already existed.
+ */
+gboolean
+g_settings_strv_append_unique (GSettings *settings,
+ const gchar *key,
+ const gchar *item)
+{
+ gchar **strv;
+ gchar **it;
+ gboolean add = TRUE;
+
+ g_return_val_if_fail (G_IS_SETTINGS (settings), FALSE);
+ g_return_val_if_fail (key != NULL, FALSE);
+ g_return_val_if_fail (item != NULL, FALSE);
+
+ strv = g_settings_get_strv (settings, key);
+
+ for (it = strv; *it; it++)
+ {
+ if (g_str_equal (*it, item))
+ {
+ add = FALSE;
+ break;
+ }
+ }
+
+ if (add)
+ {
+ GVariantBuilder builder;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
+
+ for (it = strv; *it; it++)
+ g_variant_builder_add (&builder, "s", *it);
+ g_variant_builder_add (&builder, "s", item);
+
+ g_settings_set_value (settings, key, g_variant_builder_end (&builder));
+ }
+
+ g_strfreev (strv);
+ return add;
+}
+
+/**
+ * g_settings_strv_remove:
+ * @settings: a #GSettings object
+ * @key: the key at which @settings contains a string array
+ * @item: the string to remove
+ *
+ * Removes all occurences of @item in @key.
+ */
+void
+g_settings_strv_remove (GSettings *settings,
+ const gchar *key,
+ const gchar *item)
+{
+ gchar **strv;
+ gchar **it;
+ GVariantBuilder builder;
+
+ g_return_if_fail (G_IS_SETTINGS (settings));
+ g_return_if_fail (key != NULL);
+ g_return_if_fail (item != NULL);
+
+ strv = g_settings_get_strv (settings, key);
+
+ g_variant_builder_init (&builder, (GVariantType *)"as");
+ for (it = strv; *it; it++)
+ {
+ if (!g_str_equal (*it, item))
+ g_variant_builder_add (&builder, "s", *it);
+ }
+ g_settings_set_value (settings, key, g_variant_builder_end (&builder));
+
+ g_strfreev (strv);
+}
=== added file 'src/gsettingsstrv.h'
--- src/gsettingsstrv.h 1970-01-01 00:00:00 +0000
+++ src/gsettingsstrv.h 2013-06-07 21:39:23 +0000
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2012 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Lars Uebernickel <lars.uebernickel@xxxxxxxxxxxxx>
+ */
+
+#ifndef __G_SETTINGS_STRV_H__
+#define __G_SETTINGS_STRV_H__
+
+#include <gio/gio.h>
+
+gboolean g_settings_strv_append_unique (GSettings *settings,
+ const gchar *key,
+ const gchar *item);
+
+void g_settings_strv_remove (GSettings *settings,
+ const gchar *key,
+ const gchar *item);
+
+#endif
=== added file 'src/ido-detail-label.c'
--- src/ido-detail-label.c 1970-01-01 00:00:00 +0000
+++ src/ido-detail-label.c 2013-06-07 21:39:23 +0000
@@ -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@xxxxxxxxxxxxx>
+ */
+
+#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);
+}
=== added file 'src/ido-detail-label.h'
--- src/ido-detail-label.h 1970-01-01 00:00:00 +0000
+++ src/ido-detail-label.h 2013-06-07 21:39:23 +0000
@@ -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@xxxxxxxxxxxxx>
+ */
+
+#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
=== added file 'src/ido-menu-item.c'
--- src/ido-menu-item.c 1970-01-01 00:00:00 +0000
+++ src/ido-menu-item.c 2013-06-07 21:39:23 +0000
@@ -0,0 +1,425 @@
+/*
+ * 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@xxxxxxxxxxxxx>
+ */
+
+#include "ido-menu-item.h"
+
+struct _IdoMenuItemPrivate
+{
+ GActionGroup *action_group;
+ gchar *action;
+ GVariant *target;
+
+ GtkWidget *icon;
+ GtkWidget *label;
+
+ gboolean has_indicator;
+ gboolean in_set_active;
+};
+
+enum
+{
+ PROP_0,
+ PROP_MENU_ITEM,
+ PROP_ACTION_GROUP,
+ NUM_PROPERTIES
+};
+
+static GParamSpec *properties[NUM_PROPERTIES];
+
+G_DEFINE_TYPE (IdoMenuItem, ido_menu_item, GTK_TYPE_CHECK_MENU_ITEM);
+
+static void
+ido_menu_item_constructed (GObject *object)
+{
+ IdoMenuItemPrivate *priv = IDO_MENU_ITEM (object)->priv;
+ GtkWidget *grid;
+
+ priv->icon = g_object_ref (gtk_image_new ());
+ gtk_widget_set_margin_right (priv->icon, 6);
+
+ priv->label = g_object_ref (gtk_label_new (""));
+
+ grid = gtk_grid_new ();
+ gtk_grid_attach (GTK_GRID (grid), priv->icon, 0, 0, 1, 1);
+ gtk_grid_attach (GTK_GRID (grid), priv->label, 1, 0, 1, 1);
+
+ gtk_container_add (GTK_CONTAINER (object), grid);
+ gtk_widget_show_all (grid);
+
+ G_OBJECT_CLASS (ido_menu_item_parent_class)->constructed (object);
+}
+
+static void
+ido_menu_item_set_active (IdoMenuItem *self,
+ gboolean active)
+{
+ /* HACK gtk_check_menu_item_set_active calls gtk_menu_item_activate.
+ * Make sure our activate handler doesn't toggle the action as a
+ * result of calling this function. */
+
+ self->priv->in_set_active = TRUE;
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (self), active);
+ self->priv->in_set_active = FALSE;
+}
+
+static void
+ido_menu_item_set_has_indicator (IdoMenuItem *self,
+ gboolean has_indicator)
+{
+ if (has_indicator == self->priv->has_indicator)
+ return;
+
+ self->priv->has_indicator = has_indicator;
+
+ gtk_widget_queue_resize (GTK_WIDGET (self));
+}
+
+static void
+ido_menu_item_set_state (IdoMenuItem *self,
+ GVariant *state)
+{
+ IdoMenuItemPrivate *priv = self->priv;
+
+ if (priv->target)
+ {
+ ido_menu_item_set_has_indicator (self, TRUE);
+ ido_menu_item_set_active (self, FALSE);
+ gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (self), TRUE);
+ 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))
+ {
+ ido_menu_item_set_has_indicator (self, TRUE);
+ gtk_check_menu_item_set_draw_as_radio (GTK_CHECK_MENU_ITEM (self), FALSE);
+ ido_menu_item_set_active (self, g_variant_get_boolean (state));
+ }
+ else
+ {
+ ido_menu_item_set_has_indicator (self, FALSE);
+ }
+}
+
+static void
+ido_menu_item_set_action_name (IdoMenuItem *self,
+ const gchar *action_name)
+{
+ IdoMenuItemPrivate *priv = self->priv;
+ gboolean enabled = FALSE;
+ GVariant *state;
+ const GVariantType *param_type;
+
+ if (priv->action != NULL)
+ g_free (priv->action);
+
+ priv->action = g_strdup (action_name);
+
+ if (priv->action_group != NULL && priv->action != NULL &&
+ g_action_group_query_action (priv->action_group, priv->action,
+ &enabled, ¶m_type, NULL, NULL, &state))
+ {
+ gtk_widget_set_sensitive (GTK_WIDGET (self), enabled);
+
+ if (state)
+ {
+ ido_menu_item_set_state (self, state);
+ g_variant_unref (state);
+ }
+ }
+ else
+ {
+ ido_menu_item_set_active (self, FALSE);
+ gtk_widget_set_sensitive (GTK_WIDGET (self), FALSE);
+ ido_menu_item_set_has_indicator (self, FALSE);
+ }
+}
+
+static void
+ido_menu_item_action_added (GActionGroup *action_group,
+ gchar *action_name,
+ gpointer user_data)
+{
+ IdoMenuItem *self = user_data;
+
+ if (g_strcmp0 (self->priv->action, action_name) == 0)
+ ido_menu_item_set_action_name (self, action_name);
+}
+
+static void
+ido_menu_item_action_removed (GActionGroup *action_group,
+ gchar *action_name,
+ gpointer user_data)
+{
+ IdoMenuItem *self = user_data;
+
+ if (g_strcmp0 (self->priv->action, action_name) == 0)
+ {
+ gtk_widget_set_sensitive (GTK_WIDGET (self), FALSE);
+ }
+}
+
+static void
+ido_menu_item_action_enabled_changed (GActionGroup *action_group,
+ gchar *action_name,
+ gboolean enabled,
+ gpointer user_data)
+{
+ IdoMenuItem *self = user_data;
+
+ if (g_strcmp0 (self->priv->action, action_name) == 0)
+ gtk_widget_set_sensitive (GTK_WIDGET (self), enabled);
+}
+
+static void
+ido_menu_item_action_state_changed (GActionGroup *action_group,
+ gchar *action_name,
+ GVariant *value,
+ gpointer user_data)
+{
+ IdoMenuItem *self = user_data;
+
+ if (g_strcmp0 (self->priv->action, action_name) == 0)
+ ido_menu_item_set_state (self, value);
+}
+
+static void
+ido_menu_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ IdoMenuItem *self = IDO_MENU_ITEM (object);
+
+ switch (property_id)
+ {
+ case PROP_MENU_ITEM:
+ ido_menu_item_set_menu_item (self, G_MENU_ITEM (g_value_get_object (value)));
+ break;
+
+ case PROP_ACTION_GROUP:
+ ido_menu_item_set_action_group (self, G_ACTION_GROUP (g_value_get_object (value)));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+ido_menu_item_dispose (GObject *object)
+{
+ IdoMenuItem *self = IDO_MENU_ITEM (object);
+
+ if (self->priv->action_group)
+ ido_menu_item_set_action_group (self, NULL);
+
+ g_clear_object (&self->priv->icon);
+ g_clear_object (&self->priv->label);
+
+ if (self->priv->target)
+ {
+ g_variant_unref (self->priv->target);
+ self->priv->target = NULL;
+ }
+
+ G_OBJECT_CLASS (ido_menu_item_parent_class)->dispose (object);
+}
+
+static void
+ido_menu_item_finalize (GObject *object)
+{
+ IdoMenuItemPrivate *priv = IDO_MENU_ITEM (object)->priv;
+
+ g_free (priv->action);
+
+ G_OBJECT_CLASS (ido_menu_item_parent_class)->finalize (object);
+}
+
+static void
+ido_menu_item_activate (GtkMenuItem *item)
+{
+ IdoMenuItemPrivate *priv = IDO_MENU_ITEM (item)->priv;
+
+ /* see ido_menu_item_set_active */
+ if (!priv->in_set_active && priv->action && priv->action_group)
+ g_action_group_activate_action (priv->action_group, priv->action, priv->target);
+
+ if (priv->in_set_active)
+ GTK_MENU_ITEM_CLASS (ido_menu_item_parent_class)->activate (item);
+}
+
+static void
+ido_menu_item_draw_indicator (GtkCheckMenuItem *item,
+ cairo_t *cr)
+{
+ IdoMenuItem *self = IDO_MENU_ITEM (item);
+
+ if (self->priv->has_indicator)
+ GTK_CHECK_MENU_ITEM_CLASS (ido_menu_item_parent_class)
+ ->draw_indicator (item, cr);
+}
+
+static void
+ido_menu_item_class_init (IdoMenuItemClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkMenuItemClass *menu_item_class = GTK_MENU_ITEM_CLASS (klass);
+ GtkCheckMenuItemClass *check_class = GTK_CHECK_MENU_ITEM_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (IdoMenuItemPrivate));
+
+ object_class->constructed = ido_menu_item_constructed;
+ object_class->set_property = ido_menu_set_property;
+ object_class->dispose = ido_menu_item_dispose;
+ object_class->finalize = ido_menu_item_finalize;
+
+ menu_item_class->activate = ido_menu_item_activate;
+
+ check_class->draw_indicator = ido_menu_item_draw_indicator;
+
+ properties[PROP_MENU_ITEM] = g_param_spec_object ("menu-item",
+ "Menu item",
+ "The model GMenuItem for this menu item",
+ G_TYPE_MENU_ITEM,
+ G_PARAM_WRITABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_ACTION_GROUP] = g_param_spec_object ("action-group",
+ "Action group",
+ "The action group associated with this menu item",
+ G_TYPE_ACTION_GROUP,
+ G_PARAM_WRITABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
+}
+
+static void
+ido_menu_item_init (IdoMenuItem *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ IDO_TYPE_MENU_ITEM,
+ IdoMenuItemPrivate);
+}
+
+void
+ido_menu_item_set_menu_item (IdoMenuItem *self,
+ GMenuItem *menuitem)
+{
+ gchar *iconstr = NULL;
+ GIcon *icon = NULL;
+ gchar *label = NULL;
+ gchar *action = NULL;
+
+ if (g_menu_item_get_attribute (menuitem, "x-canonical-icon", "s", &iconstr))
+ {
+ GError *error;
+
+ /* only indent the label if icon is set to "" */
+ if (iconstr[0] == '\0')
+ {
+ gint width;
+
+ gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &width, NULL);
+ gtk_widget_set_size_request (self->priv->icon, width, -1);
+ }
+ else
+ {
+ icon = g_icon_new_for_string (iconstr, &error);
+ if (icon == NULL)
+ {
+ g_warning ("unable to set icon: %s", error->message);
+ g_error_free (error);
+ }
+ }
+ g_free (iconstr);
+ }
+ gtk_image_set_from_gicon (GTK_IMAGE (self->priv->icon), icon, GTK_ICON_SIZE_MENU);
+
+ g_menu_item_get_attribute (menuitem, "label", "s", &label);
+ gtk_label_set_label (GTK_LABEL (self->priv->label), label ? label : "");
+
+ self->priv->target = g_menu_item_get_attribute_value (menuitem, "target", NULL);
+
+ g_menu_item_get_attribute (menuitem, "action", "s", &action);
+ ido_menu_item_set_action_name (self, action);
+
+ if (icon)
+ g_object_unref (icon);
+ g_free (label);
+ g_free (action);
+}
+
+void
+ido_menu_item_set_action_group (IdoMenuItem *self,
+ GActionGroup *action_group)
+{
+ IdoMenuItemPrivate *priv = self->priv;
+
+ if (priv->action_group != NULL)
+ {
+ g_signal_handlers_disconnect_by_func (priv->action_group, ido_menu_item_action_added, self);
+ g_signal_handlers_disconnect_by_func (priv->action_group, ido_menu_item_action_removed, self);
+ g_signal_handlers_disconnect_by_func (priv->action_group, ido_menu_item_action_enabled_changed, self);
+ g_signal_handlers_disconnect_by_func (priv->action_group, ido_menu_item_action_state_changed, self);
+
+ g_clear_object (&priv->action_group);
+ }
+
+ if (action_group != NULL)
+ {
+ priv->action_group = g_object_ref (action_group);
+
+ g_signal_connect (priv->action_group, "action-added",
+ G_CALLBACK (ido_menu_item_action_added), self);
+ g_signal_connect (priv->action_group, "action-removed",
+ G_CALLBACK (ido_menu_item_action_removed), self);
+ g_signal_connect (priv->action_group, "action-enabled-changed",
+ G_CALLBACK (ido_menu_item_action_enabled_changed), self);
+ g_signal_connect (priv->action_group, "action-state-changed",
+ G_CALLBACK (ido_menu_item_action_state_changed), self);
+ }
+}
=== added file 'src/ido-menu-item.h'
--- src/ido-menu-item.h 1970-01-01 00:00:00 +0000
+++ src/ido-menu-item.h 2013-06-07 21:39:23 +0000
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2012 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Lars Uebernickel <lars.uebernickel@xxxxxxxxxxxxx>
+ */
+
+#ifndef __IDO_MENU_ITEM_H__
+#define __IDO_MENU_ITEM_H__
+
+#include <gtk/gtk.h>
+
+#define IDO_TYPE_MENU_ITEM (ido_menu_item_get_type ())
+#define IDO_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IDO_TYPE_MENU_ITEM, IdoMenuItem))
+#define IDO_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), IDO_TYPE_MENU_ITEM, IdoMenuItemClass))
+#define IS_IDO_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IDO_TYPE_MENU_ITEM))
+#define IS_IDO_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), IDO_TYPE_MENU_ITEM))
+#define IDO_MENU_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), IDO_TYPE_MENU_ITEM, IdoMenuItemClass))
+
+typedef struct _IdoMenuItem IdoMenuItem;
+typedef struct _IdoMenuItemClass IdoMenuItemClass;
+typedef struct _IdoMenuItemPrivate IdoMenuItemPrivate;
+
+struct _IdoMenuItemClass
+{
+ GtkCheckMenuItemClass parent_class;
+};
+
+struct _IdoMenuItem
+{
+ GtkCheckMenuItem parent;
+ IdoMenuItemPrivate *priv;
+};
+
+GType ido_menu_item_get_type (void);
+
+void ido_menu_item_set_menu_item (IdoMenuItem *item,
+ GMenuItem *menuitem);
+void ido_menu_item_set_action_group (IdoMenuItem *self,
+ GActionGroup *action_group);
+
+#endif
=== added file 'src/im-app-menu-item.c'
--- src/im-app-menu-item.c 1970-01-01 00:00:00 +0000
+++ src/im-app-menu-item.c 2013-06-07 21:39:23 +0000
@@ -0,0 +1,351 @@
+/*
+ * 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@xxxxxxxxxxxxx>
+ */
+
+#include "im-app-menu-item.h"
+
+struct _ImAppMenuItemPrivate
+{
+ GActionGroup *action_group;
+ gchar *action;
+ gboolean is_running;
+
+ GtkWidget *icon;
+ GtkWidget *label;
+};
+
+enum
+{
+ PROP_0,
+ PROP_MENU_ITEM,
+ PROP_ACTION_GROUP,
+ NUM_PROPERTIES
+};
+
+static GParamSpec *properties[NUM_PROPERTIES];
+
+G_DEFINE_TYPE (ImAppMenuItem, im_app_menu_item, GTK_TYPE_MENU_ITEM);
+
+static void
+im_app_menu_item_constructed (GObject *object)
+{
+ ImAppMenuItemPrivate *priv = IM_APP_MENU_ITEM (object)->priv;
+ GtkWidget *grid;
+
+ priv->icon = g_object_ref (gtk_image_new ());
+ gtk_widget_set_margin_right (priv->icon, 6);
+
+ priv->label = g_object_ref (gtk_label_new (""));
+
+ grid = gtk_grid_new ();
+ gtk_grid_attach (GTK_GRID (grid), priv->icon, 0, 0, 1, 1);
+ gtk_grid_attach (GTK_GRID (grid), priv->label, 1, 0, 1, 1);
+
+ gtk_container_add (GTK_CONTAINER (object), grid);
+ gtk_widget_show_all (grid);
+
+ G_OBJECT_CLASS (im_app_menu_item_parent_class)->constructed (object);
+}
+
+static void
+im_app_menu_item_set_action_name (ImAppMenuItem *self,
+ const gchar *action_name)
+{
+ ImAppMenuItemPrivate *priv = self->priv;
+ gboolean enabled = FALSE;
+ GVariant *state;
+
+ if (priv->action != NULL)
+ g_free (priv->action);
+
+ priv->action = g_strdup (action_name);
+
+ priv->is_running = FALSE;
+
+ if (priv->action_group != NULL && priv->action != NULL &&
+ g_action_group_query_action (priv->action_group, priv->action,
+ &enabled, NULL, NULL, NULL, &state))
+ {
+ if (state && g_variant_is_of_type (state, G_VARIANT_TYPE ("b")))
+ priv->is_running = g_variant_get_boolean (state);
+ else
+ enabled = FALSE;
+
+ if (state)
+ g_variant_unref (state);
+ }
+
+ gtk_widget_set_sensitive (GTK_WIDGET (self), enabled);
+ gtk_widget_queue_draw (GTK_WIDGET (self));
+}
+
+static void
+im_app_menu_item_action_added (GActionGroup *action_group,
+ gchar *action_name,
+ gpointer user_data)
+{
+ ImAppMenuItem *self = user_data;
+
+ if (g_strcmp0 (self->priv->action, action_name) == 0)
+ im_app_menu_item_set_action_name (self, action_name);
+}
+
+static void
+im_app_menu_item_action_removed (GActionGroup *action_group,
+ gchar *action_name,
+ gpointer user_data)
+{
+ ImAppMenuItem *self = user_data;
+
+ if (g_strcmp0 (self->priv->action, action_name) == 0)
+ {
+ gtk_widget_set_sensitive (GTK_WIDGET (self), FALSE);
+ self->priv->is_running = FALSE;
+ gtk_widget_queue_draw (GTK_WIDGET (self));
+ }
+}
+
+static void
+im_app_menu_item_action_enabled_changed (GActionGroup *action_group,
+ gchar *action_name,
+ gboolean enabled,
+ gpointer user_data)
+{
+ ImAppMenuItem *self = user_data;
+
+ if (g_strcmp0 (self->priv->action, action_name) == 0)
+ gtk_widget_set_sensitive (GTK_WIDGET (self), enabled);
+}
+
+static void
+im_app_menu_item_action_state_changed (GActionGroup *action_group,
+ gchar *action_name,
+ GVariant *value,
+ gpointer user_data)
+{
+ ImAppMenuItem *self = user_data;
+
+ if (g_strcmp0 (self->priv->action, action_name) == 0)
+ {
+ g_return_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("b")));
+
+ self->priv->is_running = g_variant_get_boolean (value);
+ gtk_widget_queue_draw (GTK_WIDGET (self));
+ }
+}
+
+static void
+im_app_menu_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ ImAppMenuItem *self = IM_APP_MENU_ITEM (object);
+
+ switch (property_id)
+ {
+ case PROP_MENU_ITEM:
+ im_app_menu_item_set_menu_item (self, G_MENU_ITEM (g_value_get_object (value)));
+ break;
+
+ case PROP_ACTION_GROUP:
+ im_app_menu_item_set_action_group (self, G_ACTION_GROUP (g_value_get_object (value)));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+im_app_menu_item_dispose (GObject *object)
+{
+ ImAppMenuItem *self = IM_APP_MENU_ITEM (object);
+
+ if (self->priv->action_group)
+ im_app_menu_item_set_action_group (self, NULL);
+
+ g_clear_object (&self->priv->icon);
+ g_clear_object (&self->priv->label);
+
+ G_OBJECT_CLASS (im_app_menu_item_parent_class)->dispose (object);
+}
+
+static void
+im_app_menu_item_finalize (GObject *object)
+{
+ ImAppMenuItemPrivate *priv = IM_APP_MENU_ITEM (object)->priv;
+
+ g_free (priv->action);
+
+ G_OBJECT_CLASS (im_app_menu_item_parent_class)->finalize (object);
+}
+
+static gboolean
+im_app_menu_item_draw (GtkWidget *widget,
+ cairo_t *cr)
+{
+ ImAppMenuItemPrivate *priv = IM_APP_MENU_ITEM (widget)->priv;
+
+ GTK_WIDGET_CLASS (im_app_menu_item_parent_class)->draw (widget, cr);
+
+ if (priv->is_running)
+ {
+ const int arrow_width = 5;
+ const double half_arrow_height = 4.5;
+ GtkAllocation alloc;
+ GdkRGBA color;
+ double center;
+
+ gtk_widget_get_allocation (widget, &alloc);
+
+ gtk_style_context_get_color (gtk_widget_get_style_context (widget),
+ gtk_widget_get_state_flags (widget),
+ &color);
+ gdk_cairo_set_source_rgba (cr, &color);
+
+ center = alloc.height / 2 + 0.5;
+
+ cairo_move_to (cr, 0, center - half_arrow_height);
+ cairo_line_to (cr, 0, center + half_arrow_height);
+ cairo_line_to (cr, arrow_width, center);
+ cairo_close_path (cr);
+
+ cairo_fill (cr);
+ }
+
+ return FALSE;
+}
+
+static void
+im_app_menu_item_activate (GtkMenuItem *item)
+{
+ ImAppMenuItemPrivate *priv = IM_APP_MENU_ITEM (item)->priv;
+
+ if (priv->action && priv->action_group)
+ g_action_group_activate_action (priv->action_group, priv->action, NULL);
+}
+
+static void
+im_app_menu_item_class_init (ImAppMenuItemClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ GtkMenuItemClass *menu_item_class = GTK_MENU_ITEM_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (ImAppMenuItemPrivate));
+
+ object_class->constructed = im_app_menu_item_constructed;
+ object_class->set_property = im_app_menu_set_property;
+ object_class->dispose = im_app_menu_item_dispose;
+ object_class->finalize = im_app_menu_item_finalize;
+
+ widget_class->draw = im_app_menu_item_draw;
+
+ menu_item_class->activate = im_app_menu_item_activate;
+
+ properties[PROP_MENU_ITEM] = g_param_spec_object ("menu-item",
+ "Menu item",
+ "The model GMenuItem for this menu item",
+ G_TYPE_MENU_ITEM,
+ G_PARAM_WRITABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_ACTION_GROUP] = g_param_spec_object ("action-group",
+ "Action group",
+ "The action group associated with this menu item",
+ G_TYPE_ACTION_GROUP,
+ G_PARAM_WRITABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
+}
+
+static void
+im_app_menu_item_init (ImAppMenuItem *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ IM_TYPE_APP_MENU_ITEM,
+ ImAppMenuItemPrivate);
+}
+
+void
+im_app_menu_item_set_menu_item (ImAppMenuItem *self,
+ GMenuItem *menuitem)
+{
+ gchar *iconstr = NULL;
+ GIcon *icon = NULL;
+ gchar *label;
+ gchar *action = NULL;
+
+ if (g_menu_item_get_attribute (menuitem, "x-canonical-icon", "s", &iconstr))
+ {
+ GError *error;
+
+ icon = g_icon_new_for_string (iconstr, &error);
+ if (icon == NULL)
+ {
+ g_warning ("unable to set icon: %s", error->message);
+ g_error_free (error);
+ }
+ g_free (iconstr);
+ }
+ gtk_image_set_from_gicon (GTK_IMAGE (self->priv->icon), icon, GTK_ICON_SIZE_MENU);
+
+ g_menu_item_get_attribute (menuitem, "label", "s", &label);
+ gtk_label_set_label (GTK_LABEL (self->priv->label), label ? label : "");
+
+ g_menu_item_get_attribute (menuitem, "action", "s", &action);
+ im_app_menu_item_set_action_name (self, action);
+
+ if (icon)
+ g_object_unref (icon);
+ g_free (label);
+ g_free (action);
+}
+
+void
+im_app_menu_item_set_action_group (ImAppMenuItem *self,
+ GActionGroup *action_group)
+{
+ ImAppMenuItemPrivate *priv = self->priv;
+
+ if (priv->action_group != NULL)
+ {
+ g_signal_handlers_disconnect_by_func (priv->action_group, im_app_menu_item_action_added, self);
+ g_signal_handlers_disconnect_by_func (priv->action_group, im_app_menu_item_action_removed, self);
+ g_signal_handlers_disconnect_by_func (priv->action_group, im_app_menu_item_action_enabled_changed, self);
+ g_signal_handlers_disconnect_by_func (priv->action_group, im_app_menu_item_action_state_changed, self);
+
+ g_clear_object (&priv->action_group);
+ }
+
+ if (action_group != NULL)
+ {
+ priv->action_group = g_object_ref (action_group);
+
+ g_signal_connect (priv->action_group, "action-added",
+ G_CALLBACK (im_app_menu_item_action_added), self);
+ g_signal_connect (priv->action_group, "action-removed",
+ G_CALLBACK (im_app_menu_item_action_removed), self);
+ g_signal_connect (priv->action_group, "action-enabled-changed",
+ G_CALLBACK (im_app_menu_item_action_enabled_changed), self);
+ g_signal_connect (priv->action_group, "action-state-changed",
+ G_CALLBACK (im_app_menu_item_action_state_changed), self);
+ }
+}
=== added file 'src/im-app-menu-item.h'
--- src/im-app-menu-item.h 1970-01-01 00:00:00 +0000
+++ src/im-app-menu-item.h 2013-06-07 21:39:23 +0000
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2012 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Lars Uebernickel <lars.uebernickel@xxxxxxxxxxxxx>
+ */
+
+#ifndef __IM_APP_MENU_ITEM_H__
+#define __IM_APP_MENU_ITEM_H__
+
+#include <gtk/gtk.h>
+
+#define IM_TYPE_APP_MENU_ITEM (im_app_menu_item_get_type ())
+#define IM_APP_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IM_TYPE_APP_MENU_ITEM, ImAppMenuItem))
+#define IM_APP_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), IM_TYPE_APP_MENU_ITEM, ImAppMenuItemClass))
+#define IS_IM_APP_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IM_TYPE_APP_MENU_ITEM))
+#define IS_IM_APP_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), IM_TYPE_APP_MENU_ITEM))
+#define IM_APP_MENU_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), IM_TYPE_APP_MENU_ITEM, ImAppMenuItemClass))
+
+typedef struct _ImAppMenuItem ImAppMenuItem;
+typedef struct _ImAppMenuItemClass ImAppMenuItemClass;
+typedef struct _ImAppMenuItemPrivate ImAppMenuItemPrivate;
+
+struct _ImAppMenuItemClass
+{
+ GtkMenuItemClass parent_class;
+};
+
+struct _ImAppMenuItem
+{
+ GtkMenuItem parent;
+ ImAppMenuItemPrivate *priv;
+};
+
+GType im_app_menu_item_get_type (void);
+
+void im_app_menu_item_set_menu_item (ImAppMenuItem *item,
+ GMenuItem *menuitem);
+void im_app_menu_item_set_action_group (ImAppMenuItem *self,
+ GActionGroup *action_group);
+
+#endif
=== removed file 'src/im-menu-item.c'
--- src/im-menu-item.c 2011-01-14 19:35:21 +0000
+++ src/im-menu-item.c 1970-01-01 00:00:00 +0000
@@ -1,538 +0,0 @@
-/*
-An indicator to show information that is in messaging applications
-that the user is using.
-
-Copyright 2009 Canonical Ltd.
-
-Authors:
- Ted Gould <ted@xxxxxxxxxxxxx>
-
-This program is free software: you can redistribute it and/or modify it
-under the terms of the GNU General Public License version 3, as published
-by the Free Software Foundation.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranties of
-MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
-PURPOSE. See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along
-with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <glib/gi18n.h>
-#include <libdbusmenu-glib/client.h>
-#include <libindicate/indicator.h>
-#include <libindicate/indicator-messages.h>
-#include <libindicate/listener.h>
-#include "im-menu-item.h"
-#include "dbus-data.h"
-
-enum {
- TIME_CHANGED,
- ATTENTION_CHANGED,
- LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL] = { 0 };
-
-typedef struct _ImMenuItemPrivate ImMenuItemPrivate;
-
-struct _ImMenuItemPrivate
-{
- IndicateListener * listener;
- IndicateListenerServer * server;
- IndicateListenerIndicator * indicator;
-
- glong creation_seconds;
- glong seconds;
- gchar * count;
- gulong indicator_changed;
- gboolean attention;
- gboolean show;
-
- guint time_update_min;
-};
-
-#define IM_MENU_ITEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), IM_MENU_ITEM_TYPE, ImMenuItemPrivate))
-
-/* Prototypes */
-static void im_menu_item_class_init (ImMenuItemClass *klass);
-static void im_menu_item_init (ImMenuItem *self);
-static void im_menu_item_dispose (GObject *object);
-static void im_menu_item_finalize (GObject *object);
-static void sender_cb (IndicateListener * listener,
- IndicateListenerServer * server,
- IndicateListenerIndicator * indicator,
- gchar * property,
- const gchar * propertydata,
- gpointer data);
-static void time_cb (IndicateListener * listener,
- IndicateListenerServer * server,
- IndicateListenerIndicator * indicator,
- gchar * property,
- const GTimeVal * propertydata,
- gpointer data);
-static void icon_cb (IndicateListener * listener,
- IndicateListenerServer * server,
- IndicateListenerIndicator * indicator,
- gchar * property,
- const gchar * propertydata,
- gpointer data);
-static void activate_cb (ImMenuItem * self,
- guint timestamp,
- gpointer data);
-static void indicator_modified_cb (IndicateListener * listener,
- IndicateListenerServer * server,
- IndicateListenerIndicator * indicator,
- gchar * property,
- ImMenuItem * self);
-
-G_DEFINE_TYPE (ImMenuItem, im_menu_item, DBUSMENU_TYPE_MENUITEM);
-
-static void
-im_menu_item_class_init (ImMenuItemClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- g_type_class_add_private (klass, sizeof (ImMenuItemPrivate));
-
- object_class->dispose = im_menu_item_dispose;
- object_class->finalize = im_menu_item_finalize;
-
- signals[TIME_CHANGED] = g_signal_new(IM_MENU_ITEM_SIGNAL_TIME_CHANGED,
- G_TYPE_FROM_CLASS(klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ImMenuItemClass, time_changed),
- NULL, NULL,
- g_cclosure_marshal_VOID__LONG,
- G_TYPE_NONE, 1, G_TYPE_LONG);
- signals[ATTENTION_CHANGED] = g_signal_new(IM_MENU_ITEM_SIGNAL_ATTENTION_CHANGED,
- G_TYPE_FROM_CLASS(klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ImMenuItemClass, attention_changed),
- NULL, NULL,
- g_cclosure_marshal_VOID__BOOLEAN,
- G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
-
- return;
-}
-
-static void
-im_menu_item_init (ImMenuItem *self)
-{
- g_debug("Building new IM Menu Item");
- ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(self);
-
- /* Set the variables to NULL, but they should be
- configured further down the line. */
- priv->listener = NULL;
- priv->server = NULL;
- priv->indicator = NULL;
-
- /* A sane default, but look below */
- priv->creation_seconds = 0;
- priv->seconds = 0;
-
- /* Set the seconds to be the time when the item was
- created incase we're not given a better time. */
- GTimeVal current_time;
- g_get_current_time(¤t_time);
- priv->creation_seconds = current_time.tv_sec;
-
- return;
-}
-
-static void
-im_menu_item_dispose (GObject *object)
-{
- G_OBJECT_CLASS (im_menu_item_parent_class)->dispose (object);
-
- ImMenuItem * self = IM_MENU_ITEM(object);
- ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(self);
-
- if (priv->time_update_min != 0) {
- g_source_remove(priv->time_update_min);
- }
-
- g_signal_handler_disconnect(priv->listener, priv->indicator_changed);
- priv->indicator_changed = 0;
-
- return;
-}
-
-static void
-im_menu_item_finalize (GObject *object)
-{
- G_OBJECT_CLASS (im_menu_item_parent_class)->finalize (object);
-}
-
-/* Call back for getting icon data. It just passes it along
- to the indicator so that it can visualize it. Not our problem. */
-static void
-icon_cb (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * property, const gchar * propertydata, gpointer data)
-{
- dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(data), INDICATOR_MENUITEM_PROP_ICON, propertydata);
- return;
-}
-
-/* This function takes the time and turns it into the appropriate
- string to put on the right side of the menu item. Of course it
- doesn't do that if there is a count set. If there's a count then
- it gets that space. */
-static void
-update_time (ImMenuItem * self)
-{
- ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(self);
-
- /* Count has been set, so it takes priority. */
- if (priv->count != NULL) {
- return;
- }
-
- /* Seconds hasn't been set, so we just want to keep the time
- area blank. */
- if (priv->seconds == 0) {
- dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), INDICATOR_MENUITEM_PROP_RIGHT, "");
- return;
- }
-
- gchar * timestring = NULL;
-
- GTimeVal current_time;
- g_get_current_time(¤t_time);
-
- guint elapsed_seconds = current_time.tv_sec - priv->seconds;
- guint elapsed_minutes = elapsed_seconds / 60;
-
- if (elapsed_seconds % 60 > 55) {
- /* We're using fuzzy timers, so we need fuzzy comparisons */
- elapsed_minutes += 1;
- }
-
- if (elapsed_minutes < 60) {
- /* TRANSLATORS: This string is used to represent the number of minutes
- since an IM has occured. It is in the right column
- of a menu so being brief is desirable, but one character
- is not a requirement. */
- timestring = g_strdup_printf(ngettext("%d m", "%d m", elapsed_minutes), elapsed_minutes);
- } else {
- guint elapsed_hours = elapsed_minutes / 60;
-
- if (elapsed_minutes % 60 > 55) {
- /* We're using fuzzy timers, so we need fuzzy comparisons */
- elapsed_hours += 1;
- }
-
- /* TRANSLATORS: This string is used to represent the number of hours
- since an IM has occured. It is in the right column
- of a menu so being brief is desirable, but one character
- is not a requirement. */
- timestring = g_strdup_printf(ngettext("%d h", "%d h", elapsed_hours), elapsed_hours);
- }
-
- if (timestring != NULL) {
- dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), INDICATOR_MENUITEM_PROP_RIGHT, timestring);
- g_free(timestring);
- }
-
- return;
-}
-
-/* This is a wrapper around update_time that matches the prototype
- needed to make this a timer callback. Silly. */
-static gboolean
-time_update_cb (gpointer data)
-{
- ImMenuItem * self = IM_MENU_ITEM(data);
-
- update_time(self);
-
- return TRUE;
-}
-
-/* Yet another time function. This one takes the time as formated as
- we get it from libindicate and turns it into the seconds that we're
- looking for. It should only be called once at the init with a new
- indicator and again when the value changes. */
-static void
-time_cb (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * property, const GTimeVal * propertydata, gpointer data)
-{
- g_debug("Got Time info");
- ImMenuItem * self = IM_MENU_ITEM(data);
- if (self == NULL) {
- g_error("Menu Item callback called without a menu item");
- return;
- }
-
- if (property == NULL || g_strcmp0(property, "time")) {
- g_warning("Time callback called without being sent the time.");
- return;
- }
-
- ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(self);
-
- priv->seconds = propertydata->tv_sec;
-
- update_time(self);
-
- if (priv->time_update_min == 0) {
- priv->time_update_min = g_timeout_add_seconds(60, time_update_cb, self);
- }
-
- g_signal_emit(G_OBJECT(self), signals[TIME_CHANGED], 0, priv->seconds, TRUE);
-
- return;
-}
-
-/* Callback from libindicate that is for getting the sender information
- on a particular indicator. */
-static void
-sender_cb (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * property, const gchar * propertydata, gpointer data)
-{
- g_debug("Got Sender Information: %s", propertydata);
- ImMenuItem * self = IM_MENU_ITEM(data);
-
- /* Our data should be right */
- g_return_if_fail(self != NULL);
- /* We should have a property name */
- g_return_if_fail(property != NULL);
- /* The Property should be sender or name */
- g_return_if_fail(!g_strcmp0(property, "sender") || !g_strcmp0(property, INDICATE_INDICATOR_MESSAGES_PROP_NAME));
-
- /* We might get the sender variable returning a
- null string as it doesn't exist on newer clients
- but we don't want to listen to that. */
- if (!g_strcmp0(property, "sender") && propertydata[0] == '\0') {
- return;
- }
-
- dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), INDICATOR_MENUITEM_PROP_LABEL, propertydata);
-
- return;
-}
-
-/* Callback saying that the count is updated, we need to either put
- that on the menu item or just remove it if the count is gone. If
- that's the case we can update time. */
-static void
-count_cb (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * property, const gchar * propertydata, gpointer data)
-{
- g_debug("Got Count Information");
- ImMenuItem * self = IM_MENU_ITEM(data);
-
- /* Our data should be right */
- g_return_if_fail(self != NULL);
- /* We should have a property name */
- g_return_if_fail(property != NULL);
- /* The Property should be count */
- g_return_if_fail(!g_strcmp0(property, INDICATE_INDICATOR_MESSAGES_PROP_COUNT));
-
- ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(self);
-
- if (propertydata == NULL || propertydata[0] == '\0') {
- /* The count is either being unset or it was never
- set in the first place. */
- if (priv->count != NULL) {
- g_free(priv->count);
- priv->count = NULL;
- update_time(self);
- }
- return;
- }
-
- if (priv->count != NULL) {
- g_free(priv->count);
- }
-
- priv->count = g_strdup_printf("%s", propertydata);
- dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), INDICATOR_MENUITEM_PROP_RIGHT, priv->count);
-
- return;
-}
-
-/* This is getting the attention variable that's looking at whether
- this indicator should be calling for attention or not. If we are,
- we need to signal that. */
-static void
-attention_cb (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * property, GVariant * propertydata, gpointer data)
-{
- g_debug("Got Attention Information");
- ImMenuItem * self = IM_MENU_ITEM(data);
-
- /* Our data should be right */
- g_return_if_fail(self != NULL);
- /* We should have a property name */
- g_return_if_fail(property != NULL);
- /* The Property should be count */
- g_return_if_fail(!g_strcmp0(property, INDICATE_INDICATOR_MESSAGES_PROP_ATTENTION));
-
- ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(self);
-
- gboolean wantit;
- if (g_variant_is_of_type(propertydata, G_VARIANT_TYPE_BOOLEAN)) {
- wantit = g_variant_get_boolean(propertydata);
- } else if (g_variant_is_of_type(propertydata, G_VARIANT_TYPE_STRING)) {
- const gchar * propstring = g_variant_get_string(propertydata, NULL);
-
- if (propstring == NULL || propstring[0] == '\0' || !g_strcmp0(propstring, "false")) {
- wantit = FALSE;
- } else {
- wantit = TRUE;
- }
- } else {
- g_warning("Got property '%s' of an unknown type.", property);
- return;
- }
-
- if (priv->attention != wantit) {
- priv->attention = wantit;
- g_signal_emit(G_OBJECT(self), signals[ATTENTION_CHANGED], 0, wantit, TRUE);
- }
-
- return;
-}
-
-/* Callback when the item gets clicked on from the Messaging Menu */
-static void
-activate_cb (ImMenuItem * self, guint timestamp, gpointer data)
-{
- ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(self);
-
- indicate_listener_display(priv->listener, priv->server, priv->indicator, timestamp);
-}
-
-/* Callback when a property gets modified. It figures out which one
- got modified and notifies the appropriate person. */
-void
-indicator_modified_cb (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * property, ImMenuItem * self)
-{
- ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(self);
-
- /* Not meant for us */
- if (INDICATE_LISTENER_INDICATOR_ID(indicator) != INDICATE_LISTENER_INDICATOR_ID(priv->indicator)) return;
- if (server != priv->server) return;
-
- /* Determine which property has been changed and request the
- value go to the appropriate callback. */
- if (!g_strcmp0(property, INDICATE_INDICATOR_MESSAGES_PROP_NAME)) {
- indicate_listener_get_property(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_NAME, sender_cb, self);
- } else if (!g_strcmp0(property, INDICATE_INDICATOR_MESSAGES_PROP_TIME)) {
- indicate_listener_get_property_time(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_TIME, time_cb, self);
- } else if (!g_strcmp0(property, INDICATE_INDICATOR_MESSAGES_PROP_ICON)) {
- indicate_listener_get_property(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_ICON, icon_cb, self);
- } else if (!g_strcmp0(property, INDICATE_INDICATOR_MESSAGES_PROP_COUNT)) {
- indicate_listener_get_property(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_COUNT, count_cb, self);
- } else if (!g_strcmp0(property, INDICATE_INDICATOR_MESSAGES_PROP_ATTENTION)) {
- indicate_listener_get_property_variant(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_ATTENTION, attention_cb, self);
- } else if (!g_strcmp0(property, "sender")) {
- /* This is a compatibility string with v1 and should be removed */
- g_debug("Indicator is using 'sender' property which is a v1 string.");
- indicate_listener_get_property(listener, server, indicator, "sender", sender_cb, self);
- }
-
- return;
-}
-
-ImMenuItem *
-im_menu_item_new (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator)
-{
- ImMenuItem * self = g_object_new(IM_MENU_ITEM_TYPE, NULL);
-
- ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(self);
-
- priv->listener = listener;
- priv->server = server;
- priv->indicator = indicator;
- priv->count = NULL;
- priv->time_update_min = 0;
- priv->attention = FALSE;
- priv->show = TRUE;
-
- dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_TYPE, INDICATOR_MENUITEM_TYPE);
-
- indicate_listener_displayed(listener, server, indicator, TRUE);
-
- indicate_listener_get_property(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_NAME, sender_cb, self);
- indicate_listener_get_property_time(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_TIME, time_cb, self);
- indicate_listener_get_property(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_ICON, icon_cb, self);
- indicate_listener_get_property(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_COUNT, count_cb, self);
- indicate_listener_get_property_variant(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_ATTENTION, attention_cb, self);
- indicate_listener_get_property(listener, server, indicator, "sender", sender_cb, self);
-
- g_signal_connect(G_OBJECT(self), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(activate_cb), NULL);
- priv->indicator_changed = g_signal_connect(G_OBJECT(listener), INDICATE_LISTENER_SIGNAL_INDICATOR_MODIFIED, G_CALLBACK(indicator_modified_cb), self);
-
- return self;
-}
-
-/* Gets the number of seconds for the creator
- of this item. */
-glong
-im_menu_item_get_seconds (ImMenuItem * menuitem)
-{
- g_return_val_if_fail(IS_IM_MENU_ITEM(menuitem), 0);
-
- ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(menuitem);
-
- if (priv->seconds == 0) {
- return priv->creation_seconds;
- } else {
- return priv->seconds;
- }
-}
-
-/* Gets whether or not this indicator item is
- asking for attention or not. */
-gboolean
-im_menu_item_get_attention (ImMenuItem * menuitem)
-{
- g_return_val_if_fail(IS_IM_MENU_ITEM(menuitem), FALSE);
-
- ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(menuitem);
- return priv->attention;
-}
-
-/* This takes care of items that need to be hidden, this is
- usually because they go over the count of allowed indicators.
- Which is more than a little bit silly. We shouldn't do that.
- But we need to enforce it to save users against bad apps. */
-void
-im_menu_item_show (ImMenuItem * menuitem, gboolean show)
-{
- g_return_if_fail(IS_IM_MENU_ITEM(menuitem));
-
- ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(menuitem);
-
- if (priv->show == show) {
- return;
- }
-
- priv->show = show;
- /* Tell the app what we're doing to it. If it's being
- punished it needs to know about it. */
- indicate_listener_displayed(priv->listener, priv->server, priv->indicator, priv->show);
- if (priv->attention) {
- /* If we were asking for attention we can ask for it
- again if we're being shown, otherwise no. */
- g_signal_emit(G_OBJECT(menuitem), signals[ATTENTION_CHANGED], 0, priv->show, TRUE);
- }
- dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(menuitem), DBUSMENU_MENUITEM_PROP_VISIBLE, priv->show ? "true" : "false");
-
- return;
-}
-
-/* Check to see if this item is shown. Accessor for the
- internal variable. */
-gboolean
-im_menu_item_shown (ImMenuItem * menuitem)
-{
- g_return_val_if_fail(IS_IM_MENU_ITEM(menuitem), FALSE);
-
- ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(menuitem);
-
- return priv->show;
-}
=== removed file 'src/im-menu-item.h'
--- src/im-menu-item.h 2009-09-04 22:31:29 +0000
+++ src/im-menu-item.h 1970-01-01 00:00:00 +0000
@@ -1,67 +0,0 @@
-/*
-An indicator to show information that is in messaging applications
-that the user is using.
-
-Copyright 2009 Canonical Ltd.
-
-Authors:
- Ted Gould <ted@xxxxxxxxxxxxx>
-
-This program is free software: you can redistribute it and/or modify it
-under the terms of the GNU General Public License version 3, as published
-by the Free Software Foundation.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranties of
-MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
-PURPOSE. See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along
-with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-#ifndef __IM_MENU_ITEM_H__
-#define __IM_MENU_ITEM_H__
-
-#include <glib.h>
-#include <glib-object.h>
-
-#include <libdbusmenu-glib/menuitem.h>
-#include <libindicate/listener.h>
-
-G_BEGIN_DECLS
-
-#define IM_MENU_ITEM_TYPE (im_menu_item_get_type ())
-#define IM_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IM_MENU_ITEM_TYPE, ImMenuItem))
-#define IM_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), IM_MENU_ITEM_TYPE, ImMenuItemClass))
-#define IS_IM_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IM_MENU_ITEM_TYPE))
-#define IS_IM_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), IM_MENU_ITEM_TYPE))
-#define IM_MENU_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), IM_MENU_ITEM_TYPE, ImMenuItemClass))
-
-#define IM_MENU_ITEM_SIGNAL_TIME_CHANGED "time-changed"
-#define IM_MENU_ITEM_SIGNAL_ATTENTION_CHANGED "attention-changed"
-
-typedef struct _ImMenuItem ImMenuItem;
-typedef struct _ImMenuItemClass ImMenuItemClass;
-
-struct _ImMenuItemClass {
- DbusmenuMenuitemClass parent_class;
-
- void (*time_changed) (glong seconds);
- void (*attention_changed) (gboolean requestit);
-};
-
-struct _ImMenuItem {
- DbusmenuMenuitem parent;
-};
-
-GType im_menu_item_get_type (void);
-ImMenuItem * im_menu_item_new (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator);
-glong im_menu_item_get_seconds (ImMenuItem * menuitem);
-gboolean im_menu_item_get_attention (ImMenuItem * menuitem);
-void im_menu_item_show (ImMenuItem * menuitem, gboolean show);
-gboolean im_menu_item_shown (ImMenuItem * menuitem);
-
-G_END_DECLS
-
-#endif
-
=== added file 'src/im-source-menu-item.c'
--- src/im-source-menu-item.c 1970-01-01 00:00:00 +0000
+++ src/im-source-menu-item.c 2013-06-07 21:39:23 +0000
@@ -0,0 +1,407 @@
+/*
+ * 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@xxxxxxxxxxxxx>
+ */
+
+#include "im-source-menu-item.h"
+
+#include <libintl.h>
+#include "ido-detail-label.h"
+
+struct _ImSourceMenuItemPrivate
+{
+ GActionGroup *action_group;
+ gchar *action;
+
+ GtkWidget *icon;
+ GtkWidget *label;
+ GtkWidget *detail;
+
+ gint64 time;
+ guint timer_id;
+};
+
+enum
+{
+ PROP_0,
+ PROP_MENU_ITEM,
+ PROP_ACTION_GROUP,
+ NUM_PROPERTIES
+};
+
+static GParamSpec *properties[NUM_PROPERTIES];
+
+G_DEFINE_TYPE (ImSourceMenuItem, im_source_menu_item, GTK_TYPE_MENU_ITEM);
+
+static void
+im_source_menu_item_constructed (GObject *object)
+{
+ ImSourceMenuItemPrivate *priv = IM_SOURCE_MENU_ITEM (object)->priv;
+ GtkWidget *grid;
+ gint icon_width;
+
+ gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_width, NULL);
+
+ priv->icon = g_object_ref (gtk_image_new ());
+ 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 (ido_detail_label_new (""));
+ gtk_widget_set_halign (priv->detail, GTK_ALIGN_END);
+ gtk_widget_set_hexpand (priv->detail, TRUE);
+ gtk_style_context_add_class (gtk_widget_get_style_context (priv->detail), "accelerator");
+
+ grid = gtk_grid_new ();
+ gtk_grid_attach (GTK_GRID (grid), priv->icon, 0, 0, 1, 1);
+ gtk_grid_attach (GTK_GRID (grid), priv->label, 1, 0, 1, 1);
+ gtk_grid_attach (GTK_GRID (grid), priv->detail, 2, 0, 1, 1);
+
+ gtk_container_add (GTK_CONTAINER (object), grid);
+ gtk_widget_show_all (grid);
+
+ G_OBJECT_CLASS (im_source_menu_item_parent_class)->constructed (object);
+}
+
+static gchar *
+im_source_menu_item_time_span_string (gint64 timestamp)
+{
+ gchar *str;
+ gint64 span;
+ gint hours;
+ gint minutes;
+
+ span = MAX (g_get_real_time () - timestamp, 0) / G_USEC_PER_SEC;
+ hours = span / 3600;
+ minutes = (span / 60) % 60;
+
+ if (hours == 0)
+ {
+ /* TRANSLATORS: number of minutes that have passed */
+ str = g_strdup_printf (ngettext ("%d m", "%d m", minutes), minutes);
+ }
+ else
+ {
+ /* TRANSLATORS: number of hours that have passed */
+ str = g_strdup_printf (ngettext ("%d h", "%d h", hours), hours);
+ }
+
+ return str;
+}
+
+static 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;
+
+ im_source_menu_item_set_detail_time (self, self->priv->time);
+
+ return TRUE;
+}
+
+static gboolean
+im_source_menu_item_set_state (ImSourceMenuItem *self,
+ GVariant *state)
+{
+ ImSourceMenuItemPrivate *priv = self->priv;
+ guint32 count;
+ gint64 time;
+ const gchar *str;
+
+ if (priv->timer_id != 0)
+ {
+ g_source_remove (priv->timer_id);
+ priv->timer_id = 0;
+ }
+
+ g_return_val_if_fail (g_variant_is_of_type (state, G_VARIANT_TYPE ("(uxsb)")), FALSE);
+
+ g_variant_get (state, "(ux&sb)", &count, &time, &str, NULL);
+
+ if (count != 0)
+ ido_detail_label_set_count (IDO_DETAIL_LABEL (priv->detail), count);
+ else if (time != 0)
+ {
+ 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)
+ ido_detail_label_set_text (IDO_DETAIL_LABEL (priv->detail), str);
+
+ return TRUE;
+}
+
+static void
+im_source_menu_item_set_action_name (ImSourceMenuItem *self,
+ const gchar *action_name)
+{
+ ImSourceMenuItemPrivate *priv = self->priv;
+ gboolean enabled = FALSE;
+ GVariant *state;
+
+ if (priv->action != NULL)
+ g_free (priv->action);
+
+ priv->action = g_strdup (action_name);
+
+ if (priv->action_group != NULL && priv->action != NULL &&
+ g_action_group_query_action (priv->action_group, priv->action,
+ &enabled, NULL, NULL, NULL, &state))
+ {
+ if (!state || !im_source_menu_item_set_state (self, state))
+ enabled = FALSE;
+
+ if (state)
+ g_variant_unref (state);
+ }
+
+ gtk_widget_set_sensitive (GTK_WIDGET (self), enabled);
+}
+
+static void
+im_source_menu_item_action_added (GActionGroup *action_group,
+ gchar *action_name,
+ gpointer user_data)
+{
+ ImSourceMenuItem *self = user_data;
+
+ if (g_strcmp0 (self->priv->action, action_name) == 0)
+ im_source_menu_item_set_action_name (self, action_name);
+}
+
+static void
+im_source_menu_item_action_removed (GActionGroup *action_group,
+ gchar *action_name,
+ gpointer user_data)
+{
+ ImSourceMenuItem *self = user_data;
+
+ if (g_strcmp0 (self->priv->action, action_name) == 0)
+ {
+ gtk_widget_set_sensitive (GTK_WIDGET (self), FALSE);
+ }
+}
+
+static void
+im_source_menu_item_action_enabled_changed (GActionGroup *action_group,
+ gchar *action_name,
+ gboolean enabled,
+ gpointer user_data)
+{
+ ImSourceMenuItem *self = user_data;
+
+ if (g_strcmp0 (self->priv->action, action_name) == 0)
+ gtk_widget_set_sensitive (GTK_WIDGET (self), enabled);
+}
+
+static void
+im_source_menu_item_action_state_changed (GActionGroup *action_group,
+ gchar *action_name,
+ GVariant *value,
+ gpointer user_data)
+{
+ ImSourceMenuItem *self = user_data;
+
+ if (g_strcmp0 (self->priv->action, action_name) == 0)
+ im_source_menu_item_set_state (self, value);
+}
+
+static void
+im_source_menu_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ ImSourceMenuItem *self = IM_SOURCE_MENU_ITEM (object);
+
+ switch (property_id)
+ {
+ case PROP_MENU_ITEM:
+ im_source_menu_item_set_menu_item (self, G_MENU_ITEM (g_value_get_object (value)));
+ break;
+
+ case PROP_ACTION_GROUP:
+ im_source_menu_item_set_action_group (self, G_ACTION_GROUP (g_value_get_object (value)));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+im_source_menu_item_dispose (GObject *object)
+{
+ ImSourceMenuItem *self = IM_SOURCE_MENU_ITEM (object);
+
+ if (self->priv->timer_id != 0)
+ {
+ g_source_remove (self->priv->timer_id);
+ self->priv->timer_id = 0;
+ }
+
+ if (self->priv->action_group)
+ im_source_menu_item_set_action_group (self, NULL);
+
+ g_clear_object (&self->priv->icon);
+ g_clear_object (&self->priv->label);
+ g_clear_object (&self->priv->detail);
+
+ G_OBJECT_CLASS (im_source_menu_item_parent_class)->dispose (object);
+}
+
+static void
+im_source_menu_item_finalize (GObject *object)
+{
+ ImSourceMenuItemPrivate *priv = IM_SOURCE_MENU_ITEM (object)->priv;
+
+ g_free (priv->action);
+
+ G_OBJECT_CLASS (im_source_menu_item_parent_class)->finalize (object);
+}
+
+static void
+im_source_menu_item_activate (GtkMenuItem *item)
+{
+ ImSourceMenuItemPrivate *priv = IM_SOURCE_MENU_ITEM (item)->priv;
+
+ if (priv->action && priv->action_group)
+ g_action_group_activate_action (priv->action_group, priv->action, NULL);
+}
+
+static void
+im_source_menu_item_class_init (ImSourceMenuItemClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkMenuItemClass *menu_item_class = GTK_MENU_ITEM_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (ImSourceMenuItemPrivate));
+
+ object_class->constructed = im_source_menu_item_constructed;
+ object_class->set_property = im_source_menu_set_property;
+ object_class->dispose = im_source_menu_item_dispose;
+ object_class->finalize = im_source_menu_item_finalize;
+
+ menu_item_class->activate = im_source_menu_item_activate;
+
+ properties[PROP_MENU_ITEM] = g_param_spec_object ("menu-item",
+ "Menu item",
+ "The model GMenuItem for this menu item",
+ G_TYPE_MENU_ITEM,
+ G_PARAM_WRITABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_ACTION_GROUP] = g_param_spec_object ("action-group",
+ "Action group",
+ "The action group associated with this menu item",
+ G_TYPE_ACTION_GROUP,
+ G_PARAM_WRITABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
+}
+
+static void
+im_source_menu_item_init (ImSourceMenuItem *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ IM_TYPE_SOURCE_MENU_ITEM,
+ ImSourceMenuItemPrivate);
+}
+
+void
+im_source_menu_item_set_menu_item (ImSourceMenuItem *self,
+ GMenuItem *menuitem)
+{
+ gchar *iconstr = NULL;
+ GIcon *icon = NULL;
+ gchar *label;
+ gchar *action = NULL;
+
+ if (g_menu_item_get_attribute (menuitem, "x-canonical-icon", "s", &iconstr))
+ {
+ GError *error;
+ icon = g_icon_new_for_string (iconstr, &error);
+ if (icon == NULL)
+ {
+ g_warning ("unable to set icon: %s", error->message);
+ g_error_free (error);
+ }
+ g_free (iconstr);
+ }
+ gtk_image_set_from_gicon (GTK_IMAGE (self->priv->icon), icon, GTK_ICON_SIZE_MENU);
+
+ g_menu_item_get_attribute (menuitem, "label", "s", &label);
+ gtk_label_set_label (GTK_LABEL (self->priv->label), label ? label : "");
+
+ g_menu_item_get_attribute (menuitem, "action", "s", &action);
+ im_source_menu_item_set_action_name (self, action);
+
+ if (icon)
+ g_object_unref (icon);
+ g_free (label);
+ g_free (action);
+}
+
+void
+im_source_menu_item_set_action_group (ImSourceMenuItem *self,
+ GActionGroup *action_group)
+{
+ ImSourceMenuItemPrivate *priv = self->priv;
+
+ if (priv->action_group != NULL)
+ {
+ g_signal_handlers_disconnect_by_func (priv->action_group, im_source_menu_item_action_added, self);
+ g_signal_handlers_disconnect_by_func (priv->action_group, im_source_menu_item_action_removed, self);
+ g_signal_handlers_disconnect_by_func (priv->action_group, im_source_menu_item_action_enabled_changed, self);
+ g_signal_handlers_disconnect_by_func (priv->action_group, im_source_menu_item_action_state_changed, self);
+
+ g_clear_object (&priv->action_group);
+ }
+
+ if (action_group != NULL)
+ {
+ priv->action_group = g_object_ref (action_group);
+
+ g_signal_connect (priv->action_group, "action-added",
+ G_CALLBACK (im_source_menu_item_action_added), self);
+ g_signal_connect (priv->action_group, "action-removed",
+ G_CALLBACK (im_source_menu_item_action_removed), self);
+ g_signal_connect (priv->action_group, "action-enabled-changed",
+ G_CALLBACK (im_source_menu_item_action_enabled_changed), self);
+ g_signal_connect (priv->action_group, "action-state-changed",
+ G_CALLBACK (im_source_menu_item_action_state_changed), self);
+ }
+}
=== added file 'src/im-source-menu-item.h'
--- src/im-source-menu-item.h 1970-01-01 00:00:00 +0000
+++ src/im-source-menu-item.h 2013-06-07 21:39:23 +0000
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2012 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ * Lars Uebernickel <lars.uebernickel@xxxxxxxxxxxxx>
+ */
+
+#ifndef __IM_SOURCE_MENU_ITEM_H__
+#define __IM_SOURCE_MENU_ITEM_H__
+
+#include <gtk/gtk.h>
+
+#define IM_TYPE_SOURCE_MENU_ITEM (im_source_menu_item_get_type ())
+#define IM_SOURCE_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), IM_TYPE_SOURCE_MENU_ITEM, ImSourceMenuItem))
+#define IM_SOURCE_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), IM_TYPE_SOURCE_MENU_ITEM, ImSourceMenuItemClass))
+#define IS_IM_SOURCE_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IM_TYPE_SOURCE_MENU_ITEM))
+#define IS_IM_SOURCE_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), IM_TYPE_SOURCE_MENU_ITEM))
+#define IM_SOURCE_MENU_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), IM_TYPE_SOURCE_MENU_ITEM, ImSourceMenuItemClass))
+
+typedef struct _ImSourceMenuItem ImSourceMenuItem;
+typedef struct _ImSourceMenuItemClass ImSourceMenuItemClass;
+typedef struct _ImSourceMenuItemPrivate ImSourceMenuItemPrivate;
+
+struct _ImSourceMenuItemClass
+{
+ GtkMenuItemClass parent_class;
+};
+
+struct _ImSourceMenuItem
+{
+ GtkMenuItem parent;
+ ImSourceMenuItemPrivate *priv;
+};
+
+GType im_source_menu_item_get_type (void);
+
+void im_source_menu_item_set_menu_item (ImSourceMenuItem *item,
+ GMenuItem *menuitem);
+void im_source_menu_item_set_action_group (ImSourceMenuItem *self,
+ GActionGroup *action_group);
+
+#endif
=== removed file 'src/indicator-messages-status-provider-0.5.pc.in.in'
--- src/indicator-messages-status-provider-0.5.pc.in.in 2011-07-08 19:46:06 +0000
+++ src/indicator-messages-status-provider-0.5.pc.in.in 1970-01-01 00:00:00 +0000
@@ -1,15 +0,0 @@
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libdir=@libdir@
-bindir=@bindir@
-includedir=@includedir@
-
-statusproviderdir=@status_provider_dir@
-
-Cflags: -I${includedir}/indicator-messages-status-provider-0.@status_provider_api_version@
-Requires: gobject-2.0
-Libs: -L${libdir} -lindicator-messages-status-provider
-
-Name: indicator-messages-status-provider
-Description: Status providers for the indicator-messages menu.
-Version: @VERSION@
=== modified file 'src/indicator-messages.c'
--- src/indicator-messages.c 2011-09-21 20:14:17 +0000
+++ src/indicator-messages.c 2013-06-07 21:39:23 +0000
@@ -2,10 +2,11 @@
An indicator to show information that is in messaging applications
that the user is using.
-Copyright 2009 Canonical Ltd.
+Copyright 2012 Canonical Ltd.
Authors:
Ted Gould <ted@xxxxxxxxxxxxx>
+ Lars Uebernickel <lars.uebernickel@xxxxxxxxxxxxx>
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
@@ -20,27 +21,24 @@
with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "config.h"
+
#include <string.h>
+#include <math.h>
#include <glib.h>
#include <glib-object.h>
-#include <glib/gi18n.h>
+#include <glib/gi18n-lib.h>
#include <gtk/gtk.h>
-#if GTK_CHECK_VERSION(3, 0, 0)
-#include <libdbusmenu-gtk3/menu.h>
-#include <libdbusmenu-gtk3/menuitem.h>
-#else
-#include <libdbusmenu-gtk/menu.h>
-#include <libdbusmenu-gtk/menuitem.h>
-#endif
-
#include <libindicator/indicator.h>
#include <libindicator/indicator-object.h>
-#include <libindicator/indicator-image-helper.h>
#include <libindicator/indicator-service-manager.h>
#include "dbus-data.h"
-#include "gen-messages-service.xml.h"
+
+#include "ido-menu-item.h"
+#include "im-app-menu-item.h"
+#include "im-source-menu-item.h"
#define INDICATOR_MESSAGES_TYPE (indicator_messages_get_type ())
#define INDICATOR_MESSAGES(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), INDICATOR_MESSAGES_TYPE, IndicatorMessages))
@@ -49,22 +47,21 @@
#define IS_INDICATOR_MESSAGES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), INDICATOR_MESSAGES_TYPE))
#define INDICATOR_MESSAGES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), INDICATOR_MESSAGES_TYPE, IndicatorMessagesClass))
-#define M_PI 3.1415926535897932384626433832795028841971693993751
-
-#define RIGHT_LABEL_FONT_SIZE 12
-#define RIGHT_LABEL_RADIUS 20
-
typedef struct _IndicatorMessages IndicatorMessages;
typedef struct _IndicatorMessagesClass IndicatorMessagesClass;
struct _IndicatorMessagesClass {
IndicatorObjectClass parent_class;
- void (*update_a11y_desc) (IndicatorServiceManager * service, gpointer * user_data);
};
struct _IndicatorMessages {
IndicatorObject parent;
IndicatorServiceManager * service;
+ GActionGroup *actions;
+ GMenuModel *menu;
+ GtkWidget *image;
+ GtkWidget *gtkmenu;
+ gchar *accessible_desc;
};
GType indicator_messages_get_type (void);
@@ -73,53 +70,34 @@
INDICATOR_SET_VERSION
INDICATOR_SET_TYPE(INDICATOR_MESSAGES_TYPE)
-/* Globals */
-static GtkWidget * main_image = NULL;
-static GDBusProxy * icon_proxy = NULL;
-static GtkSizeGroup * indicator_right_group = NULL;
-static GDBusNodeInfo * bus_node_info = NULL;
-static GDBusInterfaceInfo * bus_interface_info = NULL;
-static const gchar * accessible_desc = NULL;
-static IndicatorObject * indicator = NULL;
-
/* Prototypes */
static void indicator_messages_class_init (IndicatorMessagesClass *klass);
static void indicator_messages_init (IndicatorMessages *self);
static void indicator_messages_dispose (GObject *object);
static void indicator_messages_finalize (GObject *object);
-static GtkImage * get_icon (IndicatorObject * io);
+static void service_connection_changed (IndicatorServiceManager *sm,
+ gboolean connected,
+ gpointer user_data);
+static GtkImage * get_image (IndicatorObject * io);
static GtkMenu * get_menu (IndicatorObject * io);
-static void indicator_messages_middle_click (IndicatorObject * io,
- IndicatorObjectEntry * entry,
- guint time, gpointer data);
static const gchar * get_accessible_desc (IndicatorObject * io);
-static void connection_change (IndicatorServiceManager * sm,
- gboolean connected,
- gpointer user_data);
+static const gchar * get_name_hint (IndicatorObject * io);
+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);
-static void
-update_a11y_desc (void)
-{
- g_return_if_fail(IS_INDICATOR_MESSAGES(indicator));
-
- GList *entries = indicator_object_get_entries(indicator);
- IndicatorObjectEntry * entry = (IndicatorObjectEntry *)entries->data;
-
- entry->accessible_desc = get_accessible_desc(indicator);
-
- g_signal_emit(G_OBJECT(indicator),
- INDICATOR_OBJECT_SIGNAL_ACCESSIBLE_DESC_UPDATE_ID,
- 0,
- entry,
- TRUE);
-
- g_list_free(entries);
-
- return;
-}
-
/* Initialize the one-timers */
static void
indicator_messages_class_init (IndicatorMessagesClass *klass)
@@ -131,46 +109,30 @@
IndicatorObjectClass * io_class = INDICATOR_OBJECT_CLASS(klass);
- io_class->get_image = get_icon;
+ io_class->get_image = get_image;
io_class->get_menu = get_menu;
io_class->get_accessible_desc = get_accessible_desc;
- io_class->secondary_activate = indicator_messages_middle_click;
-
- if (bus_node_info == NULL) {
- GError * error = NULL;
-
- bus_node_info = g_dbus_node_info_new_for_xml(_messages_service, &error);
- if (error != NULL) {
- g_error("Unable to parse Messaging Menu Interface description: %s", error->message);
- g_error_free(error);
- }
- }
-
- if (bus_interface_info == NULL) {
- bus_interface_info = g_dbus_node_info_lookup_interface(bus_node_info, INDICATOR_MESSAGES_DBUS_SERVICE_INTERFACE);
-
- if (bus_interface_info == NULL) {
- g_error("Unable to find interface '" INDICATOR_MESSAGES_DBUS_SERVICE_INTERFACE "'");
- }
- }
-
- return;
+ io_class->get_name_hint = get_name_hint;
}
/* Build up our per-instance variables */
static void
indicator_messages_init (IndicatorMessages *self)
{
- /* Default values */
- self->service = NULL;
-
- /* Complex stuff */
self->service = indicator_service_manager_new_version(INDICATOR_MESSAGES_DBUS_NAME, 1);
- g_signal_connect(self->service, INDICATOR_SERVICE_MANAGER_SIGNAL_CONNECTION_CHANGE, G_CALLBACK(connection_change), self);
-
- indicator = INDICATOR_OBJECT(self);
-
- return;
+ g_signal_connect (self->service, "connection-change",
+ G_CALLBACK (service_connection_changed), self);
+
+ self->gtkmenu = gtk_menu_new ();
+ g_object_ref_sink (self->gtkmenu);
+
+ self->image = g_object_ref_sink (gtk_image_new ());
+
+ /* make sure custom menu item types are registered (so that
+ * gtk_model_new_from_menu can pick them up */
+ ido_menu_item_get_type ();
+ im_app_menu_item_get_type ();
+ im_source_menu_item_get_type ();
}
/* Unref stuff */
@@ -180,10 +142,11 @@
IndicatorMessages * self = INDICATOR_MESSAGES(object);
g_return_if_fail(self != NULL);
- if (self->service != NULL) {
- g_object_unref(self->service);
- self->service = NULL;
- }
+ g_clear_object (&self->service);
+ g_clear_object (&self->actions);
+ g_clear_object (&self->menu);
+ g_clear_object (&self->gtkmenu);
+ g_clear_object (&self->image);
G_OBJECT_CLASS (indicator_messages_parent_class)->dispose (object);
return;
@@ -193,6 +156,9 @@
static void
indicator_messages_finalize (GObject *object)
{
+ IndicatorMessages *self = INDICATOR_MESSAGES (object);
+
+ g_free (self->accessible_desc);
G_OBJECT_CLASS (indicator_messages_parent_class)->finalize (object);
return;
@@ -202,617 +168,215 @@
/* Functions */
-/* Signal off of the proxy */
-static void
-proxy_signal (GDBusProxy * proxy, const gchar * sender, const gchar * signal, GVariant * params, gpointer user_data)
-{
- gboolean prop = g_variant_get_boolean(g_variant_get_child_value(params, 0));
-
- if (g_strcmp0("AttentionChanged", signal) == 0) {
- if (prop) {
- indicator_image_helper_update(GTK_IMAGE(main_image), "indicator-messages-new");
- accessible_desc = _("New Messages");
- } else {
- indicator_image_helper_update(GTK_IMAGE(main_image), "indicator-messages");
- accessible_desc = _("Messages");
- }
- } else if (g_strcmp0("IconChanged", signal) == 0) {
- if (prop) {
- gtk_widget_hide(main_image);
- } else {
- gtk_widget_show(main_image);
- }
- } else {
- g_warning("Unknown signal %s", signal);
- }
-
- update_a11y_desc();
-
- return;
-}
-
-/* Callback from getting the attention status from the service. */
-static void
-attention_cb (GObject * object, GAsyncResult * ares, gpointer user_data)
-{
- GError * error = NULL;
- GVariant * res = g_dbus_proxy_call_finish(G_DBUS_PROXY(object), ares, &error);
-
- if (error != NULL) {
- g_warning("Unable to get attention status: %s", error->message);
- g_error_free(error);
- return;
- }
-
- gboolean prop = g_variant_get_boolean(g_variant_get_child_value(res, 0));
-
- if (prop) {
- indicator_image_helper_update(GTK_IMAGE(main_image), "indicator-messages-new");
- accessible_desc = _("New Messages");
- } else {
- indicator_image_helper_update(GTK_IMAGE(main_image), "indicator-messages");
- accessible_desc = _("Messages");
- }
-
- update_a11y_desc();
-
- return;
-}
-
-/* Change from getting the icon visibility from the service */
-static void
-icon_cb (GObject * object, GAsyncResult * ares, gpointer user_data)
-{
- GError * error = NULL;
- GVariant * res = g_dbus_proxy_call_finish(G_DBUS_PROXY(object), ares, &error);
-
- if (error != NULL) {
- g_warning("Unable to get icon visibility: %s", error->message);
- g_error_free(error);
- return;
- }
-
- gboolean prop = g_variant_get_boolean(g_variant_get_child_value(res, 0));
-
- if (prop) {
- gtk_widget_hide(main_image);
- } else {
- gtk_widget_show(main_image);
- }
-
- return;
-}
-
-static guint connection_drop_timeout = 0;
-
-/* Resets the icon to not having messages if we can't get a good
- answer on it from the service. */
-static gboolean
-connection_drop_cb (gpointer user_data)
-{
- if (main_image != NULL) {
- indicator_image_helper_update(GTK_IMAGE(main_image), "indicator-messages");
- }
- connection_drop_timeout = 0;
- return FALSE;
-}
-
-/* Proxy is setup now.. whoo! */
-static void
-proxy_ready_cb (GObject * obj, GAsyncResult * res, gpointer user_data)
-{
- GError * error = NULL;
- GDBusProxy * proxy = g_dbus_proxy_new_for_bus_finish(res, &error);
-
- if (error != NULL) {
- g_warning("Unable to get proxy of service: %s", error->message);
- g_error_free(error);
- return;
- }
-
- icon_proxy = proxy;
-
- g_signal_connect(G_OBJECT(proxy), "g-signal", G_CALLBACK(proxy_signal), user_data);
-
- g_dbus_proxy_call(icon_proxy,
- "AttentionRequested",
- NULL, /* params */
- G_DBUS_CALL_FLAGS_NONE,
- -1, /* timeout */
- NULL, /* cancel */
- attention_cb,
- user_data);
- g_dbus_proxy_call(icon_proxy,
- "IconShown",
- NULL, /* params */
- G_DBUS_CALL_FLAGS_NONE,
- -1, /* timeout */
- NULL, /* cancel */
- icon_cb,
- user_data);
-
- return;
-}
-
-/* Sets up all the icon information in the proxy. */
-static void
-connection_change (IndicatorServiceManager * sm, gboolean connected, gpointer user_data)
-{
- if (connection_drop_timeout != 0) {
- g_source_remove(connection_drop_timeout);
- connection_drop_timeout = 0;
- }
-
- if (!connected) {
- /* Ensure that we're not saying there are messages
- when we don't have a connection. */
- connection_drop_timeout = g_timeout_add(400, connection_drop_cb, NULL);
- return;
- }
-
- if (icon_proxy == NULL) {
- g_dbus_proxy_new_for_bus(G_BUS_TYPE_SESSION,
- G_DBUS_PROXY_FLAGS_NONE,
- bus_interface_info,
- INDICATOR_MESSAGES_DBUS_NAME,
- INDICATOR_MESSAGES_DBUS_SERVICE_OBJECT,
- INDICATOR_MESSAGES_DBUS_SERVICE_INTERFACE,
- NULL, /* cancel */
- proxy_ready_cb,
- sm);
- } else {
- g_dbus_proxy_call(icon_proxy,
- "AttentionRequested",
- NULL, /* params */
- G_DBUS_CALL_FLAGS_NONE,
- -1, /* timeout */
- NULL, /* cancel */
- attention_cb,
- sm);
- g_dbus_proxy_call(icon_proxy,
- "IconShown",
- NULL, /* params */
- G_DBUS_CALL_FLAGS_NONE,
- -1, /* timeout */
- NULL, /* cancel */
- icon_cb,
- sm);
- }
-
- return;
-}
-
-/* Sets the icon when it changes. */
-static void
-application_icon_change_cb (DbusmenuMenuitem * mi, gchar * prop, GVariant * value, gpointer user_data)
-{
- if (!g_strcmp0(prop, APPLICATION_MENUITEM_PROP_ICON)) {
- /* Set the main icon */
- if (GTK_IS_IMAGE(user_data)) {
- gtk_image_set_from_icon_name(GTK_IMAGE(user_data), g_variant_get_string(value, NULL), GTK_ICON_SIZE_MENU);
- }
- }
-
- return;
-}
-
-/* Sets the label when it changes. */
-static void
-application_prop_change_cb (DbusmenuMenuitem * mi, gchar * prop, GVariant * value, gpointer user_data)
-{
- if (!g_strcmp0(prop, APPLICATION_MENUITEM_PROP_NAME)) {
- /* Set the main label */
- if (GTK_IS_LABEL(user_data)) {
- gtk_label_set_text(GTK_LABEL(user_data), g_variant_get_string(value, NULL));
- }
- }
-
- if (!g_strcmp0(prop, APPLICATION_MENUITEM_PROP_RUNNING)) {
- /* TODO: should hide/show the triangle live if the menu was open.
- In practice, this is rarely needed. */
- }
-
- return;
-}
-
-/* Draws a triangle on the left, using fg[STATE_TYPE] color. */
-#if GTK_CHECK_VERSION(3, 0, 0)
-static gboolean
-application_triangle_draw_cb (GtkWidget *widget, cairo_t *cr, gpointer data)
-{
-#else
-static gboolean
-application_triangle_draw_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data)
-{
- cairo_t *cr;
-#endif
- GtkAllocation allocation;
- GtkStyle *style;
- int x, y, arrow_width, arrow_height;
-
- if (!GTK_IS_WIDGET (widget)) return FALSE;
- if (!DBUSMENU_IS_MENUITEM (data)) return FALSE;
-
- /* render the triangle indicator only if the application is running */
- if (! dbusmenu_menuitem_property_get_bool (DBUSMENU_MENUITEM(data), APPLICATION_MENUITEM_PROP_RUNNING))
- return FALSE;;
-
- /* get style */
- style = gtk_widget_get_style (widget);
-
- /* set arrow position / dimensions */
- arrow_width = 5; /* the pixel-based reference triangle is 5x9 */
- arrow_height = 9;
- gtk_widget_get_allocation (widget, &allocation);
-#if GTK_CHECK_VERSION(3, 0, 0)
- x = 0;
- y = allocation.height/2.0 - (double)arrow_height/2.0;
-#else
- x = allocation.x;
- y = allocation.y + allocation.height/2.0 - (double)arrow_height/2.0;
-#endif
-
-#if GTK_CHECK_VERSION(3, 0, 0)
- cairo_save (cr);
-#else
- /* initialize cairo drawing area */
- cr = (cairo_t*) gdk_cairo_create (gtk_widget_get_window (widget));
-#endif
-
- /* set line width */
- cairo_set_line_width (cr, 1.0);
-
- /* cairo drawing code */
- cairo_move_to (cr, x, y);
- cairo_line_to (cr, x, y + arrow_height);
- cairo_line_to (cr, x + arrow_width, y + (double)arrow_height/2.0);
- cairo_close_path (cr);
- cairo_set_source_rgb (cr, style->fg[gtk_widget_get_state(widget)].red/65535.0,
- style->fg[gtk_widget_get_state(widget)].green/65535.0,
- style->fg[gtk_widget_get_state(widget)].blue/65535.0);
- cairo_fill (cr);
-
-#if GTK_CHECK_VERSION(3, 0, 0)
- cairo_restore (cr);
-#else
- /* remember to destroy cairo context to avoid leaks */
- cairo_destroy (cr);
-#endif
-
- return FALSE;
-}
-
-/* Custom function to draw rounded rectangle with max radius */
-static void
-custom_cairo_rounded_rectangle (cairo_t *cr,
- double x, double y, double w, double h)
-{
- double radius = MIN (w/2.0, h/2.0);
-
- cairo_move_to (cr, x+radius, y);
- cairo_arc (cr, x+w-radius, y+radius, radius, M_PI*1.5, M_PI*2);
- cairo_arc (cr, x+w-radius, y+h-radius, radius, 0, M_PI*0.5);
- cairo_arc (cr, x+radius, y+h-radius, radius, M_PI*0.5, M_PI);
- cairo_arc (cr, x+radius, y+radius, radius, M_PI, M_PI*1.5);
-}
-
-/* Draws a rounded rectangle with text inside. */
-#if GTK_CHECK_VERSION(3, 0, 0)
-static gboolean
-numbers_draw_cb (GtkWidget *widget, cairo_t *cr, gpointer data)
-{
-#else
-static gboolean
-numbers_draw_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data)
-{
- cairo_t *cr;
-#endif
- GtkAllocation allocation;
- GtkStyle *style;
- double x, y, w, h;
- PangoLayout * layout;
- gint font_size = RIGHT_LABEL_FONT_SIZE;
-
- if (!GTK_IS_WIDGET (widget)) return FALSE;
-
- /* get style */
- style = gtk_widget_get_style (widget);
-
- /* set arrow position / dimensions */
- gtk_widget_get_allocation (widget, &allocation);
-#if GTK_CHECK_VERSION(3, 0, 0)
- x = 0;
- y = 0;
-#else
- x = allocation.x;
- y = allocation.y;
-#endif
- w = allocation.width;
- h = allocation.height;
-
- layout = gtk_label_get_layout (GTK_LABEL(widget));
-
- /* This does not work, don't ask me why but font_size is 0.
- * I wanted to use a dynamic font size to adjust the padding on left/right edges
- * of the rounded rectangle. Andrea Cimitan */
- /* const PangoFontDescription * font_description = pango_layout_get_font_description (layout);
- font_size = pango_font_description_get_size (font_description); */
-
-#if GTK_CHECK_VERSION(3, 0, 0)
- cairo_save (cr);
-#else
- /* initialize cairo drawing area */
- cr = (cairo_t*) gdk_cairo_create (gtk_widget_get_window (widget));
-#endif
-
- /* set line width */
- cairo_set_line_width (cr, 1.0);
-
- cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
-
- /* cairo drawing code */
- custom_cairo_rounded_rectangle (cr, x - font_size/2.0, y, w + font_size, h);
-
- cairo_set_source_rgba (cr, style->fg[gtk_widget_get_state(widget)].red/65535.0,
- style->fg[gtk_widget_get_state(widget)].green/65535.0,
- style->fg[gtk_widget_get_state(widget)].blue/65535.0, 0.5);
-
- cairo_move_to (cr, x, y);
- pango_cairo_layout_path (cr, layout);
- cairo_fill (cr);
-
-#if GTK_CHECK_VERSION(3, 0, 0)
- cairo_restore (cr);
-#else
- /* remember to destroy cairo context to avoid leaks */
- cairo_destroy (cr);
-#endif
-
- return TRUE;
-}
-
-/* Builds a menu item representing a running application in the
- messaging menu */
-static gboolean
-new_application_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client, gpointer user_data)
-{
- g_debug ("%s (\"%s\")", __func__, dbusmenu_menuitem_property_get(newitem, APPLICATION_MENUITEM_PROP_NAME));
-
- GtkMenuItem * gmi = GTK_MENU_ITEM(gtk_image_menu_item_new());
- gtk_image_menu_item_set_always_show_image(GTK_IMAGE_MENU_ITEM(gmi), TRUE);
-
- /* Set the minimum size, we always want it to take space */
- gint width, height;
- gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height);
-
- GtkWidget * icon = gtk_image_new_from_icon_name(dbusmenu_menuitem_property_get(newitem, APPLICATION_MENUITEM_PROP_ICON), GTK_ICON_SIZE_MENU);
- gtk_widget_set_size_request(icon, width
- + 5 /* ref triangle is 5x9 pixels */
- + 2 /* padding */,
- height);
- gtk_misc_set_alignment(GTK_MISC(icon), 1.0 /* right aligned */, 0.5);
- gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(gmi), icon);
- gtk_widget_show(icon);
-
- /* Application name in a label */
- GtkWidget * label = gtk_label_new(dbusmenu_menuitem_property_get(newitem, APPLICATION_MENUITEM_PROP_NAME));
- gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
- gtk_widget_show(label);
-
- /* Insert the hbox */
- gtk_container_add(GTK_CONTAINER(gmi), label);
-
- /* Attach some of the standard GTK stuff */
- dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, gmi, parent);
-
- /* Make sure we can handle the label changing */
- g_signal_connect(G_OBJECT(newitem), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(application_prop_change_cb), label);
- g_signal_connect(G_OBJECT(newitem), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(application_icon_change_cb), icon);
-#if GTK_CHECK_VERSION(3, 0, 0)
- g_signal_connect_after(G_OBJECT (gmi), "draw", G_CALLBACK (application_triangle_draw_cb), newitem);
-#else
- g_signal_connect_after(G_OBJECT (gmi), "expose_event", G_CALLBACK (application_triangle_draw_cb), newitem);
-#endif
-
- return TRUE;
-}
-
-typedef struct _indicator_item_t indicator_item_t;
-struct _indicator_item_t {
- GtkWidget * icon;
- GtkWidget * label;
- GtkWidget * right;
-};
-
-/* Whenever we have a property change on a DbusmenuMenuitem
- we need to be responsive to that. */
-static void
-indicator_prop_change_cb (DbusmenuMenuitem * mi, gchar * prop, GVariant * value, indicator_item_t * mi_data)
-{
- if (!g_strcmp0(prop, INDICATOR_MENUITEM_PROP_LABEL)) {
- /* Set the main label */
- gtk_label_set_text(GTK_LABEL(mi_data->label), g_variant_get_string(value, NULL));
- } else if (!g_strcmp0(prop, INDICATOR_MENUITEM_PROP_RIGHT)) {
- /* Set the right label */
- gtk_label_set_text(GTK_LABEL(mi_data->right), g_variant_get_string(value, NULL));
- } else if (!g_strcmp0(prop, INDICATOR_MENUITEM_PROP_ICON)) {
- /* We don't use the value here, which is probably less efficient,
- but it's easier to use the easy function. And since th value
- is already cached, shouldn't be a big deal really. */
- GdkPixbuf * pixbuf = dbusmenu_menuitem_property_get_image(mi, INDICATOR_MENUITEM_PROP_ICON);
- if (pixbuf != NULL) {
- /* If we've got a pixbuf we need to make sure it's of a reasonable
- size to fit in the menu. If not, rescale it. */
- GdkPixbuf * resized_pixbuf;
- gint width, height;
- gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height);
- if (gdk_pixbuf_get_width(pixbuf) > width ||
- gdk_pixbuf_get_height(pixbuf) > height) {
- g_debug("Resizing icon from %dx%d to %dx%d", gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf), width, height);
- resized_pixbuf = gdk_pixbuf_scale_simple(pixbuf,
- width,
- height,
- GDK_INTERP_BILINEAR);
- g_object_unref(pixbuf);
- } else {
- g_debug("Happy with icon sized %dx%d", gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf));
- resized_pixbuf = pixbuf;
- }
-
- gtk_image_set_from_pixbuf(GTK_IMAGE(mi_data->icon), resized_pixbuf);
-
- g_object_unref(resized_pixbuf);
-
- gtk_widget_show(mi_data->icon);
- } else {
- gtk_widget_hide(mi_data->icon);
- }
- }
-
- return;
-}
-
-/* We have a small little menuitem type that handles all
- of the fun stuff for indicators. Mostly this is the
- shifting over and putting the icon in with some right
- side text that'll be determined by the service. */
-static gboolean
-new_indicator_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client, gpointer user_data)
-{
- g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE);
- g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE);
- /* Note: not checking parent, it's reasonable for it to be NULL */
-
- indicator_item_t * mi_data = g_new0(indicator_item_t, 1);
-
- GtkMenuItem * gmi = GTK_MENU_ITEM(gtk_menu_item_new());
-
- gint padding = 4;
- gint font_size = RIGHT_LABEL_FONT_SIZE;
- gtk_widget_style_get(GTK_WIDGET(gmi), "toggle-spacing", &padding, NULL);
-
- GtkWidget * hbox = gtk_hbox_new(FALSE, padding);
-
- /* Icon, probably someone's face or avatar on an IM */
- mi_data->icon = gtk_image_new();
-
- /* Set the minimum size, we always want it to take space */
- gint width, height;
- gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &width, &height);
- gtk_widget_set_size_request(mi_data->icon, width, height);
-
- GdkPixbuf * pixbuf = dbusmenu_menuitem_property_get_image(newitem, INDICATOR_MENUITEM_PROP_ICON);
- if (pixbuf != NULL) {
- /* If we've got a pixbuf we need to make sure it's of a reasonable
- size to fit in the menu. If not, rescale it. */
- GdkPixbuf * resized_pixbuf;
- if (gdk_pixbuf_get_width(pixbuf) > width ||
- gdk_pixbuf_get_height(pixbuf) > height) {
- g_debug("Resizing icon from %dx%d to %dx%d", gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf), width, height);
- resized_pixbuf = gdk_pixbuf_scale_simple(pixbuf,
- width,
- height,
- GDK_INTERP_BILINEAR);
- g_object_unref(pixbuf);
- } else {
- g_debug("Happy with icon sized %dx%d", gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf));
- resized_pixbuf = pixbuf;
- }
-
- gtk_image_set_from_pixbuf(GTK_IMAGE(mi_data->icon), resized_pixbuf);
-
- g_object_unref(resized_pixbuf);
- }
- gtk_misc_set_alignment(GTK_MISC(mi_data->icon), 0.0, 0.5);
- gtk_box_pack_start(GTK_BOX(hbox), mi_data->icon, FALSE, FALSE, 0);
-
- if (pixbuf != NULL) {
- gtk_widget_show(mi_data->icon);
- }
-
- /* Label, probably a username, chat room or mailbox name */
- mi_data->label = gtk_label_new(dbusmenu_menuitem_property_get(newitem, INDICATOR_MENUITEM_PROP_LABEL));
- gtk_misc_set_alignment(GTK_MISC(mi_data->label), 0.0, 0.5);
- gtk_box_pack_start(GTK_BOX(hbox), mi_data->label, TRUE, TRUE, 0);
- gtk_widget_show(mi_data->label);
-
- /* Usually either the time or the count on the individual
- item. */
- mi_data->right = gtk_label_new(dbusmenu_menuitem_property_get(newitem, INDICATOR_MENUITEM_PROP_RIGHT));
- gtk_size_group_add_widget(indicator_right_group, mi_data->right);
- /* install extra decoration overlay */
-#if GTK_CHECK_VERSION(3, 0, 0)
- g_signal_connect (G_OBJECT (mi_data->right), "draw",
- G_CALLBACK (numbers_draw_cb), NULL);
-#else
- g_signal_connect (G_OBJECT (mi_data->right), "expose_event",
- G_CALLBACK (numbers_draw_cb), NULL);
-#endif
-
- gtk_misc_set_alignment(GTK_MISC(mi_data->right), 1.0, 0.5);
- gtk_box_pack_start(GTK_BOX(hbox), mi_data->right, FALSE, FALSE, padding + font_size/2.0);
- gtk_widget_show(mi_data->right);
-
- gtk_container_add(GTK_CONTAINER(gmi), hbox);
- gtk_widget_show(hbox);
-
- dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, gmi, parent);
-
- g_signal_connect(G_OBJECT(newitem), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(indicator_prop_change_cb), mi_data);
- g_object_weak_ref(G_OBJECT(newitem), (GWeakNotify)g_free, mi_data);
-
- return TRUE;
-}
-
-/* Builds the main image icon using the libindicator helper. */
+static void service_connection_changed (IndicatorServiceManager *sm,
+ gboolean connected,
+ gpointer user_data)
+{
+ IndicatorMessages *self = user_data;
+ GDBusConnection *bus;
+ GError *error = NULL;
+
+ if (self->actions != NULL) {
+ g_signal_handlers_disconnect_by_func (self->actions, messages_action_added, self);
+ g_signal_handlers_disconnect_by_func (self->actions, messages_state_changed, self);
+ g_clear_object (&self->actions);
+ }
+ if (self->menu != NULL) {
+ g_signal_handlers_disconnect_by_func (self->menu, menu_items_changed, self);
+ g_clear_object (&self->menu);
+ }
+ gtk_menu_shell_bind_model (GTK_MENU_SHELL (self->gtkmenu), NULL, NULL, FALSE);
+
+ if (connected == FALSE)
+ return;
+
+ bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
+ if (!bus) {
+ g_warning ("error connecting to the session bus: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ self->actions = G_ACTION_GROUP (g_dbus_action_group_get (bus,
+ INDICATOR_MESSAGES_DBUS_NAME,
+ INDICATOR_MESSAGES_DBUS_OBJECT));
+ gtk_widget_insert_action_group (self->gtkmenu,
+ get_name_hint (INDICATOR_OBJECT (self)),
+ self->actions);
+ g_signal_connect (self->actions, "action-added::messages",
+ G_CALLBACK (messages_action_added), self);
+ g_signal_connect (self->actions, "action-state-changed::messages",
+ G_CALLBACK (messages_state_changed), self);
+
+ self->menu = G_MENU_MODEL (g_dbus_menu_model_get (bus,
+ INDICATOR_MESSAGES_DBUS_NAME,
+ INDICATOR_MESSAGES_DBUS_OBJECT));
+ g_signal_connect (self->menu, "items-changed", G_CALLBACK (menu_items_changed), self);
+
+ 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);
+}
+
static GtkImage *
-get_icon (IndicatorObject * io)
+get_image (IndicatorObject * io)
{
- main_image = GTK_WIDGET(indicator_image_helper("indicator-messages"));
- gtk_widget_show(main_image);
+ IndicatorMessages *self = INDICATOR_MESSAGES (io);
- return GTK_IMAGE(main_image);
+ gtk_widget_show (self->image);
+ return GTK_IMAGE (self->image);
}
-/* Builds the menu for the indicator */
static GtkMenu *
get_menu (IndicatorObject * io)
{
- indicator_right_group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
-
- DbusmenuGtkMenu * menu = dbusmenu_gtkmenu_new(INDICATOR_MESSAGES_DBUS_NAME, INDICATOR_MESSAGES_DBUS_OBJECT);
- DbusmenuGtkClient * client = dbusmenu_gtkmenu_get_client(menu);
-
- dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), INDICATOR_MENUITEM_TYPE, new_indicator_item);
- dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), APPLICATION_MENUITEM_TYPE, new_application_item);
-
- return GTK_MENU(menu);
+ IndicatorMessages *self = INDICATOR_MESSAGES (io);
+
+ return GTK_MENU (self->gtkmenu);
}
-/* Returns the accessible description of the indicator */
static const gchar *
get_accessible_desc (IndicatorObject * io)
{
- return accessible_desc;
-}
-
-/* Hide the notifications on middle-click over the indicator-messages */
-static void
-indicator_messages_middle_click (IndicatorObject * io, IndicatorObjectEntry * entry,
- guint time, gpointer data)
-{
- if (icon_proxy == NULL) {
- return;
- }
-
- g_dbus_proxy_call(icon_proxy,
- "ClearAttention",
- NULL, /* params */
- G_DBUS_CALL_FLAGS_NONE,
- -1, /* timeout */
- NULL, /* cancel */
- NULL,
- NULL);
-
- return;
+ IndicatorMessages *self = INDICATOR_MESSAGES (io);
+ return self->accessible_desc;
+}
+
+static const gchar *
+get_name_hint (IndicatorObject *io)
+{
+ return PACKAGE;
+}
+
+static void
+indicator_messages_accessible_desc_updated (IndicatorMessages *self)
+{
+ GList *entries;
+
+ entries = indicator_object_get_entries (INDICATOR_OBJECT (self));
+ g_return_if_fail (entries != NULL);
+
+ g_signal_emit_by_name (self, INDICATOR_OBJECT_SIGNAL_ACCESSIBLE_DESC_UPDATE, entries->data);
+
+ g_list_free (entries);
+}
+
+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_item_attribute (menu, index, attribute, "s", &iconstr)) {
+ GError *error;
+
+ icon = g_icon_new_for_string (iconstr, &error);
+ if (icon == NULL) {
+ g_warning ("unable to load icon: %s", error->message);
+ g_error_free (error);
+ }
+
+ g_free (iconstr);
+ }
+
+ return icon;
+}
+
+static void
+indicator_messages_add_toplevel_menu (IndicatorMessages *self)
+{
+ GIcon *icon;
+ GMenuModel *popup;
+
+ indicator_object_set_visible (INDICATOR_OBJECT (self), TRUE);
+
+ 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);
+ }
+
+ 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);
+ }
+
+ 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 (popup);
+ }
+}
+
+static void
+menu_items_changed (GMenuModel *menu,
+ gint position,
+ gint removed,
+ gint added,
+ gpointer user_data)
+{
+ IndicatorMessages *self = user_data;
+
+ 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,
+ gpointer user_data)
+{
+ IndicatorMessages *self = user_data;
+
+ indicator_messages_update_icon (self, value);
}
=== removed file 'src/launcher-menu-item.c'
--- src/launcher-menu-item.c 2011-04-06 16:20:08 +0000
+++ src/launcher-menu-item.c 1970-01-01 00:00:00 +0000
@@ -1,392 +0,0 @@
-/*
-An indicator to show information that is in messaging applications
-that the user is using.
-
-Copyright 2009 Canonical Ltd.
-
-Authors:
- Ted Gould <ted@xxxxxxxxxxxxx>
-
-This program is free software: you can redistribute it and/or modify it
-under the terms of the GNU General Public License version 3, as published
-by the Free Software Foundation.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranties of
-MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
-PURPOSE. See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along
-with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <gdk/gdk.h>
-#include <glib/gi18n.h>
-#include <gio/gdesktopappinfo.h>
-#include <libindicator/indicator-desktop-shortcuts.h>
-#include "launcher-menu-item.h"
-#include "dbus-data.h"
-#include "default-applications.h"
-#include "seen-db.h"
-
-enum {
- NAME_CHANGED,
- LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL] = { 0 };
-
-typedef struct _LauncherMenuItemPrivate LauncherMenuItemPrivate;
-struct _LauncherMenuItemPrivate
-{
- GAppInfo * appinfo;
- GKeyFile * keyfile;
- gchar * desktop;
- IndicatorDesktopShortcuts * ids;
- GList * shortcuts;
-};
-
-#define LAUNCHER_MENU_ITEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), LAUNCHER_MENU_ITEM_TYPE, LauncherMenuItemPrivate))
-
-#define NICK_DATA "ids-nick-data"
-
-/* Prototypes */
-static void launcher_menu_item_class_init (LauncherMenuItemClass *klass);
-static void launcher_menu_item_init (LauncherMenuItem *self);
-static void launcher_menu_item_dispose (GObject *object);
-static void launcher_menu_item_finalize (GObject *object);
-static void activate_cb (LauncherMenuItem * self, guint timestamp, gpointer data);
-static void nick_activate_cb (LauncherMenuItem * self, guint timestamp, gpointer data);
-
-
-G_DEFINE_TYPE (LauncherMenuItem, launcher_menu_item, DBUSMENU_TYPE_MENUITEM);
-
-static void
-launcher_menu_item_class_init (LauncherMenuItemClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- g_type_class_add_private (klass, sizeof (LauncherMenuItemPrivate));
-
- object_class->dispose = launcher_menu_item_dispose;
- object_class->finalize = launcher_menu_item_finalize;
-
- signals[NAME_CHANGED] = g_signal_new(LAUNCHER_MENU_ITEM_SIGNAL_NAME_CHANGED,
- G_TYPE_FROM_CLASS(klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (LauncherMenuItemClass, name_changed),
- NULL, NULL,
- g_cclosure_marshal_VOID__STRING,
- G_TYPE_NONE, 1, G_TYPE_STRING);
-
- return;
-}
-
-static void
-launcher_menu_item_init (LauncherMenuItem *self)
-{
- g_debug("Building new Launcher Menu Item");
- LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(self);
-
- priv->appinfo = NULL;
- priv->desktop = NULL;
- priv->keyfile = NULL;
-
- priv->ids = NULL;
- priv->shortcuts = NULL;
-
- dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_TYPE, APPLICATION_MENUITEM_TYPE);
-
- return;
-}
-
-static void
-func_unref (gpointer data, gpointer user_data)
-{
- g_object_unref(G_OBJECT(data));
- return;
-}
-
-static void
-launcher_menu_item_dispose (GObject *object)
-{
- LauncherMenuItem * self = LAUNCHER_MENU_ITEM(object);
- LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(self);
-
- if (priv->appinfo != NULL) {
- g_object_unref(priv->appinfo);
- priv->appinfo = NULL;
- }
-
- if (priv->keyfile != NULL) {
- g_object_unref(priv->keyfile);
- priv->keyfile = NULL;
- }
-
- if (priv->ids != NULL) {
- g_object_unref(priv->ids);
- priv->ids = NULL;
- }
-
- if (priv->shortcuts != NULL) {
- g_list_foreach(priv->shortcuts, func_unref, NULL);
- g_list_free(priv->shortcuts);
- priv->shortcuts = NULL;
- }
-
- G_OBJECT_CLASS (launcher_menu_item_parent_class)->dispose (object);
-}
-
-static void
-launcher_menu_item_finalize (GObject *object)
-{
- LauncherMenuItem * self = LAUNCHER_MENU_ITEM(object);
- LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(self);
-
- if (priv->desktop != NULL) {
- g_free(priv->desktop);
- priv->desktop = NULL;
- }
-
- G_OBJECT_CLASS (launcher_menu_item_parent_class)->finalize (object);
-
- return;
-}
-
-LauncherMenuItem *
-launcher_menu_item_new (const gchar * desktop_file)
-{
- LauncherMenuItem * self = g_object_new(LAUNCHER_MENU_ITEM_TYPE, NULL);
- g_debug("\tDesktop file: %s", desktop_file);
-
- LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(self);
-
- /* Parse the desktop file we've been given. */
- priv->appinfo = G_APP_INFO(g_desktop_app_info_new_from_filename(desktop_file));
- priv->keyfile = g_key_file_new();
- g_key_file_load_from_file(priv->keyfile, desktop_file, G_KEY_FILE_NONE, NULL);
- priv->desktop = g_strdup(desktop_file);
-
- /* Set the appropriate values on this menu item based on the
- app info that we've parsed */
- g_debug("\tName: %s", launcher_menu_item_get_name(self));
-
- const gchar * default_name = NULL;
-
- if (seen_db_seen(desktop_file)) {
- default_name = get_default_name(desktop_file);
- } else {
- default_name = get_default_setup(desktop_file);
- }
-
- if (default_name == NULL) {
- dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_LABEL, launcher_menu_item_get_name(self));
- } else {
- dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_LABEL, _(default_name));
- }
-
- gchar * iconstr;
- if (default_name == NULL) {
- iconstr = launcher_menu_item_get_icon(self);
- } else {
- iconstr = g_strdup(get_default_icon(desktop_file));
- }
- dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_ICON_NAME, iconstr);
- g_free(iconstr);
- dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
-
- g_signal_connect(G_OBJECT(self), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(activate_cb), NULL);
-
- /* Start to build static shortcuts */
- if (seen_db_seen(desktop_file)) {
- priv->ids = indicator_desktop_shortcuts_new(priv->desktop, "Messaging Menu");
- const gchar ** nicks = indicator_desktop_shortcuts_get_nicks(priv->ids);
- gint i;
- for (i = 0; nicks[i] != NULL; i++) {
- DbusmenuMenuitem * mi = dbusmenu_menuitem_new();
- dbusmenu_menuitem_property_set(mi, DBUSMENU_MENUITEM_PROP_TYPE, APPLICATION_MENUITEM_TYPE);
- g_object_set_data(G_OBJECT(mi), NICK_DATA, (gpointer)nicks[i]);
-
- dbusmenu_menuitem_property_set(mi, DBUSMENU_MENUITEM_PROP_LABEL, indicator_desktop_shortcuts_nick_get_name(priv->ids, nicks[i]));
- g_signal_connect(G_OBJECT(mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(nick_activate_cb), self);
-
- priv->shortcuts = g_list_append(priv->shortcuts, mi);
- }
- }
-
- /* Check to see if we should be eclipsed */
- if (priv->appinfo == NULL) {
- launcher_menu_item_set_eclipsed(self, TRUE);
- }
-
- return self;
-}
-
-const gchar *
-launcher_menu_item_get_name (LauncherMenuItem * appitem)
-{
- LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(appitem);
-
- if (priv->appinfo == NULL) {
- return NULL;
- } else {
- return g_app_info_get_name(priv->appinfo);
- }
-}
-
-/* Respond to one of the shortcuts getting clicked on. */
-static void
-nick_activate_cb (LauncherMenuItem * self, guint timestamp, gpointer data)
-{
- gchar * nick = (gchar *)g_object_get_data(G_OBJECT(self), NICK_DATA);
- LauncherMenuItem * lmi = LAUNCHER_MENU_ITEM(data);
-
- g_return_if_fail(nick != NULL);
- g_return_if_fail(lmi != NULL);
-
- LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(lmi);
-
- g_return_if_fail(priv->ids != NULL);
-
- if (!indicator_desktop_shortcuts_nick_exec(priv->ids, nick)) {
- g_warning("Unable to execute nick '%s' for desktop file '%s'", nick, priv->desktop);
- }
-
- return;
-}
-
-/* Figure out the appropriate icon for this launcher */
-gchar *
-launcher_menu_item_get_icon (LauncherMenuItem * appitem)
-{
- LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(appitem);
- gchar * retval = NULL;
-
- /* Check to see if there is a specific icon for the messaging
- menu first. */
- if (g_key_file_has_key(priv->keyfile, G_KEY_FILE_DESKTOP_GROUP, ICON_KEY, NULL) && retval == NULL) {
- GError * error = NULL;
-
- retval = g_key_file_get_string(priv->keyfile, G_KEY_FILE_DESKTOP_GROUP, ICON_KEY, &error);
-
- if (error != NULL) {
- /* Can't figure out why this would happen, but sure, let's print something */
- g_warning("Error getting '" ICON_KEY "' from desktop file: %s", error->message);
- g_error_free(error);
- }
- }
-
- /* If there's not, or there is an error, we'll use the one
- from the application info */
- if (priv->appinfo != NULL && retval == NULL) {
- GIcon * icon = g_app_info_get_icon(priv->appinfo);
- retval = g_icon_to_string(icon);
- }
-
- return retval;
-}
-
-/* When the menu item is clicked on it tries to launch
- the application that is represented by the desktop file */
-static void
-activate_cb (LauncherMenuItem * self, guint timestamp, gpointer data)
-{
- LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(self);
- g_return_if_fail(priv->appinfo != NULL);
-
- GError * error = NULL;
- if (!g_app_info_launch(priv->appinfo, NULL, NULL, &error)) {
- g_warning("Application failed to launch '%s' because: %s", launcher_menu_item_get_name(self), error->message);
- g_error_free(error);
- }
-
- return;
-}
-
-const gchar *
-launcher_menu_item_get_desktop (LauncherMenuItem * launchitem)
-{
- g_return_val_if_fail(IS_LAUNCHER_MENU_ITEM(launchitem), NULL);
- LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(launchitem);
- return priv->desktop;
-}
-
-/* Gets the decription for the item that should
- go in the messaging menu */
-const gchar *
-launcher_menu_item_get_description (LauncherMenuItem * li)
-{
- g_return_val_if_fail(IS_LAUNCHER_MENU_ITEM(li), NULL);
- LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(li);
- return g_app_info_get_description(priv->appinfo);
-}
-
-/* Apply the eclipse value to all the shortcuts */
-static void
-eclipse_shortcuts_cb (gpointer data, gpointer user_data)
-{
- DbusmenuMenuitem * mi = DBUSMENU_MENUITEM(data);
- g_return_if_fail(mi != NULL);
-
- gboolean eclipsed = GPOINTER_TO_UINT(user_data);
-
- dbusmenu_menuitem_property_set_bool(mi, DBUSMENU_MENUITEM_PROP_VISIBLE, !eclipsed);
- return;
-}
-
-/* Hides the menu item based on whether it is eclipsed
- or not. */
-void
-launcher_menu_item_set_eclipsed (LauncherMenuItem * li, gboolean eclipsed)
-{
- g_return_if_fail(IS_LAUNCHER_MENU_ITEM(li));
- LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(li);
-
- g_debug("Laucher '%s' is %s", launcher_menu_item_get_name(li), eclipsed ? "now eclipsed" : "shown again");
- dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(li), DBUSMENU_MENUITEM_PROP_VISIBLE, !eclipsed);
-
- g_list_foreach(priv->shortcuts, eclipse_shortcuts_cb, GINT_TO_POINTER(eclipsed));
-
- /* If we're being reshown let's re-evaluate how we should be
- showing the label */
- if (!eclipsed) {
- const gchar * default_name = NULL;
-
- if (seen_db_seen(priv->desktop)) {
- default_name = get_default_name(priv->desktop);
- } else {
- default_name = get_default_setup(priv->desktop);
- }
-
- if (default_name == NULL) {
- dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(li), DBUSMENU_MENUITEM_PROP_LABEL, launcher_menu_item_get_name(li));
- } else {
- dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(li), DBUSMENU_MENUITEM_PROP_LABEL, _(default_name));
- }
- }
-
- return;
-}
-
-/* Check to see if this item is eclipsed */
-gboolean
-launcher_menu_item_get_eclipsed (LauncherMenuItem * li)
-{
- gboolean show = dbusmenu_menuitem_property_get_bool(DBUSMENU_MENUITEM(li), DBUSMENU_MENUITEM_PROP_VISIBLE);
- g_debug("Launcher check eclipse: %s", show ? "false" : "true");
- return !show;
-}
-
-/* Gets the shortcuts that are associated with this
- launcher. They're a list of DbusmenuMenuitems */
-GList *
-launcher_menu_item_get_items (LauncherMenuItem * li)
-{
- g_return_val_if_fail(IS_LAUNCHER_MENU_ITEM(li), NULL);
- LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(li);
- return priv->shortcuts;
-}
=== removed file 'src/launcher-menu-item.h'
--- src/launcher-menu-item.h 2010-02-18 17:23:29 +0000
+++ src/launcher-menu-item.h 1970-01-01 00:00:00 +0000
@@ -1,68 +0,0 @@
-/*
-An indicator to show information that is in messaging applications
-that the user is using.
-
-Copyright 2009 Canonical Ltd.
-
-Authors:
- Ted Gould <ted@xxxxxxxxxxxxx>
-
-This program is free software: you can redistribute it and/or modify it
-under the terms of the GNU General Public License version 3, as published
-by the Free Software Foundation.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranties of
-MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
-PURPOSE. See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along
-with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef __LAUNCHER_MENU_ITEM_H__
-#define __LAUNCHER_MENU_ITEM_H__
-
-#include <glib.h>
-#include <glib-object.h>
-
-#include <libdbusmenu-glib/menuitem.h>
-
-G_BEGIN_DECLS
-
-#define LAUNCHER_MENU_ITEM_TYPE (launcher_menu_item_get_type ())
-#define LAUNCHER_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), LAUNCHER_MENU_ITEM_TYPE, LauncherMenuItem))
-#define LAUNCHER_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), LAUNCHER_MENU_ITEM_TYPE, LauncherMenuItemClass))
-#define IS_LAUNCHER_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LAUNCHER_MENU_ITEM_TYPE))
-#define IS_LAUNCHER_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), LAUNCHER_MENU_ITEM_TYPE))
-#define LAUNCHER_MENU_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), LAUNCHER_MENU_ITEM_TYPE, LauncherMenuItemClass))
-
-#define LAUNCHER_MENU_ITEM_SIGNAL_NAME_CHANGED "name-changed"
-
-typedef struct _LauncherMenuItem LauncherMenuItem;
-typedef struct _LauncherMenuItemClass LauncherMenuItemClass;
-
-struct _LauncherMenuItemClass {
- DbusmenuMenuitemClass parent_class;
-
- void (* name_changed) (gchar * name);
-};
-
-struct _LauncherMenuItem {
- DbusmenuMenuitem parent;
-};
-
-GType launcher_menu_item_get_type (void);
-LauncherMenuItem * launcher_menu_item_new (const gchar * desktop_file);
-const gchar * launcher_menu_item_get_name (LauncherMenuItem * appitem);
-const gchar * launcher_menu_item_get_desktop (LauncherMenuItem * launchitem);
-const gchar * launcher_menu_item_get_description (LauncherMenuItem * li);
-gchar * launcher_menu_item_get_icon (LauncherMenuItem * appitem);
-void launcher_menu_item_set_eclipsed (LauncherMenuItem * li, gboolean eclipsed);
-gboolean launcher_menu_item_get_eclipsed (LauncherMenuItem * li);
-GList * launcher_menu_item_get_items (LauncherMenuItem * li);
-
-G_END_DECLS
-
-#endif /* __LAUNCHER_MENU_ITEM_H__ */
-
=== removed file 'src/messages-service-dbus.c'
--- src/messages-service-dbus.c 2011-07-21 21:25:58 +0000
+++ src/messages-service-dbus.c 1970-01-01 00:00:00 +0000
@@ -1,267 +0,0 @@
-/*
-An indicator to show information that is in messaging applications
-that the user is using.
-
-Copyright 2009 Canonical Ltd.
-
-Authors:
- Ted Gould <ted@xxxxxxxxxxxxx>
-
-This program is free software: you can redistribute it and/or modify it
-under the terms of the GNU General Public License version 3, as published
-by the Free Software Foundation.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranties of
-MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
-PURPOSE. See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along
-with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <gio/gio.h>
-#include "messages-service-dbus.h"
-#include "dbus-data.h"
-#include "gen-messages-service.xml.h"
-
-enum {
- ATTENTION_CHANGED,
- ICON_CHANGED,
- LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL] = { 0 };
-
-typedef struct _MessageServiceDbusPrivate MessageServiceDbusPrivate;
-
-struct _MessageServiceDbusPrivate
-{
- GDBusConnection * connection;
- gboolean dot;
- gboolean hidden;
-};
-
-#define MESSAGE_SERVICE_DBUS_GET_PRIVATE(o) \
-(G_TYPE_INSTANCE_GET_PRIVATE ((o), MESSAGE_SERVICE_DBUS_TYPE, MessageServiceDbusPrivate))
-
-static void message_service_dbus_class_init (MessageServiceDbusClass *klass);
-static void message_service_dbus_init (MessageServiceDbus *self);
-static void message_service_dbus_dispose (GObject *object);
-static void message_service_dbus_finalize (GObject *object);
-static void bus_method_call (GDBusConnection * connection,
- const gchar * sender,
- const gchar * path,
- const gchar * interface,
- const gchar * method,
- GVariant * params,
- GDBusMethodInvocation * invocation,
- gpointer user_data);
-
-static GDBusNodeInfo * bus_node_info = NULL;
-static GDBusInterfaceInfo * bus_interface_info = NULL;
-static const GDBusInterfaceVTable bus_interface_table = {
- method_call: bus_method_call,
- get_property: NULL, /* No properties */
- set_property: NULL /* No properties */
-};
-
-G_DEFINE_TYPE (MessageServiceDbus, message_service_dbus, G_TYPE_OBJECT);
-
-
-static void
-message_service_dbus_class_init (MessageServiceDbusClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- g_type_class_add_private (klass, sizeof (MessageServiceDbusPrivate));
-
- object_class->dispose = message_service_dbus_dispose;
- object_class->finalize = message_service_dbus_finalize;
-
- signals[ATTENTION_CHANGED] = g_signal_new(MESSAGE_SERVICE_DBUS_SIGNAL_ATTENTION_CHANGED,
- G_TYPE_FROM_CLASS(klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MessageServiceDbusClass, attention_changed),
- NULL, NULL,
- g_cclosure_marshal_VOID__BOOLEAN,
- G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
-
- signals[ICON_CHANGED] = g_signal_new(MESSAGE_SERVICE_DBUS_SIGNAL_ICON_CHANGED,
- G_TYPE_FROM_CLASS(klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (MessageServiceDbusClass, icon_changed),
- NULL, NULL,
- g_cclosure_marshal_VOID__BOOLEAN,
- G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
-
- if (bus_node_info == NULL) {
- GError * error = NULL;
-
- bus_node_info = g_dbus_node_info_new_for_xml(_messages_service, &error);
- if (error != NULL) {
- g_error("Unable to parse Messaging Menu Interface description: %s", error->message);
- g_error_free(error);
- }
- }
-
- if (bus_interface_info == NULL) {
- bus_interface_info = g_dbus_node_info_lookup_interface(bus_node_info, INDICATOR_MESSAGES_DBUS_SERVICE_INTERFACE);
-
- if (bus_interface_info == NULL) {
- g_error("Unable to find interface '" INDICATOR_MESSAGES_DBUS_SERVICE_INTERFACE "'");
- }
- }
-
- return;
-}
-
-static void
-connection_cb (GObject * object, GAsyncResult * res, gpointer user_data)
-{
- GError * error = NULL;
- GDBusConnection * connection = g_bus_get_finish(res, &error);
-
- if (error != NULL) {
- g_error("Unable to connect to the session bus: %s", error->message);
- g_error_free(error);
- return;
- }
-
- MessageServiceDbusPrivate * priv = MESSAGE_SERVICE_DBUS_GET_PRIVATE(user_data);
- priv->connection = connection;
-
- g_dbus_connection_register_object(connection,
- INDICATOR_MESSAGES_DBUS_SERVICE_OBJECT,
- bus_interface_info,
- &bus_interface_table,
- user_data,
- NULL, /* destroy */
- &error);
-
- if (error != NULL) {
- g_error("Unable to register on session bus: %s", error->message);
- g_error_free(error);
- return;
- }
-
- g_debug("Service on session bus");
-
- return;
-}
-
-static void
-message_service_dbus_init (MessageServiceDbus *self)
-{
- g_bus_get(G_BUS_TYPE_SESSION, NULL, connection_cb, self);
-
- MessageServiceDbusPrivate * priv = MESSAGE_SERVICE_DBUS_GET_PRIVATE(self);
-
- priv->dot = FALSE;
- priv->hidden = FALSE;
-
- return;
-}
-
-static void
-message_service_dbus_dispose (GObject *object)
-{
- MessageServiceDbusPrivate * priv = MESSAGE_SERVICE_DBUS_GET_PRIVATE(object);
-
- if (priv->connection != NULL) {
- g_object_unref(priv->connection);
- priv->connection = NULL;
- }
-
- G_OBJECT_CLASS (message_service_dbus_parent_class)->dispose (object);
- return;
-}
-
-static void
-message_service_dbus_finalize (GObject *object)
-{
-
-
- G_OBJECT_CLASS (message_service_dbus_parent_class)->finalize (object);
- return;
-}
-
-MessageServiceDbus *
-message_service_dbus_new (void)
-{
- return MESSAGE_SERVICE_DBUS(g_object_new(MESSAGE_SERVICE_DBUS_TYPE, NULL));
-}
-
-/* Method request off of DBus */
-static void
-bus_method_call (GDBusConnection * connection, const gchar * sender, const gchar * path, const gchar * interface, const gchar * method, GVariant * params, GDBusMethodInvocation * invocation, gpointer user_data)
-{
- MessageServiceDbus * ms = MESSAGE_SERVICE_DBUS(user_data);
- if (ms == NULL) { return; }
-
- MessageServiceDbusPrivate * priv = MESSAGE_SERVICE_DBUS_GET_PRIVATE(ms);
-
- if (g_strcmp0("AttentionRequested", method) == 0) {
- g_dbus_method_invocation_return_value(invocation, g_variant_new("(b)", priv->dot));
- return;
- } else if (g_strcmp0("IconShown", method) == 0) {
- g_dbus_method_invocation_return_value(invocation, g_variant_new("(b)", priv->hidden));
- return;
- } else if (g_strcmp0("ClearAttention", method) == 0) {
- message_service_dbus_set_attention(ms, FALSE);
- g_dbus_method_invocation_return_value(invocation, NULL);
- return;
- } else {
- g_warning("Unknown function call '%s'", method);
- }
-
- return;
-}
-
-void
-message_service_dbus_set_attention (MessageServiceDbus * self, gboolean attention)
-{
- MessageServiceDbusPrivate * priv = MESSAGE_SERVICE_DBUS_GET_PRIVATE(self);
- /* Do signal */
- if (attention != priv->dot) {
- priv->dot = attention;
- g_signal_emit(G_OBJECT(self), signals[ATTENTION_CHANGED], 0, priv->dot, TRUE);
-
- if (priv->connection != NULL) {
- g_dbus_connection_emit_signal(priv->connection,
- NULL,
- INDICATOR_MESSAGES_DBUS_SERVICE_OBJECT,
- INDICATOR_MESSAGES_DBUS_SERVICE_INTERFACE,
- "AttentionChanged",
- g_variant_new("(b)", priv->dot),
- NULL);
- }
- }
- return;
-}
-
-void
-message_service_dbus_set_icon (MessageServiceDbus * self, gboolean hidden)
-{
- MessageServiceDbusPrivate * priv = MESSAGE_SERVICE_DBUS_GET_PRIVATE(self);
- /* Do signal */
- if (hidden != priv->hidden) {
- priv->hidden = hidden;
- g_signal_emit(G_OBJECT(self), signals[ICON_CHANGED], 0, priv->hidden, TRUE);
-
- if (priv->connection != NULL) {
- g_dbus_connection_emit_signal(priv->connection,
- NULL,
- INDICATOR_MESSAGES_DBUS_SERVICE_OBJECT,
- INDICATOR_MESSAGES_DBUS_SERVICE_INTERFACE,
- "IconChanged",
- g_variant_new("(b)", priv->hidden),
- NULL);
- }
- }
- return;
-}
=== removed file 'src/messages-service-dbus.h'
--- src/messages-service-dbus.h 2009-08-26 15:35:56 +0000
+++ src/messages-service-dbus.h 1970-01-01 00:00:00 +0000
@@ -1,62 +0,0 @@
-/*
-An indicator to show information that is in messaging applications
-that the user is using.
-
-Copyright 2009 Canonical Ltd.
-
-Authors:
- Ted Gould <ted@xxxxxxxxxxxxx>
-
-This program is free software: you can redistribute it and/or modify it
-under the terms of the GNU General Public License version 3, as published
-by the Free Software Foundation.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranties of
-MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
-PURPOSE. See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along
-with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef __MESSAGE_SERVICE_DBUS_H__
-#define __MESSAGE_SERVICE_DBUS_H__
-
-#include <glib.h>
-#include <glib-object.h>
-
-G_BEGIN_DECLS
-
-#define MESSAGE_SERVICE_DBUS_TYPE (message_service_dbus_get_type ())
-#define MESSAGE_SERVICE_DBUS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MESSAGE_SERVICE_DBUS_TYPE, MessageServiceDbus))
-#define MESSAGE_SERVICE_DBUS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MESSAGE_SERVICE_DBUS_TYPE, MessageServiceDbusClass))
-#define IS_MESSAGE_SERVICE_DBUS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MESSAGE_SERVICE_DBUS_TYPE))
-#define IS_MESSAGE_SERVICE_DBUS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MESSAGE_SERVICE_DBUS_TYPE))
-#define MESSAGE_SERVICE_DBUS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MESSAGE_SERVICE_DBUS_TYPE, MessageServiceDbusClass))
-
-#define MESSAGE_SERVICE_DBUS_SIGNAL_ATTENTION_CHANGED "attention-changed"
-#define MESSAGE_SERVICE_DBUS_SIGNAL_ICON_CHANGED "icon-changed"
-
-typedef struct _MessageServiceDbus MessageServiceDbus;
-typedef struct _MessageServiceDbusClass MessageServiceDbusClass;
-
-struct _MessageServiceDbusClass {
- GObjectClass parent_class;
-
- void (*attention_changed) (gboolean dot);
- void (*icon_changed) (gboolean hidden);
-};
-
-struct _MessageServiceDbus {
- GObject parent;
-};
-
-GType message_service_dbus_get_type (void);
-MessageServiceDbus * message_service_dbus_new (void);
-void message_service_dbus_set_attention (MessageServiceDbus * self, gboolean attention);
-void message_service_dbus_set_icon (MessageServiceDbus * self, gboolean hidden);
-
-G_END_DECLS
-
-#endif
=== modified file 'src/messages-service.c'
--- src/messages-service.c 2011-08-25 01:26:02 +0000
+++ src/messages-service.c 2013-06-07 21:39:23 +0000
@@ -2,10 +2,11 @@
An indicator to show information that is in messaging applications
that the user is using.
-Copyright 2009 Canonical Ltd.
+Copyright 2012 Canonical Ltd.
Authors:
Ted Gould <ted@xxxxxxxxxxxxx>
+ Lars Uebernickel <lars.uebernickel@xxxxxxxxxxxxx>
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
@@ -20,1370 +21,360 @@
with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <string.h>
+#include <config.h>
#include <locale.h>
-#include <libintl.h>
-#include <config.h>
-#include <pango/pango-utils.h>
-#include <libindicate/listener.h>
#include <libindicator/indicator-service.h>
#include <gio/gio.h>
+#include <gio/gdesktopappinfo.h>
#include <glib/gi18n.h>
-#include <libdbusmenu-glib/client.h>
-#include <libdbusmenu-glib/server.h>
-
-#include "im-menu-item.h"
-#include "app-menu-item.h"
-#include "launcher-menu-item.h"
+#include "app-section.h"
#include "dbus-data.h"
-#include "dirs.h"
-#include "messages-service-dbus.h"
-#include "seen-db.h"
-#include "status-items.h"
-
-static IndicatorService * service = NULL;
-static IndicateListener * listener = NULL;
-static GList * serverList = NULL;
-static GList * launcherList = NULL;
-
-static DbusmenuMenuitem * root_menuitem = NULL;
-static DbusmenuMenuitem * status_separator = NULL;
-static DbusmenuMenuitem * clear_attention = NULL;
-static GMainLoop * mainloop = NULL;
-
-static MessageServiceDbus * dbus_interface = NULL;
-
-#define DESKTOP_FILE_GROUP "Messaging Menu"
-#define DESKTOP_FILE_KEY_DESKTOP "DesktopFile"
-
-static void server_shortcut_added (AppMenuItem * appitem, DbusmenuMenuitem * mi, gpointer data);
-static void server_shortcut_removed (AppMenuItem * appitem, DbusmenuMenuitem * mi, gpointer data);
-static void server_count_changed (AppMenuItem * appitem, guint count, gpointer data);
-static void server_name_changed (AppMenuItem * appitem, gchar * name, gpointer data);
-static void im_time_changed (ImMenuItem * imitem, glong seconds, gpointer data);
-static void resort_menu (DbusmenuMenuitem * menushell);
-static void indicator_removed (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gpointer data);
-static void check_eclipses (AppMenuItem * ai);
-static void remove_eclipses (AppMenuItem * ai);
-static gboolean build_launcher (gpointer data);
-static gboolean build_launcher_keyfile (gpointer data);
-static void build_launcher_core (const gchar * desktop);
-static gboolean build_launchers (gpointer data);
-static gboolean blacklist_init (gpointer data);
-static gboolean blacklist_add (gpointer data);
-static gchar * desktop_file_from_keyfile (const gchar * definition_file);
-static gboolean blacklist_keyfile_add (gpointer udata);
-static void blacklist_add_core (gchar * desktop, gchar * definition);
-static gboolean blacklist_remove (gpointer data);
-static void blacklist_dir_changed (GFileMonitor * monitor, GFile * file, GFile * other_file, GFileMonitorEvent event_type, gpointer user_data);
-static void app_dir_changed (GFileMonitor * monitor, GFile * file, GFile * other_file, GFileMonitorEvent event_type, gpointer user_data);
-static gboolean destroy_launcher (gpointer data);
-static void check_hidden (void);
-
-
-/*
- * Server List
- */
-
-typedef struct _serverList_t serverList_t;
-struct _serverList_t {
- IndicateListenerServer * server;
- AppMenuItem * menuitem;
- DbusmenuMenuitem * separator;
- gboolean attention;
- guint count;
- GList * imList;
-};
-
-static gint
-serverList_equal (gconstpointer a, gconstpointer b)
-{
- serverList_t * pa, * pb;
-
- pa = (serverList_t *)a;
- pb = (serverList_t *)b;
-
- const gchar * pas = INDICATE_LISTENER_SERVER_DBUS_NAME(pa->server);
- const gchar * pbs = INDICATE_LISTENER_SERVER_DBUS_NAME(pb->server);
-
- return g_strcmp0(pas, pbs);
-}
-
-static gint
-serverList_sort (gconstpointer a, gconstpointer b)
-{
- serverList_t * pa, * pb;
-
- pa = (serverList_t *)a;
- pb = (serverList_t *)b;
-
- const gchar * pan = app_menu_item_get_name(pa->menuitem);
- const gchar * pbn = app_menu_item_get_name(pb->menuitem);
-
- return g_strcmp0(pan, pbn);
-}
-
-/*
- * Item List
- */
-
-typedef struct _imList_t imList_t;
-struct _imList_t {
- IndicateListenerServer * server;
- IndicateListenerIndicator * indicator;
- DbusmenuMenuitem * menuitem;
- gulong timechange_cb;
- gulong attentionchange_cb;
-};
-
-static gboolean
-imList_equal (gconstpointer a, gconstpointer b)
-{
- imList_t * pa, * pb;
-
- pa = (imList_t *)a;
- pb = (imList_t *)b;
-
- const gchar * pas = INDICATE_LISTENER_SERVER_DBUS_NAME(pa->server);
- const gchar * pbs = INDICATE_LISTENER_SERVER_DBUS_NAME(pb->server);
-
- guint pai = INDICATE_LISTENER_INDICATOR_ID(pa->indicator);
- guint pbi = INDICATE_LISTENER_INDICATOR_ID(pb->indicator);
-
- g_debug("\tComparing (%s %d) to (%s %d)", pas, pai, pbs, pbi);
-
- return !((!g_strcmp0(pas, pbs)) && (pai == pbi));
-}
-
-static gint
-imList_sort (gconstpointer a, gconstpointer b)
-{
- imList_t * pa, * pb;
-
- pa = (imList_t *)a;
- pb = (imList_t *)b;
-
- return (gint)(im_menu_item_get_seconds(IM_MENU_ITEM(pb->menuitem)) - im_menu_item_get_seconds(IM_MENU_ITEM(pa->menuitem)));
-}
-
-/*
- * Launcher List
- */
-
-typedef struct _launcherList_t launcherList_t;
-struct _launcherList_t {
- LauncherMenuItem * menuitem;
- DbusmenuMenuitem * separator;
- GList * appdiritems;
-};
-
-static gint
-launcherList_sort (gconstpointer a, gconstpointer b)
-{
- launcherList_t * pa, * pb;
-
- pa = (launcherList_t *)a;
- pb = (launcherList_t *)b;
-
- const gchar * pan = launcher_menu_item_get_name(pa->menuitem);
- const gchar * pbn = launcher_menu_item_get_name(pb->menuitem);
-
- return g_strcmp0(pan, pbn);
-}
-
-static void
-launcherList_count_helper (gpointer data, gpointer user_data)
-{
- guint * count = (guint *)user_data;
- launcherList_t * li = (launcherList_t *)data;
-
- if (!launcher_menu_item_get_eclipsed(li->menuitem)) {
- *count = *count + 1;
- }
-
- return;
-}
-
-static guint
-launcherList_count (void)
-{
- guint count = 0;
-
- g_list_foreach(launcherList, launcherList_count_helper, &count);
-
- return count;
-}
-
-/*
- * Black List
- */
-
-static GHashTable * blacklist = NULL;
-static GFileMonitor * blacklistdirmon = NULL;
-
-/* Initialize the black list and start to setup
- handlers for it. */
-static gboolean
-blacklist_init (gpointer data)
-{
- blacklist = g_hash_table_new_full(g_str_hash, g_str_equal,
- g_free, g_free);
-
- gchar * blacklistdir = g_build_filename(g_get_user_config_dir(), USER_BLACKLIST_DIR, NULL);
- g_debug("Looking at blacklist: %s", blacklistdir);
- if (!g_file_test(blacklistdir, G_FILE_TEST_IS_DIR)) {
- g_free(blacklistdir);
- return FALSE;
- }
-
- GFile * filedir = g_file_new_for_path(blacklistdir);
- blacklistdirmon = g_file_monitor_directory(filedir, G_FILE_MONITOR_NONE, NULL, NULL);
- if (blacklistdirmon != NULL) {
- g_signal_connect(G_OBJECT(blacklistdirmon), "changed", G_CALLBACK(blacklist_dir_changed), NULL);
- }
-
- GError * error = NULL;
- GDir * dir = g_dir_open(blacklistdir, 0, &error);
- if (dir == NULL) {
- g_warning("Unable to open blacklist directory (%s): %s", blacklistdir, error == NULL ? "No Message" : error->message);
- g_error_free(error);
- g_free(blacklistdir);
- return FALSE;
- }
-
- const gchar * filename = NULL;
- while ((filename = g_dir_read_name(dir)) != NULL) {
- g_debug("Found file: %s", filename);
- gchar * path = g_build_filename(blacklistdir, filename, NULL);
- if (g_str_has_suffix(path, "keyfile")) {
- g_idle_add(blacklist_keyfile_add, path);
- } else {
- g_idle_add(blacklist_add, path);
- }
- }
-
- g_dir_close(dir);
- g_free(blacklistdir);
-
- return FALSE;
-}
-
-/* Parses through a keyfile to find the desktop file entry and
- pushes them into the blacklist. */
-static gboolean
-blacklist_keyfile_add (gpointer udata)
-{
- gchar * definition_file = (gchar *)udata;
- gchar * desktopfile = desktop_file_from_keyfile(definition_file);
- if (desktopfile != NULL) {
- blacklist_add_core(desktopfile, definition_file);
- g_free(desktopfile);
- }
- return FALSE;
-}
-
-/* Takes a keyfile and finds the desktop file in it for
- us. With some error handling. */
-static gchar *
-desktop_file_from_keyfile (const gchar * definition_file)
-{
- GKeyFile * keyfile = g_key_file_new();
- GError * error = NULL;
-
- if (!g_key_file_load_from_file(keyfile, definition_file, G_KEY_FILE_NONE, &error)) {
- g_warning("Unable to load keyfile '%s' because: %s", definition_file, error == NULL ? "unknown" : error->message);
- g_error_free(error);
- g_key_file_free(keyfile);
- return NULL;
- }
-
- if (!g_key_file_has_group(keyfile, DESKTOP_FILE_GROUP)) {
- g_warning("Unable to use keyfile '%s' as it has no '" DESKTOP_FILE_GROUP "' group.", definition_file);
- g_key_file_free(keyfile);
- return NULL;
- }
-
- if (!g_key_file_has_key(keyfile, DESKTOP_FILE_GROUP, DESKTOP_FILE_KEY_DESKTOP, &error)) {
- g_warning("Unable to use keyfile '%s' as there is no key '" DESKTOP_FILE_KEY_DESKTOP "' in the group '" DESKTOP_FILE_GROUP "' because: %s", definition_file, error == NULL ? "unknown" : error->message);
- g_error_free(error);
- g_key_file_free(keyfile);
- return NULL;
- }
-
- gchar * desktopfile = g_key_file_get_string(keyfile, DESKTOP_FILE_GROUP, DESKTOP_FILE_KEY_DESKTOP, &error);
- g_key_file_free(keyfile);
- return desktopfile;
-}
-
-/* Add a definition file into the black list and eclipse
- any launchers that have the same file. */
-static gboolean
-blacklist_add (gpointer udata)
-{
- gchar * definition_file = (gchar *)udata;
- /* Dump the file */
- gchar * desktop;
- g_file_get_contents(definition_file, &desktop, NULL, NULL);
- if (desktop == NULL) {
- g_warning("Couldn't get data out of: %s", definition_file);
- return FALSE;
- }
-
- /* Clean up the data */
- gchar * trimdesktop = pango_trim_string(desktop);
- g_free(desktop);
-
- blacklist_add_core(trimdesktop, definition_file);
- g_free(trimdesktop);
-
- return FALSE;
-}
-
-/* This takes a desktop file and tries to add it to the black
- list for applications in the messaging menu. If it can,
- then the launcher item gets marked as eclipsed and hidden
- from the user. */
-static void
-blacklist_add_core (gchar * desktop, gchar * definition)
-{
- /* Check for conflicts */
- gpointer data = g_hash_table_lookup(blacklist, desktop);
- if (data != NULL) {
- gchar * oldfile = (gchar *)data;
- if (!g_strcmp0(oldfile, definition)) {
- g_warning("Already added file '%s'", oldfile);
- } else {
- g_warning("Already have desktop file '%s' in blacklist file '%s' not adding from '%s'", desktop, oldfile, definition);
- }
-
- return;
- }
-
- /* Actually blacklist this thing */
- g_hash_table_insert(blacklist, g_strdup(desktop), g_strdup(definition));
- g_debug("Adding Blacklist item '%s' for desktop '%s'", definition, desktop);
-
- /* Go through and eclipse folks */
- GList * launcher;
- for (launcher = launcherList; launcher != NULL; launcher = launcher->next) {
- launcherList_t * item = (launcherList_t *)launcher->data;
- if (!g_strcmp0(desktop, launcher_menu_item_get_desktop(item->menuitem))) {
- launcher_menu_item_set_eclipsed(item->menuitem, TRUE);
- dbusmenu_menuitem_property_set_bool(item->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
- }
- }
-
- check_hidden();
- /* Shouldn't need a resort here as hiding shouldn't cause things to
- move other than this item disappearing. */
-
- return;
-}
-
-/* Remove a black list item based on the definition file
- and uneclipse those launchers blocked by it. */
-static gboolean
-blacklist_remove (gpointer data)
-{
- gchar * definition_file = (gchar *)data;
- g_debug("Removing: %s", definition_file);
-
+#include "gactionmuxer.h"
+#include "gsettingsstrv.h"
+#include "gmenuutils.h"
+#include "indicator-messages-service.h"
+
+#define NUM_STATUSES 5
+
+static GHashTable *applications;
+
+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)
+{
+ const gchar *id;
+
+ id = g_app_info_get_id (appinfo);
+ if (!id)
+ return NULL;
+
+ if (g_str_has_suffix (id, ".desktop"))
+ return g_strndup (id, strlen (id) - 8);
+ else
+ return g_strdup (id);
+}
+
+static void
+actions_changed (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ AppSection *section = APP_SECTION (object);
+ gchar *id;
+ GActionGroup *actions;
+
+ id = g_app_info_get_simple_id (app_section_get_app_info (section));
+ actions = app_section_get_actions (section);
+
+ g_action_muxer_insert (action_muxer, id, actions);
+ g_free (id);
+}
+
+
+static gboolean
+app_section_draws_attention (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ AppSection *section = value;
+ return app_section_get_draws_attention (section);
+}
+
+static void
+draws_attention_changed (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ GSimpleAction *clear;
+
+ clear = G_SIMPLE_ACTION (g_simple_action_group_lookup (actions, "clear"));
+ g_return_if_fail (clear != NULL);
+
+ draws_attention = g_hash_table_find (applications, app_section_draws_attention, NULL) != NULL;
+
+ g_simple_action_set_enabled (clear, draws_attention);
+
+ indicator_messages_update_icon ();
+}
+
+static gboolean
+app_section_uses_chat (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ AppSection *section = value;
+ return app_section_get_uses_chat_status (section);
+}
+
+static void
+update_chat_section ()
+{
+ gboolean show_chat;
+ GMenuModel *first_section;
+
+ show_chat = g_hash_table_find (applications, app_section_uses_chat, NULL) != NULL;
+
+ first_section = g_menu_model_get_item_link (G_MENU_MODEL (menu), 0, G_MENU_LINK_SECTION);
+ if (first_section == chat_section) {
+ if (!show_chat)
+ g_menu_remove (menu, 0);
+ }
+ else {
+ if (show_chat)
+ g_menu_insert_section (menu, 0, NULL, chat_section);
+ }
+
+ 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;
- gpointer key, value;
- gboolean found = FALSE;
-
- g_hash_table_iter_init(&iter, blacklist);
- while (g_hash_table_iter_next(&iter, &key, &value)) {
- if (!g_strcmp0((gchar *)value, definition_file)) {
- found = TRUE;
- break;
- }
- }
-
- if (!found) {
- g_debug("\tNot found!");
- return FALSE;
- }
-
- GList * launcheritem;
- for (launcheritem = launcherList; launcheritem != NULL; launcheritem = launcheritem->next) {
- launcherList_t * li = (launcherList_t *)launcheritem->data;
- if (!g_strcmp0(launcher_menu_item_get_desktop(li->menuitem), (gchar *)key)) {
- GList * serveritem;
- for (serveritem = serverList; serveritem != NULL; serveritem = serveritem->next) {
- serverList_t * si = (serverList_t *)serveritem->data;
- if (!g_strcmp0(app_menu_item_get_desktop(si->menuitem), (gchar *)key)) {
- break;
- }
- }
- if (serveritem == NULL) {
- launcher_menu_item_set_eclipsed(li->menuitem, FALSE);
- dbusmenu_menuitem_property_set_bool(li->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
- }
- }
- }
-
- if (!g_hash_table_remove(blacklist, key)) {
- g_warning("Unable to remove '%s' with value '%s'", definition_file, (gchar *)key);
- }
-
- check_hidden();
- resort_menu(root_menuitem);
-
- return FALSE;
-}
-
-/* Check to see if a particular desktop file is
- in the blacklist. */
-static gboolean
-blacklist_check (const gchar * desktop_file)
-{
- g_debug("Checking blacklist for: %s", desktop_file);
- if (blacklist == NULL) return FALSE;
-
- if (g_hash_table_lookup(blacklist, desktop_file)) {
- g_debug("\tFound!");
- return TRUE;
- }
-
- return FALSE;
-}
-
-/* A callback everytime the blacklist directory changes
- in some way. It needs to handle that. */
-static void
-blacklist_dir_changed (GFileMonitor * monitor, GFile * file, GFile * other_file, GFileMonitorEvent event_type, gpointer user_data)
-{
- g_debug("Blacklist directory changed!");
-
- switch (event_type) {
- case G_FILE_MONITOR_EVENT_DELETED: {
- gchar * path = g_file_get_path(file);
- g_debug("\tDelete: %s", path);
- g_idle_add(blacklist_remove, path);
- break;
- }
- case G_FILE_MONITOR_EVENT_CREATED: {
- gchar * path = g_file_get_path(file);
- g_debug("\tCreate: %s", path);
- g_idle_add(blacklist_add, path);
- break;
- }
- default:
- break;
- }
-
- return;
-}
-
-/*
- * More code
- */
-
-/* Goes through all the servers and sees if any of them
- want attention. If they do, then well we'll give it
- to them. If they don't, let's not bother the user
- any, shall we? */
-static void
-check_attention (void)
-{
- GList * pointer;
- for (pointer = serverList; pointer != NULL; pointer = g_list_next(pointer)) {
- serverList_t * slt = (serverList_t *)pointer->data;
- if (slt->attention) {
- message_service_dbus_set_attention(dbus_interface, TRUE);
- return;
- }
- }
- message_service_dbus_set_attention(dbus_interface, FALSE);
- return;
-}
-
-/* This checks a server listing to see if it should
- have attention. It can get attention through it's
- count or by having an indicator that is requestion
- attention. */
-static void
-server_attention (serverList_t * slt)
-{
- /* Count, easy yes and out. */
- if (slt->count > 0) {
- slt->attention = TRUE;
- return;
- }
-
- /* Check to see if any of the indicators want attention */
- GList * pointer;
- for (pointer = slt->imList; pointer != NULL; pointer = g_list_next(pointer)) {
- imList_t * ilt = (imList_t *)pointer->data;
- if (im_menu_item_get_attention(IM_MENU_ITEM(ilt->menuitem))) {
- slt->attention = TRUE;
- return;
- }
- }
-
- /* Nope, no one */
- slt->attention = FALSE;
- return;
-}
-
-/* A new server has been created on the indicate bus.
- We need to check to see if we like it. And build
- structures for it if so. */
-static void
-server_added (IndicateListener * listener, IndicateListenerServer * server, gchar * type, gpointer data)
-{
- g_debug("Server Added '%s' of type '%s'.", INDICATE_LISTENER_SERVER_DBUS_NAME(server), type);
- if (type == NULL) {
- return;
- }
-
- if (type[0] == '\0') {
- return;
- }
-
- if (strncmp(type, "message", strlen("message"))) {
- g_debug("\tServer type '%s' is not a message based type.", type);
- return;
- }
-
- DbusmenuMenuitem * menushell = DBUSMENU_MENUITEM(data);
- if (menushell == NULL) {
- g_error("\tData in callback is not a menushell");
- return;
- }
-
- /* Build the Menu item */
- AppMenuItem * menuitem = app_menu_item_new(listener, server);
-
- /* Build a possible server structure */
- serverList_t * sl_item = g_new0(serverList_t, 1);
- sl_item->server = server;
- sl_item->menuitem = menuitem;
- sl_item->imList = NULL;
- sl_item->attention = FALSE;
- sl_item->count = 0;
-
- /* Incase we got an indicator first */
- GList * alreadythere = g_list_find_custom(serverList, sl_item, serverList_equal);
- if (alreadythere != NULL) {
- /* Use the one we already had */
- g_free(sl_item);
- sl_item = (serverList_t *)alreadythere->data;
- sl_item->menuitem = menuitem;
- serverList = g_list_sort(serverList, serverList_sort);
- } else {
- /* Insert the new one in the list */
- serverList = g_list_insert_sorted(serverList, sl_item, serverList_sort);
- }
-
- /* Build a separator */
- sl_item->separator = dbusmenu_menuitem_new();
- dbusmenu_menuitem_property_set(sl_item->separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR);
-
- /* Connect the signals up to the menu item */
- g_signal_connect(G_OBJECT(menuitem), APP_MENU_ITEM_SIGNAL_COUNT_CHANGED, G_CALLBACK(server_count_changed), sl_item);
- g_signal_connect(G_OBJECT(menuitem), APP_MENU_ITEM_SIGNAL_NAME_CHANGED, G_CALLBACK(server_name_changed), menushell);
- g_signal_connect(G_OBJECT(menuitem), APP_MENU_ITEM_SIGNAL_SHORTCUT_ADDED, G_CALLBACK(server_shortcut_added), menushell);
- g_signal_connect(G_OBJECT(menuitem), APP_MENU_ITEM_SIGNAL_SHORTCUT_REMOVED, G_CALLBACK(server_shortcut_removed), menushell);
-
- /* Put our new menu item in, with the separator behind it.
- resort_menu will take care of whether it should be hidden
- or not. */
- dbusmenu_menuitem_child_append(menushell, DBUSMENU_MENUITEM(menuitem));
-
- GList * shortcuts = app_menu_item_get_items(sl_item->menuitem);
- while (shortcuts != NULL) {
- DbusmenuMenuitem * mi = DBUSMENU_MENUITEM(shortcuts->data);
- g_debug("\tAdding shortcut: %s", dbusmenu_menuitem_property_get(mi, DBUSMENU_MENUITEM_PROP_LABEL));
- dbusmenu_menuitem_child_append(menushell, mi);
- shortcuts = g_list_next(shortcuts);
- }
-
- dbusmenu_menuitem_child_append(menushell, DBUSMENU_MENUITEM(sl_item->separator));
-
- resort_menu(menushell);
- check_hidden();
-
- return;
-}
-
-/* Server shortcut has been added */
-static void
-server_shortcut_added (AppMenuItem * appitem, DbusmenuMenuitem * mi, gpointer data)
-{
- g_debug("Application Shortcut added: %s", mi != NULL ? dbusmenu_menuitem_property_get(mi, DBUSMENU_MENUITEM_PROP_LABEL) : "none");
- DbusmenuMenuitem * shell = DBUSMENU_MENUITEM(data);
- if (mi != NULL) {
- dbusmenu_menuitem_child_append(shell, mi);
- }
- resort_menu(shell);
- return;
-}
-
-/* Server shortcut has been removed */
-static void
-server_shortcut_removed (AppMenuItem * appitem, DbusmenuMenuitem * mi, gpointer data)
-{
- g_debug("Application Shortcut removed: %s", mi != NULL ? dbusmenu_menuitem_property_get(mi, DBUSMENU_MENUITEM_PROP_LABEL) : "none");
- DbusmenuMenuitem * shell = DBUSMENU_MENUITEM(data);
- dbusmenu_menuitem_child_delete(shell, mi);
- return;
-}
-
-/* The name of a server has changed, we probably
- need to reorder the menu to keep it in alphabetical
- order. This happens often after we read the destkop
- file from disk. */
-static void
-server_name_changed (AppMenuItem * appitem, gchar * name, gpointer data)
-{
- serverList = g_list_sort(serverList, serverList_sort);
- check_eclipses(appitem);
- resort_menu(DBUSMENU_MENUITEM(data));
- return;
-}
-
-/* If the count on the server changes, we need to know
- whether that should be grabbing attention or not. If
- it is, we need to reevaluate whether the whole thing
- should be grabbing attention or not. */
-static void
-server_count_changed (AppMenuItem * appitem, guint count, gpointer data)
-{
- serverList_t * slt = (serverList_t *)data;
- slt->count = count;
-
- if (count == 0 && slt->attention) {
- /* Regen based on indicators if the count isn't going to cause it. */
- server_attention(slt);
- /* If we're dropping let's see if we're the last. */
- if (!slt->attention) {
- check_attention();
- }
- }
-
- if (count != 0 && !slt->attention) {
- slt->attention = TRUE;
- /* Let's tell everyone about us! */
- message_service_dbus_set_attention(dbus_interface, TRUE);
- }
-
- return;
-}
-
-/* Respond to the IM entrie's time changing
- which results in it needing to resort the list
- and rebuild the menu to match. */
-static void
-im_time_changed (ImMenuItem * imitem, glong seconds, gpointer data)
-{
- serverList_t * sl = (serverList_t *)data;
- sl->imList = g_list_sort(sl->imList, imList_sort);
- resort_menu(root_menuitem);
- return;
-}
-
-/* The IM entrie's request for attention has changed
- so we need to pass that up the stack. */
-static void
-im_attention_changed (ImMenuItem * imitem, gboolean requestit, gpointer data)
-{
- serverList_t * sl = (serverList_t *)data;
-
- if (requestit) {
- sl->attention = TRUE;
- message_service_dbus_set_attention(dbus_interface, TRUE);
- } else {
- server_attention(sl);
- if (!sl->attention) {
- check_attention();
- }
- }
-
- return;
-}
-
-/* Run when a server is removed from the indicator bus. It figures
- out if we have it somewhere, and if so then we dump it out and
- clean up all of it's entries. */
-static void
-server_removed (IndicateListener * listener, IndicateListenerServer * server, gchar * type, gpointer data)
-{
- /* Look for the server */
- g_debug("Removing server: %s", INDICATE_LISTENER_SERVER_DBUS_NAME(server));
- serverList_t slt = {0};
- slt.server = server;
- GList * lookup = g_list_find_custom(serverList, &slt, serverList_equal);
-
- /* If we don't have it, exit */
- if (lookup == NULL) {
- g_debug("\tUnable to find server: %s", INDICATE_LISTENER_SERVER_DBUS_NAME(server));
- return;
- }
-
- serverList_t * sltp = (serverList_t *)lookup->data;
-
- /* Removing indicators from this server */
- while (sltp->imList) {
- imList_t * imitem = (imList_t *)sltp->imList->data;
- indicator_removed(listener, server, imitem->indicator, data);
- }
-
- /* Remove from the server list */
- serverList = g_list_remove(serverList, sltp);
-
- /* Remove launchers this could be eclipsing */
- remove_eclipses(sltp->menuitem);
-
- /* If there is a menu item, let's get rid of it. */
- if (sltp->menuitem != NULL) {
- /* If there are shortcuts remove them */
- GList * shortcuts = app_menu_item_get_items(sltp->menuitem);
- while (shortcuts != NULL) {
- g_debug("\tRemoving shortcut: %s", dbusmenu_menuitem_property_get(DBUSMENU_MENUITEM(shortcuts->data), DBUSMENU_MENUITEM_PROP_LABEL));
- dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(shortcuts->data), DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
- dbusmenu_menuitem_child_delete(DBUSMENU_MENUITEM(data), DBUSMENU_MENUITEM(shortcuts->data));
- shortcuts = g_list_next(shortcuts);
- }
-
- g_debug("\tRemoving item");
- dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(sltp->menuitem), DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
- dbusmenu_menuitem_child_delete(DBUSMENU_MENUITEM(data), DBUSMENU_MENUITEM(sltp->menuitem));
- g_object_unref(G_OBJECT(sltp->menuitem));
- } else {
- g_debug("\tNo menuitem");
- }
-
- /* If there is a separator, let's get rid of it. */
- if (sltp->separator != NULL) {
- g_debug("\tRemoving separator");
- dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(sltp->separator), DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
- dbusmenu_menuitem_child_delete(DBUSMENU_MENUITEM(data), DBUSMENU_MENUITEM(sltp->separator));
- g_object_unref(G_OBJECT(sltp->separator));
- } else {
- g_debug("\tNo separator");
- }
-
- if (sltp->attention) {
- /* Check to see if this was the server causing the menu item to
- be lit up. */
- check_attention();
- }
-
- g_free(sltp);
-
- check_hidden();
-
- return;
-}
-
-typedef struct _menushell_location menushell_location_t;
-struct _menushell_location {
- const IndicateListenerServer * server;
- gint position;
- gboolean found;
-};
-
-static void
-menushell_foreach_cb (DbusmenuMenuitem * data_mi, gpointer data_ms) {
- menushell_location_t * msl = (menushell_location_t *)data_ms;
-
- if (msl->found) return;
-
- if (!IS_APP_MENU_ITEM(data_mi)) {
- msl->position++;
- return;
- }
-
- AppMenuItem * appmenu = APP_MENU_ITEM(data_mi);
- if (!g_strcmp0(INDICATE_LISTENER_SERVER_DBUS_NAME((IndicateListenerServer*)msl->server), INDICATE_LISTENER_SERVER_DBUS_NAME(app_menu_item_get_server(appmenu)))) {
- msl->found = TRUE;
- /* Return a position at the end of our shortcuts */
- msl->position += g_list_length(app_menu_item_get_items(appmenu));
- } else {
- msl->position++;
- }
-
- return;
-}
-
-static void
-check_hidden (void)
-{
- g_debug("Checking Hidden...");
- gboolean hide = FALSE;
- if (launcherList_count() == 0) {
- g_debug("\tZero Launchers");
- /* If we don't have visible launchers we need to look more */
- if (g_list_length(serverList) == 0) {
- g_debug("\tZero Applications");
- hide = TRUE;
- }
- }
-
- message_service_dbus_set_icon(dbus_interface, hide);
- return;
-}
-
-/* This function takes care of putting the menu in the right order.
- It basically it rebuilds the order by looking through all the
- applications and launchers and puts them in the right place. The
- menu functions will handle the cases where they don't move so this
- is a good way to ensure everything is right. */
-static void
-resort_menu (DbusmenuMenuitem * menushell)
-{
- guint position = 0;
- GList * serverentry;
- GList * launcherentry = launcherList;
-
- g_debug("Reordering Menu:");
-
- if (DBUSMENU_IS_MENUITEM(status_separator)) {
- position = dbusmenu_menuitem_get_position(status_separator, root_menuitem) + 1;
- g_debug("\tPriming with location of status separator: %d", position);
- }
-
- for (serverentry = serverList; serverentry != NULL; serverentry = serverentry->next) {
- serverList_t * si = (serverList_t *)serverentry->data;
-
- /* Looking to see if there are any launchers we need to insert
- into the menu structure. We put as many as we need to. */
- if (launcherentry != NULL) {
- launcherList_t * li = (launcherList_t *)launcherentry->data;
- while (launcherentry != NULL && g_strcmp0(launcher_menu_item_get_name(li->menuitem), app_menu_item_get_name(si->menuitem)) < 0) {
- /* Putting the launcher item in */
- g_debug("\tMoving launcher '%s' to position %d", launcher_menu_item_get_name(li->menuitem), position);
- dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(li->menuitem), position);
- position++;
-
- /* Inserting the shortcuts from the launcher */
- GList * shortcuts = launcher_menu_item_get_items(li->menuitem);
- while (shortcuts != NULL) {
- g_debug("\t\tMoving shortcut to position %d", position);
- dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(shortcuts->data), position);
- position++;
- shortcuts = g_list_next(shortcuts);
- }
-
- /* Putting the launcher separator in */
- g_debug("\tMoving launcher separator to position %d", position);
- dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(li->separator), position);
- if (!launcher_menu_item_get_eclipsed(li->menuitem)) {
- /* Only clear the visiblity if we're not eclipsed */
- dbusmenu_menuitem_property_set_bool(li->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
- }
- position++;
-
- launcherentry = launcherentry->next;
- if (launcherentry != NULL) {
- li = (launcherList_t *)launcherentry->data;
- }
- }
- }
-
- /* Putting the app menu item in */
- if (si->menuitem != NULL) {
- g_debug("\tMoving app %s to position %d", INDICATE_LISTENER_SERVER_DBUS_NAME(si->server), position);
- dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(si->menuitem), position);
- position++;
-
- /* Inserting the shortcuts from the launcher */
- GList * shortcuts = app_menu_item_get_items(si->menuitem);
- while (shortcuts != NULL) {
- g_debug("\t\tMoving shortcut to position %d", position);
- dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(shortcuts->data), position);
- position++;
- shortcuts = g_list_next(shortcuts);
- }
- }
-
- /* Putting all the indicators that are related to this application
- after it. */
- GList * imentry;
- for (imentry = si->imList; imentry != NULL; imentry = imentry->next) {
- imList_t * imi = (imList_t *)imentry->data;
-
- if (imi->menuitem != NULL) {
- g_debug("\tMoving indicator on %s id %d to position %d", INDICATE_LISTENER_SERVER_DBUS_NAME(imi->server), INDICATE_LISTENER_INDICATOR_ID(imi->indicator), position);
-
- if (si->menuitem == NULL || !dbusmenu_menuitem_property_get_bool(DBUSMENU_MENUITEM(si->menuitem), DBUSMENU_MENUITEM_PROP_VISIBLE)) {
- dbusmenu_menuitem_property_set_bool(imi->menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
- } else {
- dbusmenu_menuitem_property_set_bool(imi->menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
- }
-
- dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(imi->menuitem), position);
- position++;
- }
- }
-
- /* Lastly putting the separator in */
- if (si->separator != NULL) {
- g_debug("\tMoving app %s separator to position %d", INDICATE_LISTENER_SERVER_DBUS_NAME(si->server), position);
-
- if (si->menuitem == NULL || !dbusmenu_menuitem_property_get_bool(DBUSMENU_MENUITEM(si->menuitem), DBUSMENU_MENUITEM_PROP_VISIBLE)) {
- dbusmenu_menuitem_property_set_bool(si->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
- /* Note, this isn't the last if we can't see it */
- } else {
- dbusmenu_menuitem_property_set_bool(si->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
- }
-
- dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(si->separator), position);
- position++;
- }
- }
-
- /* Put any leftover launchers in at the end of the list. */
- while (launcherentry != NULL) {
- launcherList_t * li = (launcherList_t *)launcherentry->data;
-
- /* Putting the launcher in */
- g_debug("\tMoving launcher '%s' to position %d", launcher_menu_item_get_name(li->menuitem), position);
- dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(li->menuitem), position);
- position++;
-
- /* Inserting the shortcuts from the launcher */
- GList * shortcuts = launcher_menu_item_get_items(li->menuitem);
- while (shortcuts != NULL) {
- g_debug("\t\tMoving shortcut to position %d", position);
- dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(shortcuts->data), position);
- position++;
- shortcuts = g_list_next(shortcuts);
- }
-
- /* Putting the launcher separator in */
- g_debug("\tMoving launcher separator to position %d", position);
- dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(li->separator), position);
- if (!launcher_menu_item_get_eclipsed(li->menuitem)) {
- /* Only clear the visiblity if we're not eclipsed */
- dbusmenu_menuitem_property_set_bool(li->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
- }
- position++;
-
- launcherentry = launcherentry->next;
- }
-
- if (clear_attention != NULL) {
- dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), clear_attention, position);
- position++; /* Not needed, but reduce bugs on code tacked on here, compiler will remove */
- }
-
- return;
-}
-
-/* Responding to a new indicator showing up on the bus. We
- need to create a menuitem for it and start populating the
- internal structures to track it. */
-static void
-indicator_added (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gpointer data)
-{
- DbusmenuMenuitem * menushell = DBUSMENU_MENUITEM(data);
- if (menushell == NULL) {
- g_error("Data in callback is not a menushell");
- return;
- }
-
- imList_t * listItem = g_new0(imList_t, 1);
- listItem->server = server;
- listItem->indicator = indicator;
-
- /* Building the IM Menu Item which is a subclass
- of DBus Menuitem */
- ImMenuItem * menuitem = im_menu_item_new(listener, server, indicator);
- listItem->menuitem = DBUSMENU_MENUITEM(menuitem);
-
- /* Looking for a server entry to attach this indicator
- to. If we can't find one then we have to build one
- and attach the indicator to it. */
- serverList_t sl_item_local = {0};
- serverList_t * sl_item = NULL;
- sl_item_local.server = server;
- GList * serverentry = g_list_find_custom(serverList, &sl_item_local, serverList_equal);
-
- if (serverentry == NULL) {
- /* This sucks, we got an indicator before the server. I guess
- that's the joy of being asynchronous */
- sl_item = g_new0(serverList_t, 1);
- sl_item->server = server;
- sl_item->menuitem = NULL;
- sl_item->imList = NULL;
- sl_item->attention = FALSE;
- sl_item->count = 0;
- sl_item->separator = NULL;
-
- serverList = g_list_insert_sorted(serverList, sl_item, serverList_sort);
- } else {
- sl_item = (serverList_t *)serverentry->data;
- }
-
- /* Added a this entry into the IM list */
- sl_item->imList = g_list_insert_sorted(sl_item->imList, listItem, imList_sort);
- listItem->timechange_cb = g_signal_connect(G_OBJECT(menuitem), IM_MENU_ITEM_SIGNAL_TIME_CHANGED, G_CALLBACK(im_time_changed), sl_item);
- listItem->attentionchange_cb = g_signal_connect(G_OBJECT(menuitem), IM_MENU_ITEM_SIGNAL_ATTENTION_CHANGED, G_CALLBACK(im_attention_changed), sl_item);
-
- /* Check the length of the list. If we've got more inidactors
- than we allow. Well. Someone's gotta pay. Sorry. I didn't
- want to do this, but you did it to yourself. */
- if (g_list_length(sl_item->imList) > MAX_NUMBER_OF_INDICATORS) {
- GList * indicatoritem;
- gint count;
- for (indicatoritem = sl_item->imList, count = 0; indicatoritem != NULL; indicatoritem = g_list_next(indicatoritem), count++) {
- imList_t * im = (imList_t *)indicatoritem->data;
- im_menu_item_show(IM_MENU_ITEM(im->menuitem), count < MAX_NUMBER_OF_INDICATORS);
- }
- }
-
- /* Placing the item into the shell. Look to see if
- we can find our server and slip in there. Otherwise
- we'll just append. */
- menushell_location_t msl;
- msl.found = FALSE;
- msl.position = 0;
- msl.server = server;
-
- dbusmenu_menuitem_foreach(DBUSMENU_MENUITEM(menushell), menushell_foreach_cb, &msl);
- if (msl.found) {
- dbusmenu_menuitem_child_add_position(menushell, DBUSMENU_MENUITEM(menuitem), msl.position);
- } else {
- g_warning("Unable to find server menu item");
- dbusmenu_menuitem_child_append(menushell, DBUSMENU_MENUITEM(menuitem));
- }
-
- return;
-}
-
-/* Process and indicator getting removed from the system. We
- first need to ensure that it's one of ours and figure out
- where we put it. When we find all that out we can go through
- the process of removing the effect it had on the system. */
-static void
-indicator_removed (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gpointer data)
-{
- g_debug("Removing %s %d", INDICATE_LISTENER_SERVER_DBUS_NAME(server), INDICATE_LISTENER_INDICATOR_ID(indicator));
-
- gboolean removed = FALSE;
-
- /* Find the server that was related to this item */
- serverList_t sl_item_local = {0};
- serverList_t * sl_item = NULL;
- sl_item_local.server = server;
- GList * serverentry = g_list_find_custom(serverList, &sl_item_local, serverList_equal);
- if (serverentry == NULL) {
- /* We didn't care about that server */
- return;
- }
- sl_item = (serverList_t *)serverentry->data;
-
- /* Look in the IM Hash Table */
- imList_t listData = {0};
- listData.server = server;
- listData.indicator = indicator;
-
- GList * listItem = g_list_find_custom(sl_item->imList, &listData, imList_equal);
- DbusmenuMenuitem * menuitem = NULL;
- imList_t * ilt = NULL;
- if (listItem != NULL) {
- ilt = (imList_t *)listItem->data;
- menuitem = ilt->menuitem;
- }
-
- /* If we found a menu item and an imList_t item then
- we can go ahead and remove it. Otherwise we can
- skip this and exit. */
- if (!removed && menuitem != NULL) {
- sl_item->imList = g_list_remove(sl_item->imList, ilt);
- g_signal_handler_disconnect(menuitem, ilt->timechange_cb);
- g_signal_handler_disconnect(menuitem, ilt->attentionchange_cb);
- g_free(ilt);
-
- if (im_menu_item_get_attention(IM_MENU_ITEM(menuitem)) && im_menu_item_shown(IM_MENU_ITEM(menuitem))) {
- /* If the removed indicator menu item was asking for
- attention we need to see if this server should still
- be asking for attention. */
- server_attention(sl_item);
- /* If the server is no longer asking for attention then
- we need to check if the whole system should be. */
- if (!sl_item->attention) {
- check_attention();
- }
- }
-
- if (im_menu_item_shown(IM_MENU_ITEM(menuitem)) && g_list_length(sl_item->imList) >= MAX_NUMBER_OF_INDICATORS) {
- /* In this case we need to show a different indicator
- becasue a shown one has left. But we're going to be
- easy and set all the values. */
- GList * indicatoritem;
- gint count;
- for (indicatoritem = sl_item->imList, count = 0; indicatoritem != NULL; indicatoritem = g_list_next(indicatoritem), count++) {
- imList_t * im = (imList_t *)indicatoritem->data;
- im_menu_item_show(IM_MENU_ITEM(im->menuitem), count < MAX_NUMBER_OF_INDICATORS);
- }
- }
-
- /* Hide the item immediately, and then remove it
- which might take a little longer. */
- dbusmenu_menuitem_property_set_bool(menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
- dbusmenu_menuitem_child_delete(DBUSMENU_MENUITEM(data), menuitem);
- removed = TRUE;
- }
-
- if (!removed) {
- g_warning("We were asked to remove %s %d but we didn't.", INDICATE_LISTENER_SERVER_DBUS_NAME(server), INDICATE_LISTENER_INDICATOR_ID(indicator));
- }
-
- return;
-}
-
-static void
-app_dir_changed (GFileMonitor * monitor, GFile * file, GFile * other_file, GFileMonitorEvent event_type, gpointer user_data)
-{
- gchar * directory = (gchar *)user_data;
- g_debug("Application directory changed: %s", directory);
-
- switch (event_type) {
- case G_FILE_MONITOR_EVENT_DELETED: {
- gchar * path = g_file_get_path(file);
- g_debug("\tDelete: %s", path);
- g_idle_add(destroy_launcher, path);
- break;
- }
- case G_FILE_MONITOR_EVENT_CREATED: {
- gchar * path = g_file_get_path(file);
- g_debug("\tCreate: %s", path);
- if (g_str_has_suffix(path, "keyfile")) {
- g_idle_add(build_launcher_keyfile, path);
- } else {
- g_idle_add(build_launcher, path);
- }
- break;
- }
- default:
- break;
- }
-
- return;
-}
-
-/* Check to see if a new desktop file causes
- any of the launchers to be eclipsed by a running
- process */
-static void
-check_eclipses (AppMenuItem * ai)
-{
- g_debug("Checking eclipsing");
- const gchar * aidesktop = app_menu_item_get_desktop(ai);
- if (aidesktop == NULL) return;
- g_debug("\tApp desktop: %s", aidesktop);
-
- GList * llitem;
- for (llitem = launcherList; llitem != NULL; llitem = llitem->next) {
- launcherList_t * ll = (launcherList_t *)llitem->data;
- const gchar * lidesktop = launcher_menu_item_get_desktop(ll->menuitem);
- g_debug("\tLauncher desktop: %s", lidesktop);
-
- if (!g_strcmp0(aidesktop, lidesktop)) {
- launcher_menu_item_set_eclipsed(ll->menuitem, TRUE);
- dbusmenu_menuitem_property_set_bool(ll->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
- break;
- }
- }
-
- return;
-}
-
-/* Remove any eclipses that might have been caused
- by this app item that is now retiring */
-static void
-remove_eclipses (AppMenuItem * ai)
-{
- const gchar * aidesktop = app_menu_item_get_desktop(ai);
- if (aidesktop == NULL) return;
-
- if (blacklist_check(aidesktop)) return;
-
- GList * llitem;
- for (llitem = launcherList; llitem != NULL; llitem = llitem->next) {
- launcherList_t * ll = (launcherList_t *)llitem->data;
- const gchar * lidesktop = launcher_menu_item_get_desktop(ll->menuitem);
-
- if (!g_strcmp0(aidesktop, lidesktop)) {
- launcher_menu_item_set_eclipsed(ll->menuitem, FALSE);
- dbusmenu_menuitem_property_set_bool(ll->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
- break;
- }
- }
-
- return;
-}
-
-/* Remove a launcher from the system. We need to figure
- out what it's up to! */
-static gboolean
-destroy_launcher (gpointer data)
-{
- gchar * appdirentry = (gchar *)data;
-
- GList * listitem;
- GList * direntry;
- launcherList_t * li;
- gchar * appdir;
-
- for (listitem = launcherList; listitem != NULL; listitem = listitem->next) {
- li = (launcherList_t *)listitem->data;
- for (direntry = li->appdiritems; direntry != NULL; direntry = direntry->next) {
- appdir = (gchar *)direntry->data;
- if (!g_strcmp0(appdir, appdirentry)) {
- break;
- }
- }
-
- if (direntry != NULL) {
- break;
- }
- }
-
- if (listitem == NULL) {
- g_warning("Removed '%s' by the way of it not seeming to exist anywhere.", appdirentry);
- return FALSE;
- }
-
- if (g_list_length(li->appdiritems) > 1) {
- /* Just remove this item, and we can move on */
- g_debug("Just removing file entry: %s", appdir);
- li->appdiritems = g_list_remove(li->appdiritems, appdir);
- g_free(appdir);
- return FALSE;
- }
-
- /* Full Destroy */
- g_free(appdir);
- g_list_free(li->appdiritems);
-
- if (li->menuitem != NULL) {
- /* If there are shortcuts remove them */
- GList * shortcuts = launcher_menu_item_get_items(li->menuitem);
- while (shortcuts != NULL) {
- dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(shortcuts->data), DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
- dbusmenu_menuitem_child_delete(DBUSMENU_MENUITEM(data), DBUSMENU_MENUITEM(shortcuts->data));
- shortcuts = g_list_next(shortcuts);
- }
-
- dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(li->menuitem), DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
- dbusmenu_menuitem_child_delete(root_menuitem, DBUSMENU_MENUITEM(li->menuitem));
- g_object_unref(G_OBJECT(li->menuitem));
- li->menuitem = NULL;
- }
-
- launcherList = g_list_remove(launcherList, li);
- g_free(li);
-
- return FALSE;
-}
-
-/* This function turns a specific file into a menu
+ 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 *
+add_application (const gchar *desktop_id)
+{
+ GDesktopAppInfo *appinfo;
+ gchar *id;
+ AppSection *section;
+
+ appinfo = g_desktop_app_info_new (desktop_id);
+ if (!appinfo) {
+ g_warning ("could not add '%s', there's no desktop file with that id", desktop_id);
+ return NULL;
+ }
+
+ id = g_app_info_get_simple_id (G_APP_INFO (appinfo));
+ section = g_hash_table_lookup (applications, id);
+
+ if (!section) {
+ GMenuItem *menuitem;
+
+ section = app_section_new(appinfo);
+ g_hash_table_insert (applications, g_strdup (id), section);
+
+ g_action_muxer_insert (action_muxer, id, app_section_get_actions (section));
+ g_signal_connect (section, "notify::actions",
+ G_CALLBACK (actions_changed), NULL);
+ g_signal_connect (section, "notify::draws-attention",
+ G_CALLBACK (draws_attention_changed), NULL);
+ 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));
+ g_menu_item_set_attribute (menuitem, "action-namespace", "s", id);
+ g_menu_insert_item (menu, g_menu_model_get_n_items (G_MENU_MODEL (menu)) -1, menuitem);
+ 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;
+}
+
+static void
+remove_application (const char *desktop_id)
+{
+ GDesktopAppInfo *appinfo;
+ gchar *id;
+ AppSection *section;
+
+ appinfo = g_desktop_app_info_new (desktop_id);
+ if (!appinfo) {
+ g_warning ("could not remove '%s', there's no desktop file with that id", desktop_id);
+ return;
+ }
+
+ id = g_app_info_get_simple_id (G_APP_INFO (appinfo));
+
+ section = g_hash_table_lookup (applications, id);
+ if (section) {
+ remove_section (section, id);
+ }
+ else {
+ g_warning ("could not remove '%s', it's not registered", desktop_id);
+ }
+
+ g_free (id);
+ g_object_unref (appinfo);
+}
+
+/* This function turns a specific desktop id into a menu
item and registers it appropriately with everyone */
static gboolean
build_launcher (gpointer data)
{
- /* Read the file get the data */
- gchar * path = (gchar *)data;
- g_debug("\tpath: %s", path);
- gchar * desktop = NULL;
-
- g_file_get_contents(path, &desktop, NULL, NULL);
-
- if (desktop == NULL) {
- return FALSE;
- }
-
- gchar * trimdesktop = pango_trim_string(desktop);
- g_free(desktop);
- g_debug("\tcontents: %s", trimdesktop);
-
- build_launcher_core(trimdesktop);
- g_free(trimdesktop);
- return FALSE;
-}
-
-/* Use a key file to find the desktop file. */
-static gboolean
-build_launcher_keyfile (gpointer data)
-{
- gchar * path = (gchar *)data;
- gchar * desktop = desktop_file_from_keyfile (path);
- if (desktop != NULL) {
- build_launcher_core(desktop);
- g_free(desktop);
- }
- return FALSE;
-}
-
-/* The core action of dealing with a desktop file that should
- be a launcher */
-static void
-build_launcher_core (const gchar * desktop)
-{
- /* Check to see if we already have a launcher */
- GList * listitem;
- for (listitem = launcherList; listitem != NULL; listitem = listitem->next) {
- launcherList_t * li = (launcherList_t *)listitem->data;
- if (!g_strcmp0(launcher_menu_item_get_desktop(li->menuitem), desktop)) {
- break;
- }
- }
-
- if (listitem == NULL) {
- /* If not */
- /* Build the item */
- launcherList_t * ll = g_new0(launcherList_t, 1);
- ll->menuitem = launcher_menu_item_new(desktop);
- ll->appdiritems = g_list_append(NULL, g_strdup(desktop));
-
- /* Build a separator */
- ll->separator = dbusmenu_menuitem_new();
- dbusmenu_menuitem_property_set(ll->separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR);
-
- /* Add it to the list */
- launcherList = g_list_insert_sorted(launcherList, ll, launcherList_sort);
-
- /* Add it to the menu */
- dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(ll->menuitem), DBUSMENU_MENUITEM_PROP_TYPE, APPLICATION_MENUITEM_TYPE);
- dbusmenu_menuitem_child_append(root_menuitem, DBUSMENU_MENUITEM(ll->menuitem));
- GList * shortcuts = launcher_menu_item_get_items(ll->menuitem);
- while (shortcuts != NULL) {
- dbusmenu_menuitem_child_append(root_menuitem, DBUSMENU_MENUITEM(shortcuts->data));
- shortcuts = g_list_next(shortcuts);
- }
- dbusmenu_menuitem_child_append(root_menuitem, DBUSMENU_MENUITEM(ll->separator));
-
- /* If we're in the black list or we've gotten eclipsed
- by something else, hide the item and the separator. */
- if (blacklist_check(launcher_menu_item_get_desktop(ll->menuitem)) ||
- launcher_menu_item_get_eclipsed(ll->menuitem)) {
- launcher_menu_item_set_eclipsed(ll->menuitem, TRUE);
- dbusmenu_menuitem_property_set_bool(ll->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
- }
-
- /* Check to see if any of the current applications should
- be eclipsing us. */
- GList * server;
- for (server = serverList; server != NULL; server = g_list_next(server)) {
- serverList_t * slt = (serverList_t *)server->data;
- check_eclipses(slt->menuitem);
- }
-
- resort_menu(root_menuitem);
- check_hidden();
- } else {
- /* If so add ourselves */
- launcherList_t * ll = (launcherList_t *)listitem->data;
- ll->appdiritems = g_list_append(ll->appdiritems, g_strdup(desktop));
- }
-
- return;
+ gchar *desktop_id = data;
+
+ add_application (desktop_id);
+
+ g_free (desktop_id);
+ return FALSE;
}
/* This function goes through all the launchers that we're
@@ -1393,86 +384,272 @@
static gboolean
build_launchers (gpointer data)
{
- gchar * directory = (gchar *)data;
-
- if (!g_file_test(directory, G_FILE_TEST_IS_DIR)) {
- return FALSE;
- }
-
- GFile * filedir = g_file_new_for_path(directory);
- GFileMonitor * dirmon = g_file_monitor_directory(filedir, G_FILE_MONITOR_NONE, NULL, NULL);
- if (dirmon != NULL) {
- g_signal_connect(G_OBJECT(dirmon), "changed", G_CALLBACK(app_dir_changed), directory);
- }
-
- GError * error = NULL;
- GDir * dir = g_dir_open(directory, 0, &error);
- if (dir == NULL) {
- g_warning("Unable to open system apps directory: %s", error->message);
- g_error_free(error);
- return FALSE;
- }
-
- const gchar * filename = NULL;
- while ((filename = g_dir_read_name(dir)) != NULL) {
- g_debug("Found file: %s", filename);
- gchar * path = g_build_filename(directory, filename, NULL);
- if (g_str_has_suffix(path, "keyfile")) {
- g_idle_add(build_launcher_keyfile, path);
- } else {
- g_idle_add(build_launcher, path);
- }
- }
-
- g_dir_close(dir);
- launcherList = g_list_sort(launcherList, launcherList_sort);
+ gchar **applications = g_settings_get_strv (settings, "applications");
+ gchar **app;
+
+ g_return_val_if_fail (applications != NULL, FALSE);
+
+ for (app = applications; *app; app++)
+ {
+ g_idle_add(build_launcher, g_strdup (*app));
+ }
+
+ g_strfreev (applications);
return FALSE;
}
static void
service_shutdown (IndicatorService * service, gpointer user_data)
{
+ GMainLoop *mainloop = user_data;
+
g_warning("Shutting down service!");
g_main_loop_quit(mainloop);
- return;
-}
-
-/* Respond to changing status by updating the icon that
- is on the panel */
-static void
-status_update_callback (void)
-{
- return;
-}
-
-/* The clear attention item has been clicked on, what to do? */
-static void
-clear_attention_activate (DbusmenuMenuitem * mi, guint timestamp, MessageServiceDbus * dbus)
-{
- message_service_dbus_set_attention(dbus, FALSE);
- return;
-}
-
-/* Handle an update of the active state to ensure that we're
- only enabled when we could do something. */
-static void
-clear_attention_handler (MessageServiceDbus * msd, gboolean attention, DbusmenuMenuitem * clearitem)
-{
- dbusmenu_menuitem_property_set_bool(clearitem, DBUSMENU_MENUITEM_PROP_ENABLED, attention);
- return;
-}
-
-/* Oh, if you don't know what main() is for
- we really shouldn't be talking. */
+}
+
+static void
+app_section_remove_attention (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ AppSection *section = value;
+ app_section_clear_draws_attention (section);
+}
+
+static void
+clear_action_activate (GSimpleAction *simple,
+ GVariant *param,
+ gpointer user_data)
+{
+ g_hash_table_foreach (applications, app_section_remove_attention, NULL);
+}
+
+static void
+status_action_activate (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ const gchar *status;
+
+ status = g_variant_get_string (parameter, NULL);
+
+ indicator_messages_service_emit_status_changed (messages_service, status);
+}
+
+static void
+register_application (IndicatorMessagesService *service,
+ GDBusMethodInvocation *invocation,
+ const gchar *desktop_id,
+ const gchar *menu_path,
+ gpointer user_data)
+{
+ AppSection *section;
+ GDBusConnection *bus;
+ const gchar *sender;
+
+ section = add_application (desktop_id);
+ if (!section)
+ return;
+
+ bus = g_dbus_interface_skeleton_get_connection (G_DBUS_INTERFACE_SKELETON (service));
+ sender = g_dbus_method_invocation_get_sender (invocation);
+
+ app_section_set_object_path (section, bus, sender, menu_path);
+ g_settings_strv_append_unique (settings, "applications", desktop_id);
+
+ indicator_messages_service_complete_register_application (service, invocation);
+}
+
+static void
+unregister_application (IndicatorMessagesService *service,
+ GDBusMethodInvocation *invocation,
+ const gchar *desktop_id,
+ gpointer user_data)
+{
+ remove_application (desktop_id);
+ g_settings_strv_remove (settings, "applications", desktop_id);
+
+ indicator_messages_service_complete_unregister_application (service, invocation);
+}
+
+static void
+application_stopped_running (IndicatorMessagesService *service,
+ GDBusMethodInvocation *invocation,
+ const gchar *desktop_id,
+ gpointer user_data)
+{
+ GDesktopAppInfo *appinfo;
+ gchar *id;
+ AppSection *section;
+
+ indicator_messages_service_complete_application_stopped_running (service, invocation);
+
+ if (!(appinfo = g_desktop_app_info_new (desktop_id)))
+ return;
+
+ id = g_app_info_get_simple_id (G_APP_INFO (appinfo));
+ section = g_hash_table_lookup (applications, id);
+ app_section_unset_object_path (section);
+
+ g_free (id);
+ g_object_unref (appinfo);
+}
+
+static void
+set_status (IndicatorMessagesService *service,
+ GDBusMethodInvocation *invocation,
+ const gchar *desktop_id,
+ const gchar *status_str,
+ gpointer user_data)
+{
+ GDesktopAppInfo *appinfo;
+ gchar *id;
+ AppSection *section;
+
+ 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"));
+
+ 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 *
+create_action_group (void)
+{
+ GSimpleActionGroup *actions;
+ 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 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_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);
+ g_signal_connect (clear, "activate", G_CALLBACK (clear_action_activate), NULL);
+
+ g_simple_action_group_insert (actions, G_ACTION (messages));
+ g_simple_action_group_insert (actions, G_ACTION (status));
+ g_simple_action_group_insert (actions, G_ACTION (clear));
+
+ g_free (icon);
+ return actions;
+}
+
+static GMenuModel *
+create_status_section (void)
+{
+ GMenu *menu;
+ GMenuItem *item;
+ struct status_item {
+ gchar *label;
+ gchar *action;
+ gchar *icon_name;
+ } status_items[] = {
+ { _("Available"), "status::available", "user-available" },
+ { _("Away"), "status::away", "user-away" },
+ { _("Busy"), "status::busy", "user-busy" },
+ { _("Invisible"), "status::invisible", "user-invisible" },
+ { _("Offline"), "status::offline", "user-offline" }
+ };
+ int i;
+
+ menu = g_menu_new ();
+
+ item = g_menu_item_new (NULL, NULL);
+ g_menu_item_set_attribute (item, "x-canonical-type", "s", "IdoMenuItem");
+
+ for (i = 0; i < G_N_ELEMENTS (status_items); i++) {
+ g_menu_item_set_label (item, status_items[i].label);
+ g_menu_item_set_detailed_action (item, status_items[i].action);
+ g_menu_item_set_attribute (item, "x-canonical-icon", "s", status_items[i].icon_name);
+ g_menu_append_item (menu, item);
+ }
+
+ g_object_unref (item);
+ return G_MENU_MODEL (menu);
+}
+
+static void
+got_bus (GObject *object,
+ GAsyncResult * res,
+ gpointer user_data)
+{
+ GDBusConnection *bus;
+ GError *error = NULL;
+
+ bus = g_bus_get_finish (res, &error);
+ if (!bus) {
+ g_warning ("unable to connect to the session bus: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ g_dbus_connection_export_action_group (bus, INDICATOR_MESSAGES_DBUS_OBJECT,
+ G_ACTION_GROUP (action_muxer), &error);
+ if (error) {
+ g_warning ("unable to export action group on dbus: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ g_dbus_connection_export_menu_model (bus, INDICATOR_MESSAGES_DBUS_OBJECT,
+ G_MENU_MODEL (toplevel_menu), &error);
+ if (error) {
+ g_warning ("unable to export menu on dbus: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (messages_service),
+ bus, INDICATOR_MESSAGES_DBUS_SERVICE_OBJECT,
+ &error);
+ if (error) {
+ g_warning ("unable to export messages service on dbus: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ g_object_unref (bus);
+}
+
int
main (int argc, char ** argv)
{
- /* Glib init */
- g_type_init();
+ GMainLoop * mainloop;
+ IndicatorService * service;
+
+ mainloop = g_main_loop_new (NULL, FALSE);
/* Create the Indicator Service interface */
service = indicator_service_new_version(INDICATOR_MESSAGES_DBUS_NAME, 1);
- g_signal_connect(service, INDICATOR_SERVICE_SIGNAL_SHUTDOWN, G_CALLBACK(service_shutdown), NULL);
+ g_signal_connect(service, INDICATOR_SERVICE_SIGNAL_SHUTDOWN, G_CALLBACK(service_shutdown), mainloop);
/* Setting up i18n and gettext. Apparently, we need
all of these. */
@@ -1480,58 +657,43 @@
bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
textdomain (GETTEXT_PACKAGE);
- /* Create the Seen DB */
- seen_db_init();
-
/* Bring up the service DBus interface */
- dbus_interface = message_service_dbus_new();
-
- /* Build the base menu */
- root_menuitem = dbusmenu_menuitem_new();
- DbusmenuServer * server = dbusmenu_server_new(INDICATOR_MESSAGES_DBUS_OBJECT);
- dbusmenu_server_set_root(server, root_menuitem);
-
- /* Add status items */
- GList * statusitems = status_items_build(&status_update_callback);
- while (statusitems != NULL) {
- dbusmenu_menuitem_child_append(root_menuitem, DBUSMENU_MENUITEM(statusitems->data));
- statusitems = g_list_next(statusitems);
- }
- status_separator = dbusmenu_menuitem_new();
- dbusmenu_menuitem_property_set(status_separator, DBUSMENU_MENUITEM_PROP_TYPE, DBUSMENU_CLIENT_TYPES_SEPARATOR);
- dbusmenu_menuitem_child_append(root_menuitem, status_separator);
-
- /* Add in the clear attention item */
- clear_attention = dbusmenu_menuitem_new();
- dbusmenu_menuitem_property_set(clear_attention, DBUSMENU_MENUITEM_PROP_LABEL, _("Clear"));
- dbusmenu_menuitem_child_append(root_menuitem, clear_attention);
- g_signal_connect(G_OBJECT(dbus_interface), MESSAGE_SERVICE_DBUS_SIGNAL_ATTENTION_CHANGED, G_CALLBACK(clear_attention_handler), clear_attention);
- g_signal_connect(G_OBJECT(clear_attention), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(clear_attention_activate), dbus_interface);
-
- /* Start up the libindicate listener */
- listener = indicate_listener_ref_default();
- serverList = NULL;
-
- g_signal_connect(listener, INDICATE_LISTENER_SIGNAL_INDICATOR_ADDED, G_CALLBACK(indicator_added), root_menuitem);
- g_signal_connect(listener, INDICATE_LISTENER_SIGNAL_INDICATOR_REMOVED, G_CALLBACK(indicator_removed), root_menuitem);
- g_signal_connect(listener, INDICATE_LISTENER_SIGNAL_SERVER_ADDED, G_CALLBACK(server_added), root_menuitem);
- g_signal_connect(listener, INDICATE_LISTENER_SIGNAL_SERVER_REMOVED, G_CALLBACK(server_removed), root_menuitem);
-
- /* Find launchers by looking through the config directories
- in the idle loop */
- g_idle_add(blacklist_init, NULL);
- g_idle_add(build_launchers, SYSTEM_APPS_DIR);
- g_idle_add(build_launchers, SYSTEM_APPS_DIR_OLD);
- gchar * userdir = g_build_filename(g_get_user_config_dir(), USER_APPS_DIR, NULL);
- g_idle_add(build_launchers, userdir);
-
- /* Let's run a mainloop */
- mainloop = g_main_loop_new(NULL, FALSE);
+ messages_service = indicator_messages_service_skeleton_new ();
+
+ g_bus_get (G_BUS_TYPE_SESSION, NULL, got_bus, NULL);
+
+ actions = create_action_group ();
+
+ action_muxer = g_action_muxer_new ();
+ g_action_muxer_insert (action_muxer, NULL, G_ACTION_GROUP (actions));
+
+ g_signal_connect (messages_service, "handle-register-application",
+ G_CALLBACK (register_application), NULL);
+ g_signal_connect (messages_service, "handle-unregister-application",
+ G_CALLBACK (unregister_application), NULL);
+ g_signal_connect (messages_service, "handle-application-stopped-running",
+ G_CALLBACK (application_stopped_running), NULL);
+ g_signal_connect (messages_service, "handle-set-status",
+ G_CALLBACK (set_status), NULL);
+
+ menu = g_menu_new ();
+ chat_section = create_status_section ();
+ g_menu_append (menu, _("Clear"), "clear");
+
+ toplevel_menu = g_menu_new ();
+
+ settings = g_settings_new ("com.canonical.indicator.messages");
+
+ applications = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+
+ g_idle_add(build_launchers, NULL);
+
g_main_loop_run(mainloop);
/* Clean up */
- status_items_cleanup();
- g_free(userdir);
-
+ g_object_unref (messages_service);
+ g_object_unref (chat_section);
+ g_object_unref (settings);
+ g_hash_table_unref (applications);
return 0;
}
=== modified file 'src/messages-service.xml'
--- src/messages-service.xml 2011-07-21 21:17:09 +0000
+++ src/messages-service.xml 2013-06-07 21:39:23 +0000
@@ -2,21 +2,26 @@
<node name="/">
<interface name="com.canonical.indicator.messages.service">
-<!-- Methods -->
- <method name="AttentionRequested">
- <arg type="b" name="dot" direction="out" />
- </method>
- <method name="IconShown">
- <arg type="b" name="hidden" direction="out" />
- </method>
- <method name="ClearAttention" />
-
-<!-- Signals -->
- <signal name="AttentionChanged">
- <arg type="b" name="dot" direction="out" />
- </signal>
- <signal name="IconChanged">
- <arg type="b" name="hidden" direction="out" />
+ <method name="RegisterApplication">
+ <arg type="s" name="desktop_id" direction="in" />
+ <arg type="o" name="menu_path" direction="in" />
+ </method>
+
+ <method name="UnregisterApplication">
+ <arg type="s" name="desktop_id" direction="in" />
+ </method>
+
+ <method name="ApplicationStoppedRunning">
+ <arg type="s" name="desktop_id" direction="in" />
+ </method>
+
+ <method name="SetStatus">
+ <arg type="s" name="desktop_id" direction="in" />
+ <arg type="s" name="status" direction="in" />
+ </method>
+
+ <signal name="StatusChanged">
+ <arg type="s" name="status" direction="in" />
</signal>
</interface>
=== removed file 'src/seen-db.c'
--- src/seen-db.c 2010-03-25 15:25:13 +0000
+++ src/seen-db.c 1970-01-01 00:00:00 +0000
@@ -1,177 +0,0 @@
-/*
-A small database of which desktop files we've seen.
-
-Copyright 2010 Canonical Ltd.
-
-Authors:
- Ted Gould <ted@xxxxxxxxxxxxx>
-
-This program is free software: you can redistribute it and/or modify it
-under the terms of the GNU General Public License version 3, as published
-by the Free Software Foundation.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranties of
-MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
-PURPOSE. See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along
-with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "seen-db.h"
-
-#define GROUP_NAME "Seen Database"
-#define KEY_NAME "DesktopFiles"
-
-GHashTable * seendb = NULL;
-gchar * filename = NULL;
-gchar * dirname = NULL;
-guint write_process = 0;
-
-/* Build the hashtable and then see if we have a keyfile that
- we can get the history of desktop files we've seen. */
-void
-seen_db_init(void)
-{
- g_return_if_fail(seendb == NULL);
-
- seendb = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
-
- /* Build the filename for the seen database. We're putting
- it in the cache directory because it could get deleted and
- it really wouldn't be a big deal. */
- if (dirname == NULL) {
- dirname = g_build_filename(g_get_user_cache_dir(), "indicators", "messages", NULL);
- }
- if (filename == NULL) {
- filename = g_build_filename(dirname, "seen-db.keyfile", NULL);
- }
-
- if (g_file_test(filename, G_FILE_TEST_EXISTS)) {
- GKeyFile * keyfile = g_key_file_new();
-
- /* Load from file */
- if (!g_key_file_load_from_file(keyfile, filename, G_KEY_FILE_NONE, NULL)) {
- g_key_file_free(keyfile);
- keyfile = NULL;
- }
-
- /* Check for keys */
- if (keyfile != NULL && !g_key_file_has_key(keyfile, GROUP_NAME, KEY_NAME, NULL)) {
- g_warning("Seen DB '%s' does not have key '%s' in group '%s'", filename, KEY_NAME, GROUP_NAME);
- g_key_file_free(keyfile);
- keyfile = NULL;
- }
-
- /* Grab them and put in DB */
- if (keyfile != NULL) {
- gchar ** desktops = g_key_file_get_string_list(keyfile, GROUP_NAME, KEY_NAME, NULL, NULL);
- gint i = 0;
-
- while (desktops[i] != NULL) {
- g_hash_table_insert(seendb,
- g_strdup(desktops[i]),
- GINT_TO_POINTER(TRUE));
- i++;
- }
-
- g_strfreev(desktops);
- }
-
- /* Clean up our file */
- if (keyfile != NULL) {
- g_key_file_free(keyfile);
- }
- }
-
- return;
-}
-
-/* A function to write out the seen database after it's been
- modified for a while. */
-static gboolean
-write_seen_db (gpointer user_data)
-{
- write_process = 0;
-
- /* Build up the key file */
- GKeyFile * keyfile = g_key_file_new();
- GArray * desktops = g_array_new(FALSE, FALSE, sizeof(gchar *));
-
- /* Get the keys from the hashtable and make them
- into an array */
- if (keyfile != NULL) {
- GList * desktop_keys = g_hash_table_get_keys(seendb);
- GList * head = NULL;
-
- for (head = desktop_keys; head != NULL; head = g_list_next(head)) {
- g_array_append_val(desktops, head->data);
- }
-
- g_list_free(desktop_keys);
- }
-
- /* Use the array to dump the strings into the keyfile */
- g_key_file_set_string_list(keyfile,
- GROUP_NAME,
- KEY_NAME,
- (const gchar * const *)desktops->data,
- desktops->len);
- g_array_free(desktops, TRUE);
-
- /* Dump the key file to string */
- gchar * keydump = NULL;
- gsize keydumplen = 0;
- keydump = g_key_file_to_data(keyfile, &keydumplen, NULL);
- g_key_file_free(keyfile);
-
- /* Ensure the directory exists */
- if (g_mkdir_with_parents(dirname, 0700) != 0) {
- g_warning("Unable to make directory: %s", dirname);
- g_free(keydump);
- return FALSE;
- }
-
- /* Dump out the file */
- GError * error = NULL;
- if (!g_file_set_contents(filename, keydump, keydumplen, &error)) {
- g_warning("Unable to write out file '%s': %s", filename, error->message);
- g_error_free(error);
- }
-
- /* Clean up */
- g_free(keydump);
-
- return FALSE;
-}
-
-/* Add a new desktop file to the seen database. Also sets up a timer
- to do the write out. */
-void
-seen_db_add (const gchar * desktop)
-{
- /* If this is a new one, let's set up the timer. If
- there's already one clear it. */
- if (!seen_db_seen(desktop)) {
- if (write_process != 0) {
- g_source_remove(write_process);
- write_process = 0;
- }
-
- write_process = g_timeout_add_seconds(60, write_seen_db, NULL);
- }
-
- g_hash_table_insert(seendb,
- g_strdup(desktop),
- GINT_TO_POINTER(TRUE));
-
- return;
-}
-
-/* Checks to see if a desktop file has been seen. */
-gboolean
-seen_db_seen (const gchar * desktop)
-{
- return GPOINTER_TO_INT(g_hash_table_lookup(seendb, desktop));
-}
=== removed file 'src/seen-db.h'
--- src/seen-db.h 2010-03-25 02:26:07 +0000
+++ src/seen-db.h 1970-01-01 00:00:00 +0000
@@ -1,31 +0,0 @@
-/*
-A small database of which desktop files we've seen.
-
-Copyright 2010 Canonical Ltd.
-
-Authors:
- Ted Gould <ted@xxxxxxxxxxxxx>
-
-This program is free software: you can redistribute it and/or modify it
-under the terms of the GNU General Public License version 3, as published
-by the Free Software Foundation.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranties of
-MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
-PURPOSE. See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along
-with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef SEEN_DB_H__
-#define SEEN_DB_H__ 1
-
-#include <glib.h>
-
-void seen_db_init(void);
-void seen_db_add (const gchar * desktop);
-gboolean seen_db_seen (const gchar * desktop);
-
-#endif /* SEEN_DB_H__ */
=== removed file 'src/status-items.c'
--- src/status-items.c 2011-07-13 20:17:58 +0000
+++ src/status-items.c 1970-01-01 00:00:00 +0000
@@ -1,314 +0,0 @@
-/*
-Code to build and maintain the status adjustment menuitems.
-
-Copyright 2011 Canonical Ltd.
-
-Authors:
- Ted Gould <ted@xxxxxxxxxxxxx>
-
-This program is free software: you can redistribute it and/or modify it
-under the terms of the GNU General Public License version 3, as published
-by the Free Software Foundation.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranties of
-MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
-PURPOSE. See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along
-with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <glib.h>
-#include <glib/gi18n.h>
-#include <gio/gio.h>
-#include <libdbusmenu-glib/dbusmenu-glib.h>
-
-#include "status-items.h"
-#include "status-provider.h"
-
-static const gchar * status_strings [STATUS_PROVIDER_STATUS_LAST] = {
- /* STATUS_PROVIDER_STATUS_ONLINE, */ N_("Available"),
- /* STATUS_PROVIDER_STATUS_AWAY, */ N_("Away"),
- /* STATUS_PROVIDER_STATUS_DND */ N_("Busy"),
- /* STATUS_PROVIDER_STATUS_INVISIBLE */ N_("Invisible"),
- /* STATUS_PROVIDER_STATUS_OFFLINE, */ N_("Offline"),
- /* STATUS_PROVIDER_STATUS_DISCONNECTED*/ N_("Offline")
-};
-
-static const gchar * status_icons[STATUS_PROVIDER_STATUS_LAST] = {
- /* STATUS_PROVIDER_STATUS_ONLINE, */ "user-available",
- /* STATUS_PROVIDER_STATUS_AWAY, */ "user-away",
- /* STATUS_PROVIDER_STATUS_DND, */ "user-busy",
- /* STATUS_PROVIDER_STATUS_INVISIBLE, */ "user-invisible",
- /* STATUS_PROVIDER_STATUS_OFFLINE */ "user-offline",
- /* STATUS_PROVIDER_STATUS_DISCONNECTED */ "user-offline-panel"
-};
-
-static const gchar * panel_icons[STATUS_PROVIDER_STATUS_LAST] = {
- /* STATUS_PROVIDER_STATUS_ONLINE, */ "indicator-messages-user-available",
- /* STATUS_PROVIDER_STATUS_AWAY, */ "indicator-messages-user-away",
- /* STATUS_PROVIDER_STATUS_DND, */ "indicator-messages-user-busy",
- /* STATUS_PROVIDER_STATUS_INVISIBLE, */ "indicator-messages-user-invisible",
- /* STATUS_PROVIDER_STATUS_OFFLINE */ "indicator-messages-user-offline",
- /* STATUS_PROVIDER_STATUS_DISCONNECTED */ "indicator-messages-user-disconnected"
-};
-
-static const gchar * panel_active_icons[STATUS_PROVIDER_STATUS_LAST] = {
- /* STATUS_PROVIDER_STATUS_ONLINE, */ "indicator-messages-new-user-available",
- /* STATUS_PROVIDER_STATUS_AWAY, */ "indicator-messages-new-user-away",
- /* STATUS_PROVIDER_STATUS_DND, */ "indicator-messages-new-user-busy",
- /* STATUS_PROVIDER_STATUS_INVISIBLE, */ "indicator-messages-new-user-invisible",
- /* STATUS_PROVIDER_STATUS_OFFLINE */ "indicator-messages-new-user-offline",
- /* STATUS_PROVIDER_STATUS_DISCONNECTED */ "indicator-messages-new-user-disconnected"
-};
-
-/* Prototypes */
-static gboolean provider_directory_parse (gpointer dir);
-static gboolean load_status_provider (gpointer dir);
-static void user_status_change (DbusmenuMenuitem * item, guint timestamp, gpointer pstatus);
-
-/* Globals */
-static StatusProviderStatus current_status = STATUS_PROVIDER_STATUS_DISCONNECTED;
-static GList * menuitems = NULL;
-static GList * status_providers = NULL;
-static StatusUpdateFunc update_func = NULL;
-
-/* Build the inital status items and start kicking off the async code
- for handling all the statuses */
-GList *
-status_items_build (StatusUpdateFunc status_update_func)
-{
- int i;
- for (i = STATUS_PROVIDER_STATUS_ONLINE; i < STATUS_PROVIDER_STATUS_DISCONNECTED; i++) {
- DbusmenuMenuitem * item = dbusmenu_menuitem_new();
-
- dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_LABEL, _(status_strings[i]));
- dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_ICON_NAME, status_icons[i]);
-
- dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
- dbusmenu_menuitem_property_set_bool(item, DBUSMENU_MENUITEM_PROP_ENABLED, FALSE);
-
- dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE, DBUSMENU_MENUITEM_TOGGLE_RADIO);
- dbusmenu_menuitem_property_set(item, DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED);
-
- g_signal_connect(G_OBJECT(item), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(user_status_change), GINT_TO_POINTER(i));
-
- menuitems = g_list_append(menuitems, item);
- }
-
- update_func = status_update_func;
-
- const gchar * status_providers_env = g_getenv("INDICATOR_MESSAGES_STATUS_PROVIDER_DIR");
- if (status_providers_env == NULL) {
- g_idle_add(provider_directory_parse, STATUS_PROVIDER_DIR);
- } else {
- g_idle_add(provider_directory_parse, (gpointer)status_providers_env);
- }
-
- return menuitems;
-}
-
-/* Clean up our globals and stop with all this allocation
- of memory */
-void
-status_items_cleanup (void)
-{
- while (status_providers != NULL) {
- StatusProvider * sprovider = STATUS_PROVIDER(status_providers->data);
- g_object_unref(sprovider);
- status_providers = g_list_remove(status_providers, sprovider);
- }
-
- return;
-}
-
-/* Get the icon that should be shown on the panel */
-const gchar *
-status_current_panel_icon (gboolean alert)
-{
- if (alert) {
- return panel_active_icons[current_status];
- } else {
- return panel_icons[current_status];
- }
-}
-
-/* Update status from all the providers */
-static void
-update_status (void)
-{
- StatusProviderStatus status = STATUS_PROVIDER_STATUS_DISCONNECTED;
- GList * provider;
-
- for (provider = status_providers; provider != NULL; provider = g_list_next(provider)) {
- StatusProviderStatus localstatus = status_provider_get_status(STATUS_PROVIDER(provider->data));
-
- if (localstatus < status) {
- status = localstatus;
- }
- }
-
- if (status == current_status) {
- return;
- }
-
- current_status = status;
-
- if (update_func != NULL) {
- update_func();
- }
-
- GList * menu;
- int i;
- for (menu = menuitems, i = 0; menu != NULL && i < STATUS_PROVIDER_STATUS_DISCONNECTED; menu = g_list_next(menu), i++) {
- /* If we're the seleced status or if we're disconnected
- show the user that we're offline */
- if (i == current_status || (current_status == STATUS_PROVIDER_STATUS_DISCONNECTED && i == STATUS_PROVIDER_STATUS_OFFLINE)) {
- dbusmenu_menuitem_property_set_int(DBUSMENU_MENUITEM(menu->data), DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, DBUSMENU_MENUITEM_TOGGLE_STATE_CHECKED);
- } else {
- dbusmenu_menuitem_property_set_int(DBUSMENU_MENUITEM(menu->data), DBUSMENU_MENUITEM_PROP_TOGGLE_STATE, DBUSMENU_MENUITEM_TOGGLE_STATE_UNCHECKED);
- }
-
- if (current_status == STATUS_PROVIDER_STATUS_DISCONNECTED) {
- dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(menu->data), DBUSMENU_MENUITEM_PROP_ENABLED, FALSE);
- } else {
- dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(menu->data), DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
- }
- }
-
- return;
-}
-
-/* Handle the user requesting a status change */
-static void
-user_status_change (DbusmenuMenuitem * item, guint timestamp, gpointer pstatus)
-{
- StatusProviderStatus status = GPOINTER_TO_INT(pstatus);
- GList * provider;
-
- /* Set each provider to this status */
- for (provider = status_providers; provider != NULL; provider = g_list_next(provider)) {
- status_provider_set_status(STATUS_PROVIDER(provider->data), status);
- }
-
- /* See what we really are now */
- update_status();
- return;
-}
-
-/* Start parsing a directory and setting up the entires in the idle loop */
-static gboolean
-provider_directory_parse (gpointer directory)
-{
- const gchar * dirname = (const gchar *)directory;
- g_debug("Looking for status providers in: %s", dirname);
-
- if (!g_file_test(dirname, G_FILE_TEST_EXISTS)) {
- return FALSE;
- }
-
- GDir * dir = g_dir_open(dirname, 0, NULL);
- if (dir == NULL) {
- return FALSE;
- }
-
- const gchar * name;
- while ((name = g_dir_read_name(dir)) != NULL) {
- if (!g_str_has_suffix(name, G_MODULE_SUFFIX)) {
- continue;
- }
-
- gchar * fullname = g_build_filename(dirname, name, NULL);
- g_idle_add(load_status_provider, fullname);
- }
-
- g_dir_close(dir);
-
- return FALSE;
-}
-
-/* Close the module as an idle function so that we know
- it's all cleaned up */
-static gboolean
-module_destroy_in_idle_helper (gpointer data)
-{
- GModule * module = (GModule *)data;
- if (module != NULL) {
- g_debug("Unloading module: %s", g_module_name(module));
- g_module_close(module);
- }
- return FALSE;
-}
-
-/* Set up an idle function to close the module */
-static void
-module_destroy_in_idle (gpointer data)
-{
- g_idle_add_full(G_PRIORITY_LOW, module_destroy_in_idle_helper, data, NULL);
- return;
-}
-
-/* Load a particular status provider */
-static gboolean
-load_status_provider (gpointer dir)
-{
- gchar * provider = (gchar *)dir;
-
- if (!g_file_test(provider, G_FILE_TEST_EXISTS)) {
- goto exit_final;
- }
-
- g_debug("Loading status provider: %s", provider);
-
- GModule * module;
-
- module = g_module_open(provider, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
- if (module == NULL) {
- g_warning("Unable to module for: %s", provider);
- goto exit_module_fail;
- }
-
- /* Got it */
- GType (*type_func) (void);
- if (!g_module_symbol(module, STATUS_PROVIDER_EXPORT_S, (gpointer *)&type_func)) {
- g_warning("Unable to find type symbol in: %s", provider);
- goto exit_module_fail;
- }
-
- GType provider_type = type_func();
- if (provider_type == 0) {
- g_warning("Unable to create type from: %s", provider);
- goto exit_module_fail;
- }
-
- StatusProvider * sprovider = STATUS_PROVIDER(g_object_new(provider_type, NULL));
- if (sprovider == NULL) {
- g_warning("Unable to build provider from: %s", provider);
- goto exit_module_fail;
- }
-
- /* On update let's talk to all of them and create the aggregate
- value to export */
- g_signal_connect(G_OBJECT(sprovider), STATUS_PROVIDER_SIGNAL_STATUS_CHANGED, G_CALLBACK(update_status), NULL);
-
- /* Attach the module object to the status provider so
- that when the status provider is free'd the module
- is close automatically. */
- g_object_set_data_full(G_OBJECT(sprovider), "status-provider-module", module, module_destroy_in_idle);
-
- status_providers = g_list_prepend(status_providers, sprovider);
-
- /* Force and update every time just so we know we're
- in a consistent state*/
- update_status();
-
- goto exit_final;
-
-exit_module_fail:
- g_module_close(module);
-
-exit_final:
- g_free(provider);
- return FALSE;
-}
=== removed file 'src/status-items.h'
--- src/status-items.h 2011-07-13 20:17:58 +0000
+++ src/status-items.h 1970-01-01 00:00:00 +0000
@@ -1,38 +0,0 @@
-/*
-Code to build and maintain the status adjustment menuitems.
-
-Copyright 2011 Canonical Ltd.
-
-Authors:
- Ted Gould <ted@xxxxxxxxxxxxx>
-
-This program is free software: you can redistribute it and/or modify it
-under the terms of the GNU General Public License version 3, as published
-by the Free Software Foundation.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranties of
-MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
-PURPOSE. See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along
-with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef __STATUS_ITEMS_H__
-#define __STATUS_ITEMS_H__
-
-#include <glib.h>
-
-G_BEGIN_DECLS
-
-typedef void (*StatusUpdateFunc) (void);
-
-GList * status_items_build (StatusUpdateFunc update_func);
-const gchar * status_current_panel_icon (gboolean alert);
-void status_items_cleanup (void);
-
-G_END_DECLS
-
-#endif /* __STATUS_ITEMS_H__ */
-
=== removed file 'src/status-provider-emesene.c'
--- src/status-provider-emesene.c 2011-07-29 12:25:03 +0000
+++ src/status-provider-emesene.c 1970-01-01 00:00:00 +0000
@@ -1,348 +0,0 @@
-/*
-A small wrapper utility to load indicators and put them as menu items
-into the gnome-panel using it's applet interface.
-
-Copyright 2011 Canonical Ltd.
-
-Authors:
- Stefano Candori <stefano.candori@xxxxxxxxx>
-
-This program is free software: you can redistribute it and/or modify it
-under the terms of the GNU General Public License version 3, as published
-by the Free Software Foundation.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranties of
-MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
-PURPOSE. See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along
-with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "status-provider.h"
-#include "status-provider-emesene.h"
-
-#include <dbus/dbus-glib.h>
-
-typedef enum {
- EM_STATUS_ONLINE,
- EM_STATUS_INVISIBLE,
- EM_STATUS_BUSY,
- EM_STATUS_AWAY,
- EM_STATUS_IDLE,
- EM_STATUS_OFFLINE
-} em_status_t;
-
-static const StatusProviderStatus em_to_sp_map[] = {
- /* EM_STATUS_ONLINE, */ STATUS_PROVIDER_STATUS_ONLINE,
- /* EM_STATUS_INVISIBLE, */ STATUS_PROVIDER_STATUS_INVISIBLE,
- /* EM_STATUS_BUSY, */ STATUS_PROVIDER_STATUS_DND,
- /* EM_STATUS_AWAY, */ STATUS_PROVIDER_STATUS_AWAY,
- /* EM_STATUS_IDLE, */ STATUS_PROVIDER_STATUS_AWAY,
- /* EM_STATUS_OFFLINE, */ STATUS_PROVIDER_STATUS_OFFLINE
-};
-
-static const em_status_t sp_to_em_map[STATUS_PROVIDER_STATUS_LAST] = {
- /* STATUS_PROVIDER_STATUS_ONLINE, */ EM_STATUS_ONLINE,
- /* STATUS_PROVIDER_STATUS_AWAY, */ EM_STATUS_AWAY,
- /* STATUS_PROVIDER_STATUS_DND */ EM_STATUS_BUSY,
- /* STATUS_PROVIDER_STATUS_INVISIBLE*/ EM_STATUS_INVISIBLE,
- /* STATUS_PROVIDER_STATUS_OFFLINE */ EM_STATUS_OFFLINE,
- /* STATUS_PROVIDER_STATUS_DISCONNECTED*/ EM_STATUS_OFFLINE
-};
-
-typedef struct _StatusProviderEmesenePrivate StatusProviderEmesenePrivate;
-struct _StatusProviderEmesenePrivate {
- DBusGProxy * proxy;
- DBusGProxy * dbus_proxy;
- em_status_t em_status;
-};
-
-#define STATUS_PROVIDER_EMESENE_GET_PRIVATE(o) \
-(G_TYPE_INSTANCE_GET_PRIVATE ((o), STATUS_PROVIDER_EMESENE_TYPE, StatusProviderEmesenePrivate))
-
-/* Prototypes */
-/* GObject stuff */
-static void status_provider_emesene_class_init (StatusProviderEmeseneClass *klass);
-static void status_provider_emesene_init (StatusProviderEmesene *self);
-static void status_provider_emesene_dispose (GObject *object);
-static void status_provider_emesene_finalize (GObject *object);
-/* Internal Funcs */
-static void set_status (StatusProvider * sp, StatusProviderStatus status);
-static StatusProviderStatus get_status (StatusProvider * sp);
-static void setup_emesene_proxy (StatusProviderEmesene * self);
-static void dbus_namechange (DBusGProxy * proxy, const gchar * name, const gchar * prev, const gchar * new, StatusProviderEmesene * self);
-
-G_DEFINE_TYPE (StatusProviderEmesene, status_provider_emesene, STATUS_PROVIDER_TYPE);
-
-STATUS_PROVIDER_EXPORT_TYPE(STATUS_PROVIDER_EMESENE_TYPE)
-
-static void
-status_provider_emesene_class_init (StatusProviderEmeseneClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- g_type_class_add_private (klass, sizeof (StatusProviderEmesenePrivate));
-
- object_class->dispose = status_provider_emesene_dispose;
- object_class->finalize = status_provider_emesene_finalize;
-
- StatusProviderClass * spclass = STATUS_PROVIDER_CLASS(klass);
-
- spclass->set_status = set_status;
- spclass->get_status = get_status;
-
- return;
-}
-
-static void
-status_cb (DBusGProxy * proxy, DBusGProxyCall * call, gpointer userdata)
-{
- StatusProviderEmesene * spe = STATUS_PROVIDER_EMESENE(userdata);
- StatusProviderEmesenePrivate * priv = STATUS_PROVIDER_EMESENE_GET_PRIVATE(spe);
-
- GError * error = NULL;
- gint status = 0;
- if (!dbus_g_proxy_end_call(proxy, call, &error, G_TYPE_INT, &status, G_TYPE_INVALID)) {
- g_warning("Unable to get status from Emesene: %s", error->message);
- g_error_free(error);
- return;
- }
-
- priv->em_status = status;
- g_signal_emit(G_OBJECT(spe), STATUS_PROVIDER_SIGNAL_STATUS_CHANGED_ID, 0, em_to_sp_map[priv->em_status], TRUE);
- return;
-}
-
-static void
-changed_status (DBusGProxy * proxy, gint status, StatusProviderEmesene * spe)
-{
- StatusProviderEmesenePrivate * priv = STATUS_PROVIDER_EMESENE_GET_PRIVATE(spe);
- g_debug("Emesene changed status to %d", status);
- priv->em_status = status;
- g_signal_emit(G_OBJECT(spe), STATUS_PROVIDER_SIGNAL_STATUS_CHANGED_ID, 0, em_to_sp_map[priv->em_status], TRUE);
- return;
-}
-
-static void
-proxy_destroy (DBusGProxy * proxy, StatusProviderEmesene * spe)
-{
- StatusProviderEmesenePrivate * priv = STATUS_PROVIDER_EMESENE_GET_PRIVATE(spe);
-
- priv->proxy = NULL;
- priv->em_status = EM_STATUS_OFFLINE;
-
- g_signal_emit(G_OBJECT(spe), STATUS_PROVIDER_SIGNAL_STATUS_CHANGED_ID, 0, em_to_sp_map[priv->em_status], TRUE);
- return;
-}
-
-static void
-status_provider_emesene_init (StatusProviderEmesene *self)
-{
- StatusProviderEmesenePrivate * priv = STATUS_PROVIDER_EMESENE_GET_PRIVATE(self);
-
- priv->proxy = NULL;
- priv->em_status = EM_STATUS_OFFLINE;
-
- DBusGConnection * bus = dbus_g_bus_get(DBUS_BUS_SESSION, NULL);
- g_return_if_fail(bus != NULL); /* Can't do anymore DBus stuff without this,
- all non-DBus stuff should be done */
-
- GError * error = NULL;
-
- /* Set up the dbus Proxy */
- priv->dbus_proxy = dbus_g_proxy_new_for_name_owner (bus,
- DBUS_SERVICE_DBUS,
- DBUS_PATH_DBUS,
- DBUS_INTERFACE_DBUS,
- &error);
- if (error != NULL) {
- g_warning("Unable to connect to DBus events: %s", error->message);
- g_error_free(error);
- return;
- }
-
- /* Configure the name owner changing */
- dbus_g_proxy_add_signal(priv->dbus_proxy, "NameOwnerChanged",
- G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
- G_TYPE_INVALID);
- dbus_g_proxy_connect_signal(priv->dbus_proxy, "NameOwnerChanged",
- G_CALLBACK(dbus_namechange),
- self, NULL);
-
- setup_emesene_proxy(self);
-
- return;
-}
-
-/* Watch to see if the Emesene comes up on Dbus */
-static void
-dbus_namechange (DBusGProxy * proxy, const gchar * name, const gchar * prev, const gchar * new, StatusProviderEmesene * self)
-{
- g_return_if_fail(name != NULL);
- g_return_if_fail(new != NULL);
-
- if (g_strcmp0(name, "org.emesene.Service") == 0) {
- setup_emesene_proxy(self);
- }
- return;
-}
-
-/* Setup the Emesene proxy so that we can talk to it
- and get signals from it. */
-static void
-setup_emesene_proxy (StatusProviderEmesene * self)
-{
- StatusProviderEmesenePrivate * priv = STATUS_PROVIDER_EMESENE_GET_PRIVATE(self);
-
- if (priv->proxy != NULL) {
- g_debug("Doh!We were asked to set up a Emesene proxy when we already had one.");
- return;
- }
-
- DBusGConnection * bus = dbus_g_bus_get(DBUS_BUS_SESSION, NULL);
- g_return_if_fail(bus != NULL); /* Can't do anymore DBus stuff without this,
- all non-DBus stuff should be done */
-
- GError * error = NULL;
-
- /* Set up the Emesene Proxy */
- priv->proxy = dbus_g_proxy_new_for_name_owner (bus,
- "org.emesene.Service",
- "/org/emesene/Service",
- "org.emesene.Service",
- &error);
- /* Report any errors */
- if (error != NULL) {
- g_debug("Unable to get Emesene proxy: %s", error->message);
- g_error_free(error);
- }
-
- /* If we have a proxy, let's start using it */
- if (priv->proxy != NULL) {
- /* Set the proxy to NULL if it's destroyed */
- g_object_add_weak_pointer (G_OBJECT(priv->proxy), (gpointer *)&priv->proxy);
- /* If it's destroyed, let's clean up as well */
- g_signal_connect(G_OBJECT(priv->proxy), "destroy",
- G_CALLBACK(proxy_destroy), self);
-
- /* Watching for the status change coming from the
- Emesene side of things. */
- g_debug("Adding Emesene Signals");
- dbus_g_proxy_add_signal (priv->proxy,
- "status_changed",
- G_TYPE_INT,
- G_TYPE_INVALID);
- dbus_g_proxy_connect_signal(priv->proxy,
- "status_changed",
- G_CALLBACK(changed_status),
- (void *)self,
- NULL);
-
- /* Get the current status to update our cached
- value of the status. */
- dbus_g_proxy_begin_call(priv->proxy,
- "get_status",
- status_cb,
- self,
- NULL,
- G_TYPE_INVALID);
- }
-
- return;
-}
-
-static void
-status_provider_emesene_dispose (GObject *object)
-{
- StatusProviderEmesenePrivate * priv = STATUS_PROVIDER_EMESENE_GET_PRIVATE(object);
-
- if (priv->proxy != NULL) {
- g_object_unref(priv->proxy);
- priv->proxy = NULL;
- }
-
- G_OBJECT_CLASS (status_provider_emesene_parent_class)->dispose (object);
- return;
-}
-
-static void
-status_provider_emesene_finalize (GObject *object)
-{
-
- G_OBJECT_CLASS (status_provider_emesene_parent_class)->finalize (object);
- return;
-}
-
-/**
- status_provider_emesene_new:
-
- Creates a new #StatusProviderEmesene object. No parameters or anything
- like that. Just a convience function.
-
- Return value: A new instance of #StatusProviderEmesene
-*/
-StatusProvider *
-status_provider_emesene_new (void)
-{
- return STATUS_PROVIDER(g_object_new(STATUS_PROVIDER_EMESENE_TYPE, NULL));
-}
-
-/* Takes the status provided generically for Status providers
- and turns it into a Emesene status and sends it to Emesene. */
-static void
-set_status (StatusProvider * sp, StatusProviderStatus status)
-{
- g_return_if_fail(IS_STATUS_PROVIDER_EMESENE(sp));
- StatusProviderEmesenePrivate * priv = STATUS_PROVIDER_EMESENE_GET_PRIVATE(sp);
-
- g_debug("Emesene set status to %d", status);
- if (priv->proxy == NULL) {
- return;
- }
-
- priv->em_status = sp_to_em_map[status];
-
- gboolean ret = FALSE;
- GError * error = NULL;
-
- ret = dbus_g_proxy_call(priv->proxy,
- "set_status", &error,
- G_TYPE_INT, priv->em_status,
- G_TYPE_INVALID,
- G_TYPE_INVALID);
-
- if (!ret) {
- if (error != NULL) {
- g_warning("Emesene unable to change to status: %s", error->message);
- g_error_free(error);
- } else {
- g_warning("Emesene unable to change to status");
- }
- error = NULL;
- }
-
- g_signal_emit(G_OBJECT(sp), STATUS_PROVIDER_SIGNAL_STATUS_CHANGED_ID, 0, em_to_sp_map[priv->em_status], TRUE);
- return;
-}
-
-/* Takes the cached Emesene status and makes it into the generic
- Status provider status. If there is no Emesene proxy then it
- returns the disconnected state. */
-static StatusProviderStatus
-get_status (StatusProvider * sp)
-{
- g_return_val_if_fail(IS_STATUS_PROVIDER_EMESENE(sp), STATUS_PROVIDER_STATUS_DISCONNECTED);
- StatusProviderEmesenePrivate * priv = STATUS_PROVIDER_EMESENE_GET_PRIVATE(sp);
-
- if (priv->proxy == NULL) {
- return STATUS_PROVIDER_STATUS_DISCONNECTED;
- }
-
- return em_to_sp_map[priv->em_status];
-}
=== removed file 'src/status-provider-emesene.h'
--- src/status-provider-emesene.h 2011-06-22 20:42:44 +0000
+++ src/status-provider-emesene.h 1970-01-01 00:00:00 +0000
@@ -1,56 +0,0 @@
-/*
-A small wrapper utility to load indicators and put them as menu items
-into the gnome-panel using it's applet interface.
-
-Copyright 20011 Canonical Ltd.
-
-Authors:
- Stefano Candori <stefano.candori@xxxxxxxxx>
-
-This program is free software: you can redistribute it and/or modify it
-under the terms of the GNU General Public License version 3, as published
-by the Free Software Foundation.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranties of
-MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
-PURPOSE. See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along
-with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef __STATUS_PROVIDER_EMESENE_H__
-#define __STATUS_PROVIDER_EMESENE_H__
-
-#include <glib.h>
-#include <glib-object.h>
-
-#include "status-provider.h"
-
-G_BEGIN_DECLS
-
-#define STATUS_PROVIDER_EMESENE_TYPE (status_provider_emesene_get_type ())
-#define STATUS_PROVIDER_EMESENE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), STATUS_PROVIDER_EMESENE_TYPE, StatusProviderEmesene))
-#define STATUS_PROVIDER_EMESENE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), STATUS_PROVIDER_EMESENE_TYPE, StatusProviderEmeseneClass))
-#define IS_STATUS_PROVIDER_EMESENE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), STATUS_PROVIDER_EMESENE_TYPE))
-#define IS_STATUS_PROVIDER_EMESENE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), STATUS_PROVIDER_EMESENE_TYPE))
-#define STATUS_PROVIDER_EMESENE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), STATUS_PROVIDER_EMESENE_TYPE, StatusProviderEmeseneClass))
-
-
-typedef struct _StatusProviderEmeseneClass StatusProviderEmeseneClass;
-struct _StatusProviderEmeseneClass {
- StatusProviderClass parent_class;
-};
-
-typedef struct _StatusProviderEmesene StatusProviderEmesene;
-struct _StatusProviderEmesene {
- StatusProvider parent;
-};
-
-GType status_provider_emesene_get_type (void);
-StatusProvider * status_provider_emesene_new (void);
-
-G_END_DECLS
-
-#endif
=== removed file 'src/status-provider-mc5.c'
--- src/status-provider-mc5.c 2011-07-02 12:15:22 +0000
+++ src/status-provider-mc5.c 1970-01-01 00:00:00 +0000
@@ -1,308 +0,0 @@
-/*
-A small wrapper utility to load indicators and put them as menu items
-into the gnome-panel using it's applet interface.
-
-Copyright 2009 Canonical Ltd.
-
-Authors:
- Ted Gould <ted@xxxxxxxxxxxxx>
-
-This program is free software: you can redistribute it and/or modify it
-under the terms of the GNU General Public License version 3, as published
-by the Free Software Foundation.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranties of
-MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
-PURPOSE. See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along
-with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <telepathy-glib/account-manager.h>
-
-#include "status-provider.h"
-#include "status-provider-mc5.h"
-#include "status-provider-mc5-marshal.h"
-
-#include <dbus/dbus-glib.h>
-#include <dbus/dbus-glib-bindings.h>
-
-static gchar * sp_to_mc_map[STATUS_PROVIDER_STATUS_LAST] = {
- /* STATUS_PROVIDER_STATUS_ONLINE, */ "available",
- /* STATUS_PROVIDER_STATUS_AWAY, */ "away",
- /* STATUS_PROVIDER_STATUS_DND */ "busy",
- /* STATUS_PROVIDER_STATUS_INVISIBLE*/ "hidden",
- /* STATUS_PROVIDER_STATUS_OFFLINE */ "offline",
- /* STATUS_PROVIDER_STATUS_DISCONNECTED*/NULL
-};
-
-static TpConnectionPresenceType sp_to_tp_map[STATUS_PROVIDER_STATUS_LAST] = {
- /* STATUS_PROVIDER_STATUS_ONLINE, */ TP_CONNECTION_PRESENCE_TYPE_AVAILABLE,
- /* STATUS_PROVIDER_STATUS_AWAY, */ TP_CONNECTION_PRESENCE_TYPE_AWAY,
- /* STATUS_PROVIDER_STATUS_DND */ TP_CONNECTION_PRESENCE_TYPE_BUSY,
- /* STATUS_PROVIDER_STATUS_INVISIBLE*/ TP_CONNECTION_PRESENCE_TYPE_HIDDEN,
- /* STATUS_PROVIDER_STATUS_OFFLINE */ TP_CONNECTION_PRESENCE_TYPE_OFFLINE,
- /* STATUS_PROVIDER_STATUS_DISCONNECTED*/ TP_CONNECTION_PRESENCE_TYPE_UNSET
-};
-
-static StatusProviderStatus tp_to_sp_map[TP_CONNECTION_PRESENCE_TYPE_ERROR + 1] = {
- /* TP_CONNECTION_PRESENCE_TYPE_UNSET */ STATUS_PROVIDER_STATUS_DISCONNECTED,
- /* TP_CONNECTION_PRESENCE_TYPE_OFFLINE */ STATUS_PROVIDER_STATUS_OFFLINE,
- /* TP_CONNECTION_PRESENCE_TYPE_AVAILABLE */ STATUS_PROVIDER_STATUS_ONLINE,
- /* TP_CONNECTION_PRESENCE_TYPE_AWAY */ STATUS_PROVIDER_STATUS_AWAY,
- /* TP_CONNECTION_PRESENCE_TYPE_EXTENDED_AWAY */ STATUS_PROVIDER_STATUS_AWAY,
- /* TP_CONNECTION_PRESENCE_TYPE_HIDDEN */ STATUS_PROVIDER_STATUS_INVISIBLE,
- /* TP_CONNECTION_PRESENCE_TYPE_BUSY */ STATUS_PROVIDER_STATUS_DND,
- /* TP_CONNECTION_PRESENCE_TYPE_UNKNOWN */ STATUS_PROVIDER_STATUS_DISCONNECTED,
- /* TP_CONNECTION_PRESENCE_TYPE_ERROR */ STATUS_PROVIDER_STATUS_DISCONNECTED
-};
-
-typedef struct _StatusProviderMC5Private StatusProviderMC5Private;
-struct _StatusProviderMC5Private {
- TpAccountManager * manager;
- StatusProviderStatus status;
- DBusGProxy * dbus_proxy;
-};
-
-#define STATUS_PROVIDER_MC5_GET_PRIVATE(o) \
-(G_TYPE_INSTANCE_GET_PRIVATE ((o), STATUS_PROVIDER_MC5_TYPE, StatusProviderMC5Private))
-#define MC5_WELL_KNOWN_NAME "org.freedesktop.Telepathy.AccountManager"
-
-/* Prototypes */
-/* GObject stuff */
-static void status_provider_mc5_class_init (StatusProviderMC5Class *klass);
-static void status_provider_mc5_init (StatusProviderMC5 *self);
-static void status_provider_mc5_dispose (GObject *object);
-static void status_provider_mc5_finalize (GObject *object);
-/* Internal Funcs */
-static void set_status (StatusProvider * sp, StatusProviderStatus status);
-static StatusProviderStatus get_status (StatusProvider * sp);
-static void presence_changed (TpAccountManager * eam, guint type, const gchar * type_str, const gchar * message, StatusProviderMC5 * sp);
-static void dbus_namechange (DBusGProxy * proxy, const gchar * name, const gchar * prev, const gchar * new, StatusProviderMC5 * self);
-static void mc5_exists_cb (DBusGProxy * proxy, gboolean exists, GError * error, gpointer userdata);
-
-G_DEFINE_TYPE (StatusProviderMC5, status_provider_mc5, STATUS_PROVIDER_TYPE);
-
-STATUS_PROVIDER_EXPORT_TYPE(STATUS_PROVIDER_MC5_TYPE)
-
-/* Create the class. We over ride a few functions but nothing
- really shocking. Most interesting is the set and get status. */
-static void
-status_provider_mc5_class_init (StatusProviderMC5Class *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- g_type_class_add_private (klass, sizeof (StatusProviderMC5Private));
-
- object_class->dispose = status_provider_mc5_dispose;
- object_class->finalize = status_provider_mc5_finalize;
-
- StatusProviderClass * spclass = STATUS_PROVIDER_CLASS(klass);
-
- spclass->set_status = set_status;
- spclass->get_status = get_status;
-
- return;
-}
-
-/* Build our telepathy account manager instance if we don't
- have one. */
-static void
-build_eam (StatusProviderMC5 * self)
-{
- StatusProviderMC5Private * priv = STATUS_PROVIDER_MC5_GET_PRIVATE(self);
-
- if (priv->manager != NULL) {
- return;
- }
-
- priv->manager = tp_account_manager_dup();
- g_signal_connect(G_OBJECT(priv->manager), "most-available-presence-changed", G_CALLBACK(presence_changed), self);
-
- return;
-}
-
-/* Creating an instance of the status provider. We set the variables
- and create an TpAccountManager object. It does all the hard
- work in this module of tracking MissionControl and enumerating the
- accounts and all that jazz. */
-static void
-status_provider_mc5_init (StatusProviderMC5 *self)
-{
- StatusProviderMC5Private * priv = STATUS_PROVIDER_MC5_GET_PRIVATE(self);
-
- priv->status = STATUS_PROVIDER_STATUS_DISCONNECTED;
- priv->manager = NULL;
-
- DBusGConnection * bus = dbus_g_bus_get(DBUS_BUS_SESSION, NULL);
- g_return_if_fail(bus != NULL); /* Can't do anymore DBus stuff without this,
- all non-DBus stuff should be done */
-
- GError * error = NULL;
-
- /* Set up the dbus Proxy */
- priv->dbus_proxy = dbus_g_proxy_new_for_name_owner (bus,
- DBUS_SERVICE_DBUS,
- DBUS_PATH_DBUS,
- DBUS_INTERFACE_DBUS,
- &error);
- if (error != NULL) {
- g_warning("Unable to connect to DBus events: %s", error->message);
- g_error_free(error);
- return;
- }
-
- /* Configure the name owner changing */
- dbus_g_proxy_add_signal(priv->dbus_proxy, "NameOwnerChanged",
- G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
- G_TYPE_INVALID);
- dbus_g_proxy_connect_signal(priv->dbus_proxy, "NameOwnerChanged",
- G_CALLBACK(dbus_namechange),
- self, NULL);
-
- org_freedesktop_DBus_name_has_owner_async(priv->dbus_proxy, MC5_WELL_KNOWN_NAME, mc5_exists_cb, self);
-
- return;
-}
-
-/* Unref the account manager and move on. Sadly, we're
- leaving the show. */
-static void
-status_provider_mc5_dispose (GObject *object)
-{
- StatusProviderMC5Private * priv = STATUS_PROVIDER_MC5_GET_PRIVATE(object);
-
- if (priv->manager != NULL) {
- g_object_unref(priv->manager);
- priv->manager = NULL;
- }
-
- if (priv->dbus_proxy != NULL) {
- g_object_unref(priv->dbus_proxy);
- priv->dbus_proxy = NULL;
- }
-
- G_OBJECT_CLASS (status_provider_mc5_parent_class)->dispose (object);
- return;
-}
-
-/* Pass to superclass */
-static void
-status_provider_mc5_finalize (GObject *object)
-{
-
- G_OBJECT_CLASS (status_provider_mc5_parent_class)->finalize (object);
- return;
-}
-
-/* Watch for MC5 Coming on and off the bus. */
-static void
-dbus_namechange (DBusGProxy * proxy, const gchar * name, const gchar * prev, const gchar * new, StatusProviderMC5 * self)
-{
- /* g_debug("DBUS NAMECHANGE: %s %s %s", name, prev, new); */
-
- if (prev[0] == '\0' && g_strcmp0(name, MC5_WELL_KNOWN_NAME) == 0) {
- g_debug("MC5 Coming online");
- build_eam(self);
- }
- if (new[0] == '\0' && g_strcmp0(name, MC5_WELL_KNOWN_NAME) == 0) {
- g_debug("MC5 going offline");
- StatusProviderMC5Private * priv = STATUS_PROVIDER_MC5_GET_PRIVATE(self);
- if (priv->manager != NULL) {
- g_object_unref(priv->manager);
- priv->manager = NULL;
- }
-
- priv->status = STATUS_PROVIDER_STATUS_DISCONNECTED;
- g_signal_emit(G_OBJECT(self), STATUS_PROVIDER_SIGNAL_STATUS_CHANGED_ID, 0, priv->status, TRUE);
- }
-
- return;
-}
-
-/* Callback for the Dbus command to do HasOwner on
- the MC5 service. If it exists, we want to have an
- account manager. */
-static void
-mc5_exists_cb (DBusGProxy * proxy, gboolean exists, GError * error, gpointer userdata)
-{
- if (error) {
- g_warning("Unable to check if MC5 is running: %s", error->message);
- return;
- }
-
- if (exists) {
- build_eam(STATUS_PROVIDER_MC5(userdata));
- }
-
- return;
-}
-
-/**
- status_provider_mc5_new:
-
- Creates a new #StatusProviderMC5 object. No parameters or anything
- like that. Just a convience function.
-
- Return value: A new instance of #StatusProviderMC5
-*/
-StatusProvider *
-status_provider_mc5_new (void)
-{
- return STATUS_PROVIDER(g_object_new(STATUS_PROVIDER_MC5_TYPE, NULL));
-}
-
-/* Setting the status in the empathy account manager. We're
- basically requesting a global status. This may or may not
- get applied to all accounts. It's really the best we can
- hope to do. */
-static void
-set_status (StatusProvider * sp, StatusProviderStatus status)
-{
- StatusProviderMC5Private * priv = STATUS_PROVIDER_MC5_GET_PRIVATE(sp);
-
- build_eam(STATUS_PROVIDER_MC5(sp));
- tp_account_manager_set_all_requested_presences(priv->manager, sp_to_tp_map[status], sp_to_mc_map[status], "");
-
- return;
-}
-
-/* Gets the status, uses the cached value that we have. Asking
- would just be painful. */
-static StatusProviderStatus
-get_status (StatusProvider * sp)
-{
- g_return_val_if_fail(IS_STATUS_PROVIDER_MC5(sp), STATUS_PROVIDER_STATUS_DISCONNECTED);
- StatusProviderMC5Private * priv = STATUS_PROVIDER_MC5_GET_PRIVATE(sp);
-
- if (priv->manager == NULL) {
- return STATUS_PROVIDER_STATUS_DISCONNECTED;
- }
-
- return priv->status;
-}
-
-/* A signal handler for when the TpAccountManager believes
- that the global status has changed. It roughly calculates this
- by finding the most available of all accounts that are active. */
-static void
-presence_changed (TpAccountManager * eam, guint type, const gchar * type_str, const gchar * message, StatusProviderMC5 * sp)
-{
- StatusProviderMC5Private * priv = STATUS_PROVIDER_MC5_GET_PRIVATE(sp);
-
- g_debug("MC5 Status changed: %d %s %s", type, type_str, message);
-
- if (priv->status != tp_to_sp_map[type]) {
- priv->status = tp_to_sp_map[type];
- g_signal_emit(G_OBJECT(sp), STATUS_PROVIDER_SIGNAL_STATUS_CHANGED_ID, 0, priv->status, TRUE);
- }
-
- return;
-}
-
=== removed file 'src/status-provider-mc5.h'
--- src/status-provider-mc5.h 2011-06-22 20:42:44 +0000
+++ src/status-provider-mc5.h 1970-01-01 00:00:00 +0000
@@ -1,56 +0,0 @@
-/*
-A small wrapper utility to load indicators and put them as menu items
-into the gnome-panel using it's applet interface.
-
-Copyright 2009 Canonical Ltd.
-
-Authors:
- Ted Gould <ted@xxxxxxxxxxxxx>
-
-This program is free software: you can redistribute it and/or modify it
-under the terms of the GNU General Public License version 3, as published
-by the Free Software Foundation.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranties of
-MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
-PURPOSE. See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along
-with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef __STATUS_PROVIDER_MC5_H__
-#define __STATUS_PROVIDER_MC5_H__
-
-#include <glib.h>
-#include <glib-object.h>
-
-#include "status-provider.h"
-
-G_BEGIN_DECLS
-
-#define STATUS_PROVIDER_MC5_TYPE (status_provider_mc5_get_type ())
-#define STATUS_PROVIDER_MC5(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), STATUS_PROVIDER_MC5_TYPE, StatusProviderMC5))
-#define STATUS_PROVIDER_MC5_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), STATUS_PROVIDER_MC5_TYPE, StatusProviderMC5Class))
-#define IS_STATUS_PROVIDER_MC5(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), STATUS_PROVIDER_MC5_TYPE))
-#define IS_STATUS_PROVIDER_MC5_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), STATUS_PROVIDER_MC5_TYPE))
-#define STATUS_PROVIDER_MC5_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), STATUS_PROVIDER_MC5_TYPE, StatusProviderMC5Class))
-
-
-typedef struct _StatusProviderMC5Class StatusProviderMC5Class;
-struct _StatusProviderMC5Class {
- StatusProviderClass parent_class;
-};
-
-typedef struct _StatusProviderMC5 StatusProviderMC5;
-struct _StatusProviderMC5 {
- StatusProvider parent;
-};
-
-GType status_provider_mc5_get_type (void);
-StatusProvider * status_provider_mc5_new (void);
-
-G_END_DECLS
-
-#endif
=== removed file 'src/status-provider-mc5.list'
--- src/status-provider-mc5.list 2011-06-22 20:42:44 +0000
+++ src/status-provider-mc5.list 1970-01-01 00:00:00 +0000
@@ -1,1 +0,0 @@
-VOID:UINT,STRING
=== removed file 'src/status-provider-pidgin.c'
--- src/status-provider-pidgin.c 2011-07-02 12:15:22 +0000
+++ src/status-provider-pidgin.c 1970-01-01 00:00:00 +0000
@@ -1,433 +0,0 @@
-/*
-A small wrapper utility to load indicators and put them as menu items
-into the gnome-panel using it's applet interface.
-
-Copyright 2009 Canonical Ltd.
-
-Authors:
- Ted Gould <ted@xxxxxxxxxxxxx>
-
-This program is free software: you can redistribute it and/or modify it
-under the terms of the GNU General Public License version 3, as published
-by the Free Software Foundation.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranties of
-MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
-PURPOSE. See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along
-with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "status-provider.h"
-#include "status-provider-pidgin.h"
-#include "status-provider-pidgin-marshal.h"
-
-#include <dbus/dbus-glib.h>
-
-typedef enum {
- PG_STATUS_UNKNOWN,
- PG_STATUS_OFFLINE,
- PG_STATUS_AVAILABLE,
- PG_STATUS_UNAVAILABLE,
- PG_STATUS_INVISIBLE,
- PG_STATUS_AWAY,
- PG_STATUS_EXTENDEND_AWAY,
- PG_STATUS_MOBILE,
- PG_STATUS_TUNE
-} pg_status_t;
-
-static const StatusProviderStatus pg_to_sp_map[] = {
- /* PG_STATUS_UNKNOWN, */ STATUS_PROVIDER_STATUS_OFFLINE,
- /* PG_STATUS_OFFLINE, */ STATUS_PROVIDER_STATUS_OFFLINE,
- /* PG_STATUS_AVAILABLE, */ STATUS_PROVIDER_STATUS_ONLINE,
- /* PG_STATUS_UNAVAILABLE, */ STATUS_PROVIDER_STATUS_DND,
- /* PG_STATUS_INVISIBLE, */ STATUS_PROVIDER_STATUS_INVISIBLE,
- /* PG_STATUS_AWAY, */ STATUS_PROVIDER_STATUS_AWAY,
- /* PG_STATUS_EXTENDEND_AWAY, */ STATUS_PROVIDER_STATUS_AWAY,
- /* PG_STATUS_MOBILE, */ STATUS_PROVIDER_STATUS_OFFLINE,
- /* PG_STATUS_TUNE */ STATUS_PROVIDER_STATUS_OFFLINE
-};
-
-static const pg_status_t sp_to_pg_map[STATUS_PROVIDER_STATUS_LAST] = {
- /* STATUS_PROVIDER_STATUS_ONLINE, */ PG_STATUS_AVAILABLE,
- /* STATUS_PROVIDER_STATUS_AWAY, */ PG_STATUS_AWAY,
- /* STATUS_PROVIDER_STATUS_DND */ PG_STATUS_UNAVAILABLE,
- /* STATUS_PROVIDER_STATUS_INVISIBLE*/ PG_STATUS_INVISIBLE,
- /* STATUS_PROVIDER_STATUS_OFFLINE */ PG_STATUS_OFFLINE,
- /* STATUS_PROVIDER_STATUS_DISCONNECTED*/ PG_STATUS_OFFLINE
-};
-
-typedef struct _StatusProviderPidginPrivate StatusProviderPidginPrivate;
-struct _StatusProviderPidginPrivate {
- DBusGProxy * proxy;
- DBusGProxy * dbus_proxy;
- pg_status_t pg_status;
-};
-
-#define STATUS_PROVIDER_PIDGIN_GET_PRIVATE(o) \
-(G_TYPE_INSTANCE_GET_PRIVATE ((o), STATUS_PROVIDER_PIDGIN_TYPE, StatusProviderPidginPrivate))
-
-/* Prototypes */
-/* GObject stuff */
-static void status_provider_pidgin_class_init (StatusProviderPidginClass *klass);
-static void status_provider_pidgin_init (StatusProviderPidgin *self);
-static void status_provider_pidgin_dispose (GObject *object);
-static void status_provider_pidgin_finalize (GObject *object);
-/* Internal Funcs */
-static void set_status (StatusProvider * sp, StatusProviderStatus status);
-static StatusProviderStatus get_status (StatusProvider * sp);
-static void setup_pidgin_proxy (StatusProviderPidgin * self);
-static void dbus_namechange (DBusGProxy * proxy, const gchar * name, const gchar * prev, const gchar * new, StatusProviderPidgin * self);
-
-G_DEFINE_TYPE (StatusProviderPidgin, status_provider_pidgin, STATUS_PROVIDER_TYPE);
-
-STATUS_PROVIDER_EXPORT_TYPE(STATUS_PROVIDER_PIDGIN_TYPE)
-
-static void
-status_provider_pidgin_class_init (StatusProviderPidginClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- g_type_class_add_private (klass, sizeof (StatusProviderPidginPrivate));
-
- object_class->dispose = status_provider_pidgin_dispose;
- object_class->finalize = status_provider_pidgin_finalize;
-
- StatusProviderClass * spclass = STATUS_PROVIDER_CLASS(klass);
-
- spclass->set_status = set_status;
- spclass->get_status = get_status;
-
- return;
-}
-
-static void
-type_cb (DBusGProxy * proxy, DBusGProxyCall * call, gpointer userdata)
-{
- GError * error = NULL;
- gint status = 0;
- if (!dbus_g_proxy_end_call(proxy, call, &error, G_TYPE_INT, &status, G_TYPE_INVALID)) {
- g_warning("Unable to get type from Pidgin: %s", error->message);
- g_error_free(error);
- return;
- }
-
- StatusProviderPidginPrivate * priv = STATUS_PROVIDER_PIDGIN_GET_PRIVATE(userdata);
- if (status != priv->pg_status) {
- priv->pg_status = status;
-
- g_signal_emit(G_OBJECT(userdata), STATUS_PROVIDER_SIGNAL_STATUS_CHANGED_ID, 0, pg_to_sp_map[priv->pg_status], TRUE);
- }
-
- return;
-}
-
-static void
-saved_status_to_type (StatusProviderPidgin * spp, gint savedstatus)
-{
- StatusProviderPidginPrivate * priv = STATUS_PROVIDER_PIDGIN_GET_PRIVATE(spp);
-
- g_debug("Pidgin figuring out type for %d", savedstatus);
- dbus_g_proxy_begin_call(priv->proxy,
- "PurpleSavedstatusGetType", type_cb, spp, NULL,
- G_TYPE_INT, savedstatus, G_TYPE_INVALID);
-
- return;
-}
-
-static void
-savedstatus_cb (DBusGProxy * proxy, DBusGProxyCall * call, gpointer userdata)
-{
- GError * error = NULL;
- gint status = 0;
- if (!dbus_g_proxy_end_call(proxy, call, &error, G_TYPE_INT, &status, G_TYPE_INVALID)) {
- g_warning("Unable to get saved status from Pidgin: %s", error->message);
- g_error_free(error);
- return;
- }
-
- saved_status_to_type(STATUS_PROVIDER_PIDGIN(userdata), status);
- return;
-}
-
-
-static void
-changed_status (DBusGProxy * proxy, gint savedstatus, GError ** error, StatusProviderPidgin * spp)
-{
- saved_status_to_type(spp, savedstatus);
- return;
-}
-
-static void
-proxy_destroy (DBusGProxy * proxy, StatusProviderPidgin * spp)
-{
- StatusProviderPidginPrivate * priv = STATUS_PROVIDER_PIDGIN_GET_PRIVATE(spp);
-
- priv->proxy = NULL;
- priv->pg_status = PG_STATUS_OFFLINE;
-
- g_signal_emit(G_OBJECT(spp), STATUS_PROVIDER_SIGNAL_STATUS_CHANGED_ID, 0, pg_to_sp_map[priv->pg_status], TRUE);
- return;
-}
-
-static void
-status_provider_pidgin_init (StatusProviderPidgin *self)
-{
- StatusProviderPidginPrivate * priv = STATUS_PROVIDER_PIDGIN_GET_PRIVATE(self);
-
- priv->proxy = NULL;
- priv->pg_status = PG_STATUS_OFFLINE;
-
- DBusGConnection * bus = dbus_g_bus_get(DBUS_BUS_SESSION, NULL);
- g_return_if_fail(bus != NULL); /* Can't do anymore DBus stuff without this,
- all non-DBus stuff should be done */
-
- GError * error = NULL;
-
- /* Set up the dbus Proxy */
- priv->dbus_proxy = dbus_g_proxy_new_for_name_owner (bus,
- DBUS_SERVICE_DBUS,
- DBUS_PATH_DBUS,
- DBUS_INTERFACE_DBUS,
- &error);
- if (error != NULL) {
- g_warning("Unable to connect to DBus events: %s", error->message);
- g_error_free(error);
- return;
- }
-
- /* Configure the name owner changing */
- dbus_g_proxy_add_signal(priv->dbus_proxy, "NameOwnerChanged",
- G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
- G_TYPE_INVALID);
- dbus_g_proxy_connect_signal(priv->dbus_proxy, "NameOwnerChanged",
- G_CALLBACK(dbus_namechange),
- self, NULL);
-
- setup_pidgin_proxy(self);
-
- return;
-}
-
-/* Watch to see if the Pidgin comes up on Dbus */
-static void
-dbus_namechange (DBusGProxy * proxy, const gchar * name, const gchar * prev, const gchar * new, StatusProviderPidgin * self)
-{
- g_return_if_fail(name != NULL);
- g_return_if_fail(new != NULL);
-
- if (g_strcmp0(name, "im.pidgin.purple.PurpleService") == 0) {
- setup_pidgin_proxy(self);
- }
- return;
-}
-
-/* Setup the Pidgin proxy so that we can talk to it
- and get signals from it. */
-static void
-setup_pidgin_proxy (StatusProviderPidgin * self)
-{
- StatusProviderPidginPrivate * priv = STATUS_PROVIDER_PIDGIN_GET_PRIVATE(self);
-
- if (priv->proxy != NULL) {
- g_debug("Odd, we were asked to set up a Pidgin proxy when we already had one.");
- return;
- }
-
- DBusGConnection * bus = dbus_g_bus_get(DBUS_BUS_SESSION, NULL);
- g_return_if_fail(bus != NULL); /* Can't do anymore DBus stuff without this,
- all non-DBus stuff should be done */
-
- GError * error = NULL;
-
- /* Set up the Pidgin Proxy */
- priv->proxy = dbus_g_proxy_new_for_name_owner (bus,
- "im.pidgin.purple.PurpleService",
- "/im/pidgin/purple/PurpleObject",
- "im.pidgin.purple.PurpleInterface",
- &error);
- /* Report any errors */
- if (error != NULL) {
- g_debug("Unable to get Pidgin proxy: %s", error->message);
- g_error_free(error);
- }
-
- /* If we have a proxy, let's start using it */
- if (priv->proxy != NULL) {
- /* Set the proxy to NULL if it's destroyed */
- g_object_add_weak_pointer (G_OBJECT(priv->proxy), (gpointer *)&priv->proxy);
- /* If it's destroyed, let's clean up as well */
- g_signal_connect(G_OBJECT(priv->proxy), "destroy",
- G_CALLBACK(proxy_destroy), self);
-
- /* Watching for the status change coming from the
- Pidgin side of things. */
- g_debug("Adding Pidgin Signals");
- dbus_g_object_register_marshaller(_status_provider_pidgin_marshal_VOID__INT_INT,
- G_TYPE_NONE,
- G_TYPE_INT,
- G_TYPE_INT,
- G_TYPE_INVALID);
- dbus_g_proxy_add_signal (priv->proxy,
- "SavedstatusChanged",
- G_TYPE_INT,
- G_TYPE_INT,
- G_TYPE_INVALID);
- dbus_g_proxy_connect_signal(priv->proxy,
- "SavedstatusChanged",
- G_CALLBACK(changed_status),
- (void *)self,
- NULL);
-
- /* Get the current status to update our cached
- value of the status. */
- dbus_g_proxy_begin_call(priv->proxy,
- "PurpleSavedstatusGetCurrent",
- savedstatus_cb,
- self,
- NULL,
- G_TYPE_INVALID);
- }
-
- return;
-}
-
-static void
-status_provider_pidgin_dispose (GObject *object)
-{
- StatusProviderPidginPrivate * priv = STATUS_PROVIDER_PIDGIN_GET_PRIVATE(object);
-
- if (priv->proxy != NULL) {
- g_object_unref(priv->proxy);
- priv->proxy = NULL;
- }
-
- G_OBJECT_CLASS (status_provider_pidgin_parent_class)->dispose (object);
- return;
-}
-
-static void
-status_provider_pidgin_finalize (GObject *object)
-{
-
- G_OBJECT_CLASS (status_provider_pidgin_parent_class)->finalize (object);
- return;
-}
-
-/**
- status_provider_pidgin_new:
-
- Creates a new #StatusProviderPidgin object. No parameters or anything
- like that. Just a convience function.
-
- Return value: A new instance of #StatusProviderPidgin
-*/
-StatusProvider *
-status_provider_pidgin_new (void)
-{
- return STATUS_PROVIDER(g_object_new(STATUS_PROVIDER_PIDGIN_TYPE, NULL));
-}
-
-/* Takes the status provided generically for Status providers
- and turns it into a Pidgin status and sends it to Pidgin. */
-static void
-set_status (StatusProvider * sp, StatusProviderStatus status)
-{
- gchar * message = "";
-
- g_return_if_fail(IS_STATUS_PROVIDER_PIDGIN(sp));
- StatusProviderPidginPrivate * priv = STATUS_PROVIDER_PIDGIN_GET_PRIVATE(sp);
-
- g_debug("\tPidgin set status to %d", status);
- if (priv->proxy == NULL) {
- return;
- }
-
- priv->pg_status = sp_to_pg_map[status];
- gint status_val = 0;
- gboolean ret = FALSE;
- GError * error = NULL;
-
- ret = dbus_g_proxy_call(priv->proxy,
- "PurpleSavedstatusFindTransientByTypeAndMessage", &error,
- G_TYPE_INT, priv->pg_status,
- G_TYPE_STRING, message,
- G_TYPE_INVALID,
- G_TYPE_INT, &status_val,
- G_TYPE_INVALID);
-
- if (!ret) {
- if (error != NULL) {
- g_error_free(error);
- }
- error = NULL;
- status_val = 0;
- g_debug("No Pidgin saved status to apply");
- }
-
- if (status_val == 0) {
- ret = dbus_g_proxy_call(priv->proxy,
- "PurpleSavedstatusNew", &error,
- G_TYPE_STRING, message,
- G_TYPE_INT, priv->pg_status,
- G_TYPE_INVALID,
- G_TYPE_INT, &status_val,
- G_TYPE_INVALID);
-
- if (!ret) {
- status_val = 0;
- if (error != NULL) {
- g_warning("Unable to create Pidgin status for %d: %s", status, error->message);
- g_error_free(error);
- } else {
- g_warning("Unable to create Pidgin status for %d", status);
- }
- error = NULL;
- }
- }
-
- if (status_val == 0) {
- return;
- }
-
- ret = dbus_g_proxy_call(priv->proxy,
- "PurpleSavedstatusActivate", &error,
- G_TYPE_INT, status_val,
- G_TYPE_INVALID,
- G_TYPE_INVALID);
-
- if (!ret) {
- if (error != NULL) {
- g_warning("Pidgin unable to change to status: %s", error->message);
- g_error_free(error);
- } else {
- g_warning("Pidgin unable to change to status");
- }
- error = NULL;
- }
-
- g_signal_emit(G_OBJECT(sp), STATUS_PROVIDER_SIGNAL_STATUS_CHANGED_ID, 0, pg_to_sp_map[priv->pg_status], TRUE);
- return;
-}
-
-/* Takes the cached Pidgin status and makes it into the generic
- Status provider status. If there is no Pidgin proxy then it
- returns the disconnected state. */
-static StatusProviderStatus
-get_status (StatusProvider * sp)
-{
- g_return_val_if_fail(IS_STATUS_PROVIDER_PIDGIN(sp), STATUS_PROVIDER_STATUS_DISCONNECTED);
- StatusProviderPidginPrivate * priv = STATUS_PROVIDER_PIDGIN_GET_PRIVATE(sp);
-
- if (priv->proxy == NULL) {
- return STATUS_PROVIDER_STATUS_DISCONNECTED;
- }
-
- return pg_to_sp_map[priv->pg_status];
-}
=== removed file 'src/status-provider-pidgin.h'
--- src/status-provider-pidgin.h 2011-06-22 20:42:44 +0000
+++ src/status-provider-pidgin.h 1970-01-01 00:00:00 +0000
@@ -1,56 +0,0 @@
-/*
-A small wrapper utility to load indicators and put them as menu items
-into the gnome-panel using it's applet interface.
-
-Copyright 2009 Canonical Ltd.
-
-Authors:
- Ted Gould <ted@xxxxxxxxxxxxx>
-
-This program is free software: you can redistribute it and/or modify it
-under the terms of the GNU General Public License version 3, as published
-by the Free Software Foundation.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranties of
-MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
-PURPOSE. See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along
-with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef __STATUS_PROVIDER_PIDGIN_H__
-#define __STATUS_PROVIDER_PIDGIN_H__
-
-#include <glib.h>
-#include <glib-object.h>
-
-#include "status-provider.h"
-
-G_BEGIN_DECLS
-
-#define STATUS_PROVIDER_PIDGIN_TYPE (status_provider_pidgin_get_type ())
-#define STATUS_PROVIDER_PIDGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), STATUS_PROVIDER_PIDGIN_TYPE, StatusProviderPidgin))
-#define STATUS_PROVIDER_PIDGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), STATUS_PROVIDER_PIDGIN_TYPE, StatusProviderPidginClass))
-#define IS_STATUS_PROVIDER_PIDGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), STATUS_PROVIDER_PIDGIN_TYPE))
-#define IS_STATUS_PROVIDER_PIDGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), STATUS_PROVIDER_PIDGIN_TYPE))
-#define STATUS_PROVIDER_PIDGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), STATUS_PROVIDER_PIDGIN_TYPE, StatusProviderPidginClass))
-
-
-typedef struct _StatusProviderPidginClass StatusProviderPidginClass;
-struct _StatusProviderPidginClass {
- StatusProviderClass parent_class;
-};
-
-typedef struct _StatusProviderPidgin StatusProviderPidgin;
-struct _StatusProviderPidgin {
- StatusProvider parent;
-};
-
-GType status_provider_pidgin_get_type (void);
-StatusProvider * status_provider_pidgin_new (void);
-
-G_END_DECLS
-
-#endif
=== removed file 'src/status-provider-pidgin.list'
--- src/status-provider-pidgin.list 2011-06-22 20:42:44 +0000
+++ src/status-provider-pidgin.list 1970-01-01 00:00:00 +0000
@@ -1,1 +0,0 @@
-VOID:INT,INT
=== removed file 'src/status-provider-telepathy.c'
--- src/status-provider-telepathy.c 2011-07-02 12:15:22 +0000
+++ src/status-provider-telepathy.c 1970-01-01 00:00:00 +0000
@@ -1,385 +0,0 @@
-/*
-A small wrapper utility to load indicators and put them as menu items
-into the gnome-panel using it's applet interface.
-
-Copyright 2009 Canonical Ltd.
-
-Authors:
- Ted Gould <ted@xxxxxxxxxxxxx>
-
-This program is free software: you can redistribute it and/or modify it
-under the terms of the GNU General Public License version 3, as published
-by the Free Software Foundation.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranties of
-MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
-PURPOSE. See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along
-with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "status-provider.h"
-#include "status-provider-telepathy.h"
-#include "status-provider-telepathy-marshal.h"
-
-#include <dbus/dbus-glib.h>
-
-typedef enum {
- MC_STATUS_UNSET,
- MC_STATUS_OFFLINE,
- MC_STATUS_AVAILABLE,
- MC_STATUS_AWAY,
- MC_STATUS_EXTENDED_AWAY,
- MC_STATUS_HIDDEN,
- MC_STATUS_DND
-} mc_status_t;
-
-static StatusProviderStatus mc_to_sp_map[] = {
- /* MC_STATUS_UNSET, */ STATUS_PROVIDER_STATUS_OFFLINE,
- /* MC_STATUS_OFFLINE, */ STATUS_PROVIDER_STATUS_OFFLINE,
- /* MC_STATUS_AVAILABLE, */ STATUS_PROVIDER_STATUS_ONLINE,
- /* MC_STATUS_AWAY, */ STATUS_PROVIDER_STATUS_AWAY,
- /* MC_STATUS_EXTENDED_AWAY, */ STATUS_PROVIDER_STATUS_AWAY,
- /* MC_STATUS_HIDDEN, */ STATUS_PROVIDER_STATUS_INVISIBLE,
- /* MC_STATUS_DND */ STATUS_PROVIDER_STATUS_DND
-};
-
-static mc_status_t sp_to_mc_map[] = {
- /* STATUS_PROVIDER_STATUS_ONLINE, */ MC_STATUS_AVAILABLE,
- /* STATUS_PROVIDER_STATUS_AWAY, */ MC_STATUS_AWAY,
- /* STATUS_PROVIDER_STATUS_DND */ MC_STATUS_DND,
- /* STATUS_PROVIDER_STATUS_INVISIBLE*/ MC_STATUS_HIDDEN,
- /* STATUS_PROVIDER_STATUS_OFFLINE */ MC_STATUS_OFFLINE,
- /* STATUS_PROVIDER_STATUS_DISCONNECTED*/MC_STATUS_OFFLINE
-};
-
-typedef struct _StatusProviderTelepathyPrivate StatusProviderTelepathyPrivate;
-struct _StatusProviderTelepathyPrivate {
- DBusGProxy * proxy;
- DBusGProxy * dbus_proxy;
- mc_status_t mc_status;
-};
-
-#define STATUS_PROVIDER_TELEPATHY_GET_PRIVATE(o) \
-(G_TYPE_INSTANCE_GET_PRIVATE ((o), STATUS_PROVIDER_TELEPATHY_TYPE, StatusProviderTelepathyPrivate))
-
-/* Prototypes */
-/* GObject stuff */
-static void status_provider_telepathy_class_init (StatusProviderTelepathyClass *klass);
-static void status_provider_telepathy_init (StatusProviderTelepathy *self);
-static void status_provider_telepathy_dispose (GObject *object);
-static void status_provider_telepathy_finalize (GObject *object);
-/* Internal Funcs */
-static void build_telepathy_proxy (StatusProviderTelepathy * self);
-static void dbus_namechange (DBusGProxy * proxy, const gchar * name, const gchar * prev, const gchar * new, StatusProviderTelepathy * self);
-static void set_status (StatusProvider * sp, StatusProviderStatus status);
-static StatusProviderStatus get_status (StatusProvider * sp);
-static void changed_status (DBusGProxy * proxy, guint status, gchar * message, StatusProvider * sp);
-static void proxy_destroy (DBusGProxy * proxy, StatusProvider * sp);
-static void get_status_async (DBusGProxy * proxy, DBusGProxyCall * call, gpointer userdata);
-
-G_DEFINE_TYPE (StatusProviderTelepathy, status_provider_telepathy, STATUS_PROVIDER_TYPE);
-
-STATUS_PROVIDER_EXPORT_TYPE(STATUS_PROVIDER_TELEPATHY_TYPE)
-
-static void
-status_provider_telepathy_class_init (StatusProviderTelepathyClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- g_type_class_add_private (klass, sizeof (StatusProviderTelepathyPrivate));
-
- object_class->dispose = status_provider_telepathy_dispose;
- object_class->finalize = status_provider_telepathy_finalize;
-
- StatusProviderClass * spclass = STATUS_PROVIDER_CLASS(klass);
-
- spclass->set_status = set_status;
- spclass->get_status = get_status;
-
- return;
-}
-
-
-static void
-status_provider_telepathy_init (StatusProviderTelepathy *self)
-{
- StatusProviderTelepathyPrivate * priv = STATUS_PROVIDER_TELEPATHY_GET_PRIVATE(self);
-
- priv->proxy = NULL;
- priv->dbus_proxy = NULL;
- priv->mc_status = MC_STATUS_OFFLINE;
-
- GError * error = NULL;
-
- /* Grabbing the session bus */
- DBusGConnection * bus = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
- if (bus == NULL) {
- g_warning("Unable to connect to Session Bus: %s", error == NULL ? "No message" : error->message);
- g_error_free(error);
- return;
- }
-
- /* Set up the dbus Proxy */
- priv->dbus_proxy = dbus_g_proxy_new_for_name_owner (bus,
- DBUS_SERVICE_DBUS,
- DBUS_PATH_DBUS,
- DBUS_INTERFACE_DBUS,
- &error);
- if (error != NULL) {
- g_warning("Unable to connect to DBus events: %s", error->message);
- g_error_free(error);
- return;
- }
-
- /* Configure the name owner changing */
- dbus_g_proxy_add_signal(priv->dbus_proxy, "NameOwnerChanged",
- G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
- G_TYPE_INVALID);
- dbus_g_proxy_connect_signal(priv->dbus_proxy, "NameOwnerChanged",
- G_CALLBACK(dbus_namechange),
- self, NULL);
-
- build_telepathy_proxy(self);
-
- return;
-}
-
-/* Builds up the proxy to Mission Control and configures all of the
- signals for getting info from the proxy. Also does a call to get
- the inital value of the status. */
-static void
-build_telepathy_proxy (StatusProviderTelepathy * self)
-{
- g_debug("Building Telepathy Proxy");
- StatusProviderTelepathyPrivate * priv = STATUS_PROVIDER_TELEPATHY_GET_PRIVATE(self);
-
- if (priv->proxy != NULL) {
- g_debug("Hmm, being asked to build a proxy we alredy have.");
- return;
- }
-
- GError * error = NULL;
-
- /* Grabbing the session bus */
- DBusGConnection * session_bus = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
- if (session_bus == NULL) {
- g_warning("Unable to connect to Session Bus: %s", error == NULL ? "No message" : error->message);
- g_error_free(error);
- return;
- }
-
- /* Get the proxy to Mission Control */
- priv->proxy = dbus_g_proxy_new_for_name_owner(session_bus,
- "org.freedesktop.Telepathy.MissionControl",
- "/org/freedesktop/Telepathy/MissionControl",
- "org.freedesktop.Telepathy.MissionControl",
- &error);
-
- if (priv->proxy != NULL) {
- /* If it goes, we set the proxy to NULL */
- g_object_add_weak_pointer (G_OBJECT(priv->proxy), (gpointer *)&priv->proxy);
- /* And we clean up other variables associated */
- g_signal_connect(G_OBJECT(priv->proxy), "destroy",
- G_CALLBACK(proxy_destroy), self);
-
- /* Set up the signal handler for watching when status changes. */
- dbus_g_object_register_marshaller(_status_provider_telepathy_marshal_VOID__UINT_STRING,
- G_TYPE_NONE,
- G_TYPE_UINT,
- G_TYPE_STRING,
- G_TYPE_INVALID);
- dbus_g_proxy_add_signal (priv->proxy,
- "PresenceChanged",
- G_TYPE_UINT,
- G_TYPE_STRING,
- G_TYPE_INVALID);
- dbus_g_proxy_connect_signal(priv->proxy,
- "PresenceChanged",
- G_CALLBACK(changed_status),
- (void *)self,
- NULL);
-
- /* Do a get here, to init the status */
- dbus_g_proxy_begin_call(priv->proxy,
- "GetStatus",
- get_status_async,
- self,
- NULL,
- G_TYPE_INVALID);
- } else {
- g_warning("Unable to connect to Mission Control");
- if (error != NULL) {
- g_error_free(error);
- }
- }
-
- return;
-}
-
-/* Watch to see if the Mission Control comes up on Dbus */
-static void
-dbus_namechange (DBusGProxy * proxy, const gchar * name, const gchar * prev, const gchar * new, StatusProviderTelepathy * self)
-{
- g_return_if_fail(name != NULL);
- g_return_if_fail(new != NULL);
-
- if (g_strcmp0(name, "org.freedesktop.Telepathy.MissionControl") == 0) {
- build_telepathy_proxy(self);
- }
- return;
-}
-
-static void
-status_provider_telepathy_dispose (GObject *object)
-{
- StatusProviderTelepathyPrivate * priv = STATUS_PROVIDER_TELEPATHY_GET_PRIVATE(object);
-
- if (priv->proxy != NULL) {
- g_object_unref(priv->proxy);
- priv->proxy = NULL;
- }
-
- G_OBJECT_CLASS (status_provider_telepathy_parent_class)->dispose (object);
- return;
-}
-
-static void
-status_provider_telepathy_finalize (GObject *object)
-{
-
- G_OBJECT_CLASS (status_provider_telepathy_parent_class)->finalize (object);
- return;
-}
-
-/**
- status_provider_telepathy_new:
-
- Creates a new #StatusProviderTelepathy object. No parameters or anything
- like that. Just a convience function.
-
- Return value: A new instance of #StatusProviderTelepathy
-*/
-StatusProvider *
-status_provider_telepathy_new (void)
-{
- return STATUS_PROVIDER(g_object_new(STATUS_PROVIDER_TELEPATHY_TYPE, NULL));
-}
-
-static void
-set_status (StatusProvider * sp, StatusProviderStatus status)
-{
- StatusProviderTelepathyPrivate * priv = STATUS_PROVIDER_TELEPATHY_GET_PRIVATE(sp);
- if (priv->proxy == NULL) {
- priv->mc_status = MC_STATUS_OFFLINE;
- return;
- }
-
- priv->mc_status = sp_to_mc_map[status];
-
- guint mcstatus = MC_STATUS_UNSET;
- gboolean ret = FALSE;
- GError * error = NULL;
-
- ret = dbus_g_proxy_call(priv->proxy,
- "GetPresence", &error,
- G_TYPE_INVALID,
- G_TYPE_UINT, &priv->mc_status,
- G_TYPE_INVALID);
-
- /* If we can't get the get call to work, let's not set */
- if (!ret) {
- if (error != NULL) {
- g_error_free(error);
- }
- return;
- }
-
- /* If the get call doesn't return a status, that means that there
- are no clients connected. We don't want to connect them by telling
- MC that we're going online -- we'd like to be more passive than that. */
- if (mcstatus == MC_STATUS_UNSET) {
- return;
- }
-
- ret = dbus_g_proxy_call(priv->proxy,
- "SetPresence", &error,
- G_TYPE_UINT, priv->mc_status,
- G_TYPE_STRING, "",
- G_TYPE_INVALID,
- G_TYPE_INVALID);
-
- if (!ret) {
- if (error != NULL) {
- g_warning("Unable to set Mission Control Presence: %s", error->message);
- g_error_free(error);
- } else {
- g_warning("Unable to set Mission Control Presence");
- }
- return;
- }
-
- return;
-}
-
-static StatusProviderStatus
-get_status (StatusProvider * sp)
-{
- g_return_val_if_fail(IS_STATUS_PROVIDER_TELEPATHY(sp), STATUS_PROVIDER_STATUS_DISCONNECTED);
- StatusProviderTelepathyPrivate * priv = STATUS_PROVIDER_TELEPATHY_GET_PRIVATE(sp);
-
- if (priv->proxy == NULL) {
- return STATUS_PROVIDER_STATUS_DISCONNECTED;
- }
-
- return mc_to_sp_map[priv->mc_status];
-}
-
-static void
-changed_status (DBusGProxy * proxy, guint status, gchar * message, StatusProvider * sp)
-{
- StatusProviderTelepathyPrivate * priv = STATUS_PROVIDER_TELEPATHY_GET_PRIVATE(sp);
- priv->mc_status = status;
- g_signal_emit(G_OBJECT(sp), STATUS_PROVIDER_SIGNAL_STATUS_CHANGED_ID, 0, mc_to_sp_map[priv->mc_status], TRUE);
-}
-
-static void
-proxy_destroy (DBusGProxy * proxy, StatusProvider * sp)
-{
- g_debug("Signal: Mission Control proxy destroyed");
- g_signal_emit(G_OBJECT(sp), STATUS_PROVIDER_SIGNAL_STATUS_CHANGED_ID, 0, STATUS_PROVIDER_STATUS_OFFLINE, TRUE);
- return;
-}
-
-static void
-get_status_async (DBusGProxy * proxy, DBusGProxyCall * call, gpointer userdata)
-{
- GError * error = NULL;
- guint status = 0;
- if (!dbus_g_proxy_end_call(proxy, call, &error, G_TYPE_UINT, &status, G_TYPE_INVALID)) {
- g_warning("Unable to get type from Mission Control: %s", error->message);
- g_error_free(error);
- return;
- }
-
- StatusProviderTelepathyPrivate * priv = STATUS_PROVIDER_TELEPATHY_GET_PRIVATE(userdata);
-
- gboolean changed = FALSE;
- if (status != priv->mc_status) {
- changed = TRUE;
- }
-
- priv->mc_status = status;
-
- if (changed) {
- g_signal_emit(G_OBJECT(userdata), STATUS_PROVIDER_SIGNAL_STATUS_CHANGED_ID, 0, mc_to_sp_map[priv->mc_status], TRUE);
- }
-
- return;
-}
=== removed file 'src/status-provider-telepathy.h'
--- src/status-provider-telepathy.h 2011-06-22 20:42:44 +0000
+++ src/status-provider-telepathy.h 1970-01-01 00:00:00 +0000
@@ -1,56 +0,0 @@
-/*
-A small wrapper utility to load indicators and put them as menu items
-into the gnome-panel using it's applet interface.
-
-Copyright 2009 Canonical Ltd.
-
-Authors:
- Ted Gould <ted@xxxxxxxxxxxxx>
-
-This program is free software: you can redistribute it and/or modify it
-under the terms of the GNU General Public License version 3, as published
-by the Free Software Foundation.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranties of
-MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
-PURPOSE. See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along
-with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef __STATUS_PROVIDER_TELEPATHY_H__
-#define __STATUS_PROVIDER_TELEPATHY_H__
-
-#include <glib.h>
-#include <glib-object.h>
-
-#include "status-provider.h"
-
-G_BEGIN_DECLS
-
-#define STATUS_PROVIDER_TELEPATHY_TYPE (status_provider_telepathy_get_type ())
-#define STATUS_PROVIDER_TELEPATHY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), STATUS_PROVIDER_TELEPATHY_TYPE, StatusProviderTelepathy))
-#define STATUS_PROVIDER_TELEPATHY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), STATUS_PROVIDER_TELEPATHY_TYPE, StatusProviderTelepathyClass))
-#define IS_STATUS_PROVIDER_TELEPATHY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), STATUS_PROVIDER_TELEPATHY_TYPE))
-#define IS_STATUS_PROVIDER_TELEPATHY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), STATUS_PROVIDER_TELEPATHY_TYPE))
-#define STATUS_PROVIDER_TELEPATHY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), STATUS_PROVIDER_TELEPATHY_TYPE, StatusProviderTelepathyClass))
-
-
-typedef struct _StatusProviderTelepathyClass StatusProviderTelepathyClass;
-struct _StatusProviderTelepathyClass {
- StatusProviderClass parent_class;
-};
-
-typedef struct _StatusProviderTelepathy StatusProviderTelepathy;
-struct _StatusProviderTelepathy {
- StatusProvider parent;
-};
-
-GType status_provider_telepathy_get_type (void);
-StatusProvider * status_provider_telepathy_new (void);
-
-G_END_DECLS
-
-#endif
=== removed file 'src/status-provider-telepathy.list'
--- src/status-provider-telepathy.list 2011-06-22 20:42:44 +0000
+++ src/status-provider-telepathy.list 1970-01-01 00:00:00 +0000
@@ -1,1 +0,0 @@
-VOID:UINT,STRING
=== removed file 'src/status-provider.c'
--- src/status-provider.c 2011-06-22 20:42:44 +0000
+++ src/status-provider.c 1970-01-01 00:00:00 +0000
@@ -1,101 +0,0 @@
-/*
-A small wrapper utility to load indicators and put them as menu items
-into the gnome-panel using it's applet interface.
-
-Copyright 2009 Canonical Ltd.
-
-Authors:
- Ted Gould <ted@xxxxxxxxxxxxx>
-
-This program is free software: you can redistribute it and/or modify it
-under the terms of the GNU General Public License version 3, as published
-by the Free Software Foundation.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranties of
-MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
-PURPOSE. See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along
-with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "status-provider.h"
-
-/* Signals */
-enum {
- STATUS_CHANGED,
- LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL] = { 0 };
-
-/* GObject Boilerplate */
-static void status_provider_class_init (StatusProviderClass *klass);
-static void status_provider_init (StatusProvider *self);
-
-G_DEFINE_TYPE (StatusProvider, status_provider, G_TYPE_OBJECT);
-
-static void
-status_provider_class_init (StatusProviderClass *klass)
-{
- // GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- klass->status_changed = NULL;
-
- klass->set_status = NULL;
- klass->get_status = NULL;
-
- /**
- StatusProvider::status-changed:
- @arg0: The #StatusProvider object.
- @arg1: The new status #StatusProviderStatus
-
- Should be emitted by subclasses everytime that the status
- changes externally to us.
- */
- signals[STATUS_CHANGED] = g_signal_new(STATUS_PROVIDER_SIGNAL_STATUS_CHANGED,
- G_TYPE_FROM_CLASS(klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET(StatusProviderClass, status_changed),
- NULL, NULL,
- g_cclosure_marshal_VOID__UINT,
- G_TYPE_NONE, 1, G_TYPE_UINT);
-
- return;
-}
-
-static void
-status_provider_init (StatusProvider *self)
-{
-
- return;
-}
-
-void
-status_provider_set_status (StatusProvider * sp, StatusProviderStatus status)
-{
- g_return_if_fail(IS_STATUS_PROVIDER(sp));
-
- StatusProviderClass * class = STATUS_PROVIDER_GET_CLASS(sp);
- g_return_if_fail(class != NULL);
- g_return_if_fail(class->set_status != NULL);
-
- return class->set_status(sp, status);
-}
-
-StatusProviderStatus
-status_provider_get_status (StatusProvider * sp)
-{
- g_return_val_if_fail(IS_STATUS_PROVIDER(sp), STATUS_PROVIDER_STATUS_OFFLINE);
-
- StatusProviderClass * class = STATUS_PROVIDER_GET_CLASS(sp);
- g_return_val_if_fail(class->get_status != NULL, STATUS_PROVIDER_STATUS_OFFLINE);
-
- return class->get_status(sp);
-}
-
=== removed file 'src/status-provider.h'
--- src/status-provider.h 2011-07-02 12:15:22 +0000
+++ src/status-provider.h 1970-01-01 00:00:00 +0000
@@ -1,81 +0,0 @@
-/*
-A small wrapper utility to load indicators and put them as menu items
-into the gnome-panel using it's applet interface.
-
-Copyright 2009 Canonical Ltd.
-
-Authors:
- Ted Gould <ted@xxxxxxxxxxxxx>
-
-This program is free software: you can redistribute it and/or modify it
-under the terms of the GNU General Public License version 3, as published
-by the Free Software Foundation.
-
-This program is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranties of
-MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
-PURPOSE. See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along
-with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef __STATUS_PROVIDER_H__
-#define __STATUS_PROVIDER_H__
-
-#include <glib.h>
-#include <glib-object.h>
-
-G_BEGIN_DECLS
-
-#define STATUS_PROVIDER_EXPORT_TYPE(x) GType status_provider_export_type (void) { return (x); }
-#define STATUS_PROVIDER_EXPORT_S "status_provider_export_type"
-
-#define STATUS_PROVIDER_TYPE (status_provider_get_type ())
-#define STATUS_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), STATUS_PROVIDER_TYPE, StatusProvider))
-#define STATUS_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), STATUS_PROVIDER_TYPE, StatusProviderClass))
-#define IS_STATUS_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), STATUS_PROVIDER_TYPE))
-#define IS_STATUS_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), STATUS_PROVIDER_TYPE))
-#define STATUS_PROVIDER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), STATUS_PROVIDER_TYPE, StatusProviderClass))
-
-typedef enum
-{
- STATUS_PROVIDER_STATUS_ONLINE,
- STATUS_PROVIDER_STATUS_AWAY,
- STATUS_PROVIDER_STATUS_DND,
- STATUS_PROVIDER_STATUS_INVISIBLE,
- STATUS_PROVIDER_STATUS_OFFLINE,
- STATUS_PROVIDER_STATUS_DISCONNECTED,
- /* Leave as last */
- STATUS_PROVIDER_STATUS_LAST
-}
-StatusProviderStatus;
-
-#define STATUS_PROVIDER_SIGNAL_STATUS_CHANGED "status-changed"
-#define STATUS_PROVIDER_SIGNAL_STATUS_CHANGED_ID (g_signal_lookup(STATUS_PROVIDER_SIGNAL_STATUS_CHANGED, STATUS_PROVIDER_TYPE))
-
-typedef struct _StatusProvider StatusProvider;
-struct _StatusProvider {
- GObject parent;
-};
-
-typedef struct _StatusProviderClass StatusProviderClass;
-struct _StatusProviderClass {
- GObjectClass parent_class;
-
- /* Signals */
- void (*status_changed) (StatusProviderStatus newstatus);
-
- /* Virtual Functions */
- void (*set_status) (StatusProvider * sp, StatusProviderStatus newstatus);
- StatusProviderStatus (*get_status) (StatusProvider * sp);
-};
-
-GType status_provider_get_type (void);
-
-void status_provider_set_status (StatusProvider * sp, StatusProviderStatus status);
-StatusProviderStatus status_provider_get_status (StatusProvider * sp);
-
-G_END_DECLS
-
-#endif
=== added file 'test/Makefile.am'
--- test/Makefile.am 1970-01-01 00:00:00 +0000
+++ test/Makefile.am 2013-06-07 21:39:23 +0000
@@ -0,0 +1,78 @@
+
+check_LIBRARIES = libgtest.a
+check_PROGRAMS = test-gactionmuxer
+
+TESTS = $(check_PROGRAMS)
+
+AM_CPPFLAGS = $(GTEST_CPPFLAGS) \
+ -I${top_srcdir}/src
+
+nodist_libgtest_a_SOURCES = \
+ $(GTEST_SOURCE)/src/gtest-all.cc \
+ $(GTEST_SOURCE)/src/gtest_main.cc
+libgtest_a_CPPFLAGS = \
+ $(GTEST_CPPFLAGS) -w \
+ $(AM_CPPFLAGS)
+libgtest_a_CXXFLAGS = \
+ $(AM_CXXFLAGS)
+
+
+test_gactionmuxer_SOURCES = \
+ test-gactionmuxer.cpp
+
+test_gactionmuxer_CPPFLAGS = \
+ $(APPLET_CFLAGS) \
+ $(AM_CPPFLAGS)
+
+test_gactionmuxer_LDADD = \
+ $(APPLET_LIBS) \
+ libindicator-messages-service.la \
+ libgtest.a
+
+
+######################################
+# Lib containing code under test
+######################################
+
+noinst_LTLIBRARIES = \
+ libindicator-messages-service.la
+
+libindicator_messages_service_la_SOURCES = \
+ $(top_builddir)/src/indicator-messages-service.c \
+ $(top_builddir)/src/indicator-messages-service.h \
+ $(top_srcdir)/src/app-section.c \
+ $(top_srcdir)/src/app-section.h \
+ $(top_srcdir)/src/gactionmuxer.c \
+ $(top_srcdir)/src/gactionmuxer.h
+ $(top_srcdir)/src/dbus-data.h
+
+libindicator_messages_service_ladir = \
+ $(includedir)/libindicator-messages-service/
+
+libindicator_messages_service_la_CFLAGS = \
+ $(APPLET_CFLAGS) \
+ $(COVERAGE_CFLAGS) \
+ -I$(top_builddir)/src \
+ -Wall \
+ -Wl,-Bsymbolic-functions \
+ -Wl,-z,defs \
+ -Wl,--as-needed \
+ -Werror \
+ -DG_LOG_DOMAIN=\"Indicator-Messages\"
+
+libindicator_messages_service_la_LIBADD = \
+ $(APPLET_LIBS)
+
+libindicator_messages_service_la_LDFLAGS = \
+ $(COVERAGE_LDFLAGS)
+
+######################################
+# Test client with dbusmock
+######################################
+
+TESTS_ENVIRONMENT = \
+ export LD_LIBRARY_PATH=$(top_builddir)/libmessaging-menu/.libs; \
+ export GI_TYPELIB_PATH=$(top_builddir)/libmessaging-menu; \
+ export XDG_DATA_DIRS=$(abs_srcdir);
+
+TESTS += test-client.py
=== added directory 'test/applications'
=== added file 'test/applications/test.desktop'
--- test/applications/test.desktop 1970-01-01 00:00:00 +0000
+++ test/applications/test.desktop 2013-06-07 21:39:23 +0000
@@ -0,0 +1,2 @@
+[Desktop Entry]
+Type=Application
=== modified file 'test/indicator-messages-service-activate.c'
--- test/indicator-messages-service-activate.c 2009-05-28 15:29:41 +0000
+++ test/indicator-messages-service-activate.c 2013-06-07 21:39:23 +0000
@@ -28,8 +28,6 @@
int
main (int argc, char ** argv)
{
- g_type_init();
-
guint returnval = 0;
GError * error = NULL;
=== added file 'test/test-client.py'
--- test/test-client.py 1970-01-01 00:00:00 +0000
+++ test/test-client.py 2013-06-07 21:39:23 +0000
@@ -0,0 +1,75 @@
+#!/usr/bin/env python3
+
+import unittest
+import dbus
+from dbus.mainloop.glib import DBusGMainLoop
+import dbusmock
+import subprocess
+from gi.repository import GLib, Gio, MessagingMenu
+
+DBusGMainLoop(set_as_default=True)
+
+class MessagingMenuTest(dbusmock.DBusTestCase):
+ @classmethod
+ def setUpClass(klass):
+ klass.start_session_bus()
+ klass.bus = klass.get_dbus(False)
+
+ def setUp(self):
+ name = 'com.canonical.indicator.messages'
+ obj_path = '/com/canonical/indicator/messages/service'
+ iface = 'com.canonical.indicator.messages.service