aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Gould <ted@gould.cx>2010-02-18 12:21:04 -0600
committerTed Gould <ted@gould.cx>2010-02-18 12:21:04 -0600
commit8fe010b29ccc4d32c2bc326b67fc9ff1f63b05df (patch)
treeb03109c0f8ff20b52161da7b906ac8962ca31835
parentd1741b51fc36866b182fe3e70f54fef45adae2f6 (diff)
parentb9713df6cd2898e5f86d8dcf1f39634bc1cc6736 (diff)
downloadayatana-indicator-messages-8fe010b29ccc4d32c2bc326b67fc9ff1f63b05df.tar.gz
ayatana-indicator-messages-8fe010b29ccc4d32c2bc326b67fc9ff1f63b05df.tar.bz2
ayatana-indicator-messages-8fe010b29ccc4d32c2bc326b67fc9ff1f63b05df.zip
* 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
-rw-r--r--configure.ac6
-rw-r--r--data/icons/16x16/status/Makefile.am1
-rw-r--r--data/icons/16x16/status/application-running.pngbin0 -> 586 bytes
-rw-r--r--data/icons/24x24/status/Makefile.am1
-rw-r--r--data/icons/24x24/status/application-running.pngbin0 -> 774 bytes
-rw-r--r--data/icons/32x32/status/Makefile.am1
-rw-r--r--data/icons/32x32/status/application-running.pngbin0 -> 996 bytes
-rw-r--r--data/icons/48x48/status/Makefile.am1
-rw-r--r--data/icons/48x48/status/application-running.pngbin0 -> 1513 bytes
-rw-r--r--data/icons/scalable/status/Makefile.am1
-rw-r--r--data/icons/scalable/status/application-running.svg179
-rw-r--r--debian/changelog14
-rw-r--r--src/app-menu-item.c215
-rw-r--r--src/app-menu-item.h7
-rw-r--r--src/dbus-data.h4
-rw-r--r--src/indicator-messages.c35
-rw-r--r--src/launcher-menu-item.c144
-rw-r--r--src/launcher-menu-item.h2
-rw-r--r--src/messages-service.c253
19 files changed, 768 insertions, 96 deletions
diff --git a/configure.ac b/configure.ac
index 47261ec..38ddccd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4,7 +4,7 @@ AC_INIT(src/indicator-messages.c)
AC_PREREQ(2.53)
AM_CONFIG_HEADER(config.h)
-AM_INIT_AUTOMAKE(indicator-messages, 0.3.1)
+AM_INIT_AUTOMAKE(indicator-messages, 0.3.2)
AM_MAINTAINER_MODE
@@ -30,8 +30,8 @@ GTK_REQUIRED_VERSION=2.12
GIO_UNIX_REQUIRED_VERSION=2.18
PANEL_REQUIRED_VERSION=2.0.0
INDICATE_REQUIRED_VERSION=0.3.0
-INDICATOR_REQUIRED_VERSION=0.3.0
-DBUSMENUGTK_REQUIRED_VERSION=0.2.2
+INDICATOR_REQUIRED_VERSION=0.3.3
+DBUSMENUGTK_REQUIRED_VERSION=0.2.5
PKG_CHECK_MODULES(APPLET, gtk+-2.0 >= $GTK_REQUIRED_VERSION
gio-unix-2.0 >= $GIO_UNIX_REQUIRED_VERSION
diff --git a/data/icons/16x16/status/Makefile.am b/data/icons/16x16/status/Makefile.am
index e9fdeed..e9c66f1 100644
--- a/data/icons/16x16/status/Makefile.am
+++ b/data/icons/16x16/status/Makefile.am
@@ -2,6 +2,7 @@
iconsdir = $(INDICATORICONSDIR)/hicolor/16x16/status
icons_DATA = \
+ application-running.png \
indicator-messages.png \
indicator-messages-new.png
diff --git a/data/icons/16x16/status/application-running.png b/data/icons/16x16/status/application-running.png
new file mode 100644
index 0000000..2c86d7e
--- /dev/null
+++ b/data/icons/16x16/status/application-running.png
Binary files differ
diff --git a/data/icons/24x24/status/Makefile.am b/data/icons/24x24/status/Makefile.am
index 71378be..7686c0e 100644
--- a/data/icons/24x24/status/Makefile.am
+++ b/data/icons/24x24/status/Makefile.am
@@ -2,6 +2,7 @@
iconsdir = $(INDICATORICONSDIR)/hicolor/24x24/status
icons_DATA = \
+ application-running.png \
indicator-messages.png \
indicator-messages-new.png
diff --git a/data/icons/24x24/status/application-running.png b/data/icons/24x24/status/application-running.png
new file mode 100644
index 0000000..5eb2466
--- /dev/null
+++ b/data/icons/24x24/status/application-running.png
Binary files differ
diff --git a/data/icons/32x32/status/Makefile.am b/data/icons/32x32/status/Makefile.am
index e34608b..84d9609 100644
--- a/data/icons/32x32/status/Makefile.am
+++ b/data/icons/32x32/status/Makefile.am
@@ -2,6 +2,7 @@
iconsdir = $(INDICATORICONSDIR)/hicolor/32x32/status
icons_DATA = \
+ application-running.png \
indicator-messages.png \
indicator-messages-new.png
diff --git a/data/icons/32x32/status/application-running.png b/data/icons/32x32/status/application-running.png
new file mode 100644
index 0000000..a7770ae
--- /dev/null
+++ b/data/icons/32x32/status/application-running.png
Binary files differ
diff --git a/data/icons/48x48/status/Makefile.am b/data/icons/48x48/status/Makefile.am
index 69c0996..ee7eb74 100644
--- a/data/icons/48x48/status/Makefile.am
+++ b/data/icons/48x48/status/Makefile.am
@@ -2,6 +2,7 @@
iconsdir = $(INDICATORICONSDIR)/hicolor/48x48/status
icons_DATA = \
+ application-running.png \
indicator-messages.png \
indicator-messages-new.png
diff --git a/data/icons/48x48/status/application-running.png b/data/icons/48x48/status/application-running.png
new file mode 100644
index 0000000..5266e22
--- /dev/null
+++ b/data/icons/48x48/status/application-running.png
Binary files differ
diff --git a/data/icons/scalable/status/Makefile.am b/data/icons/scalable/status/Makefile.am
index 263735a..060b479 100644
--- a/data/icons/scalable/status/Makefile.am
+++ b/data/icons/scalable/status/Makefile.am
@@ -2,6 +2,7 @@
iconsdir = $(INDICATORICONSDIR)/hicolor/scalable/status
icons_DATA = \
+ application-running.svg \
indicator-messages.svg \
indicator-messages-new.svg
diff --git a/data/icons/scalable/status/application-running.svg b/data/icons/scalable/status/application-running.svg
new file mode 100644
index 0000000..9b5c195
--- /dev/null
+++ b/data/icons/scalable/status/application-running.svg
@@ -0,0 +1,179 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="48"
+ height="48"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.47 r22583"
+ version="1.0"
+ sodipodi:docname="application-running.svg"
+ inkscape:export-filename="/home/jimmac/src/cvs/gnome/gnome-icon-theme/16x16/actions/go-previous.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape">
+ <defs
+ id="defs4">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 24 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="48 : 24 : 1"
+ inkscape:persp3d-origin="24 : 16 : 1"
+ id="perspective19" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient5105">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop5107" />
+ <stop
+ style="stop-color:black;stop-opacity:0;"
+ offset="1"
+ id="stop5109" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient5113">
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="0"
+ id="stop5115" />
+ <stop
+ style="stop-color:white;stop-opacity:0;"
+ offset="1"
+ id="stop5117" />
+ </linearGradient>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5105"
+ id="radialGradient4354"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,0.282946,0,13.64644)"
+ cx="11.25"
+ cy="19.03125"
+ fx="11.25"
+ fy="19.03125"
+ r="8.0625" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5113"
+ id="linearGradient5315"
+ x1="17.498823"
+ y1="10.445395"
+ x2="34.744495"
+ y2="40.231434"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.004639,0,0,1,-15.037685,0.047681)" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666"
+ borderopacity="0.17254902"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="8"
+ inkscape:cx="-3.1819493"
+ inkscape:cy="19.763605"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ width="48px"
+ height="48px"
+ inkscape:showpageshadow="false"
+ showgrid="false"
+ inkscape:window-width="1440"
+ inkscape:window-height="847"
+ inkscape:window-x="0"
+ inkscape:window-y="26"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ <dc:date>August 2006</dc:date>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Andreas Nilsson</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:contributor>
+ <cc:Agent>
+ <dc:title>Jakub Steiner</dc:title>
+ </cc:Agent>
+ </dc:contributor>
+ <dc:source>http://www.gnome.org</dc:source>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>next</rdf:li>
+ <rdf:li>arrow</rdf:li>
+ <rdf:li>go</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
+ <dc:description />
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Reproduction" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Distribution" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Notice" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/ShareAlike" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/SourceCode" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ sodipodi:type="arc"
+ style="opacity:0.16292138;color:#000000;fill:url(#radialGradient4354);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible"
+ id="path4346"
+ sodipodi:cx="11.25"
+ sodipodi:cy="19.03125"
+ sodipodi:rx="8.0625"
+ sodipodi:ry="2.28125"
+ d="m 19.3125,19.03125 a 8.0625,2.28125 0 1 1 -16.125,0 8.0625,2.28125 0 1 1 16.125,0 z"
+ transform="matrix(1.736434,0,0,2.410961,-2.284883,-4.38361)" />
+ <path
+ style="color:#000000;fill:#3465a4;fill-opacity:1;fill-rule:nonzero;stroke:#204a87;stroke-width:0.99999958;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
+ d="M 8.502204,9.5398056 27.506348,26.04583 8.502204,42.469121 l 0,-7.869835 0,-17.055132 0,-8.0043484 z"
+ id="path4348"
+ sodipodi:nodetypes="cccccc" />
+ <path
+ style="opacity:0.35393258;color:#000000;fill:#729fcf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible"
+ d="M 26.768866,25.975897 9.154262,10.631373 l 0,15.416365 17.614604,-0.07184 z"
+ id="path4352"
+ sodipodi:nodetypes="cccc" />
+ <path
+ style="opacity:0.35400002;color:#000000;fill:none;stroke:url(#linearGradient5315);stroke-width:0.99999958;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
+ d="m 9.573053,11.680863 16.516638,14.386273 -16.516638,14.199301 0,-6.738369 0,-14.978334 0,-6.868871 z"
+ id="path4360"
+ sodipodi:nodetypes="cccccc" />
+ </g>
+</svg>
diff --git a/debian/changelog b/debian/changelog
index 572d63f..154e966 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,17 @@
+indicator-messages (0.3.2-0ubuntu1~ppa1) UNRELEASED; 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
+
+ -- Ted Gould <ted@ubuntu.com> Thu, 18 Feb 2010 12:18:27 -0600
+
indicator-messages (0.3.1-0ubuntu2) lucid; urgency=low
* Upstream Merge
diff --git a/src/app-menu-item.c b/src/app-menu-item.c
index 71860ea..a37daf4 100644
--- a/src/app-menu-item.c
+++ b/src/app-menu-item.c
@@ -26,12 +26,15 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#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 "dbus-data.h"
enum {
COUNT_CHANGED,
NAME_CHANGED,
+ SHORTCUTS_CHANGED,
LAST_SIGNAL
};
@@ -48,6 +51,10 @@ struct _AppMenuItemPrivate
GAppInfo * appinfo;
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))
@@ -60,6 +67,7 @@ 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, gchar * menupath, gpointer data);
static void desktop_cb (IndicateListener * listener, IndicateListenerServer * server, gchar * value, gpointer data);
static void update_label (AppMenuItem * self);
@@ -90,6 +98,13 @@ app_menu_item_class_init (AppMenuItemClass *klass)
NULL, NULL,
g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE, 1, G_TYPE_STRING);
+ signals[SHORTCUTS_CHANGED] = g_signal_new(APP_MENU_ITEM_SIGNAL_SHORTCUTS_CHANGED,
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (AppMenuItemClass, shortcuts_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0, G_TYPE_NONE);
return;
}
@@ -107,20 +122,56 @@ app_menu_item_init (AppMenuItem *self)
priv->desktop = NULL;
priv->unreadcount = 0;
+ priv->client = NULL;
+ priv->root = NULL;
+ priv->shortcuts = NULL;
+
return;
}
+/* A wrapper to make the prototypes work for GFunc */
+static void
+func_unref (gpointer data, gpointer user_data)
+{
+ 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);
- g_object_unref(priv->listener);
+ 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, NULL);
+ g_list_free(priv->shortcuts);
+ priv->shortcuts = NULL;
+ g_signal_emit(object, signals[SHORTCUTS_CHANGED], 0, TRUE);
+ }
+
+ if (priv->root != NULL) {
+ g_object_unref(priv->root);
+ priv->root = NULL;
+ }
+
+ if (priv->client != NULL) {
+ g_object_unref(priv->client);
+ priv->client = 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)
{
@@ -164,6 +215,7 @@ app_menu_item_new (IndicateListener * listener, IndicateListenerServer * server)
/* 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);
@@ -202,6 +254,7 @@ update_label (AppMenuItem * self)
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);
@@ -230,6 +283,7 @@ count_cb (IndicateListener * listener, IndicateListenerServer * server, guint va
static void
desktop_cb (IndicateListener * listener, IndicateListenerServer * server, 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);
@@ -253,11 +307,160 @@ desktop_cb (IndicateListener * listener, IndicateListenerServer * server, gchar
priv->desktop = g_strdup(value);
update_label(self);
+
+ GIcon * icon = g_app_info_get_icon(priv->appinfo);
+ gchar * iconstr = g_icon_to_string(icon);
+ dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_ICON_NAME, iconstr);
+ g_free(iconstr);
+
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[SHORTCUTS_CHANGED], 0, 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);
+ g_object_unref(mip);
+ priv->shortcuts = g_list_remove(priv->shortcuts, mip);
+
+ g_signal_emit(G_OBJECT(data), signals[SHORTCUTS_CHANGED], 0, TRUE);
+ }
+
+ 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[SHORTCUTS_CHANGED], 0, 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);
+ gboolean change_time = FALSE;
+
+ if (priv->root != NULL) {
+ if (dbusmenu_menuitem_get_children(DBUSMENU_MENUITEM(priv->root)) != NULL) {
+ change_time = TRUE;
+ g_list_foreach(priv->shortcuts, func_unref, NULL);
+ 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;
+ 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) {
+ change_time = TRUE;
+ 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);
+ children = g_list_next(children);
+ }
+ }
+
+ if (change_time) {
+ g_signal_emit(G_OBJECT(self), signals[SHORTCUTS_CHANGED], 0, TRUE);
+ }
+
+ 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, 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)
{
@@ -305,3 +508,13 @@ app_menu_item_get_desktop (AppMenuItem * appitem)
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;
+}
diff --git a/src/app-menu-item.h b/src/app-menu-item.h
index 583d50d..48a7cfa 100644
--- a/src/app-menu-item.h
+++ b/src/app-menu-item.h
@@ -37,8 +37,9 @@ G_BEGIN_DECLS
#define IS_APP_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), APP_MENU_ITEM_TYPE))
#define APP_MENU_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), APP_MENU_ITEM_TYPE, AppMenuItemClass))
-#define APP_MENU_ITEM_SIGNAL_COUNT_CHANGED "count-changed"
-#define APP_MENU_ITEM_SIGNAL_NAME_CHANGED "name-changed"
+#define APP_MENU_ITEM_SIGNAL_COUNT_CHANGED "count-changed"
+#define APP_MENU_ITEM_SIGNAL_NAME_CHANGED "name-changed"
+#define APP_MENU_ITEM_SIGNAL_SHORTCUTS_CHANGED "shortcuts-changed"
typedef struct _AppMenuItem AppMenuItem;
typedef struct _AppMenuItemClass AppMenuItemClass;
@@ -48,6 +49,7 @@ struct _AppMenuItemClass {
void (* count_changed) (guint count);
void (* name_changed) (gchar * name);
+ void (* shortcuts_changed) (void);
};
struct _AppMenuItem {
@@ -60,6 +62,7 @@ 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);
G_END_DECLS
diff --git a/src/dbus-data.h b/src/dbus-data.h
index 9f53f94..e3d9fd5 100644
--- a/src/dbus-data.h
+++ b/src/dbus-data.h
@@ -8,10 +8,6 @@
#define INDICATOR_MESSAGES_DBUS_SERVICE_OBJECT "/org/ayatana/indicator/messages/service"
#define INDICATOR_MESSAGES_DBUS_SERVICE_INTERFACE "org.ayatana.indicator.messages.service"
-#define LAUNCHER_MENUITEM_TYPE "launcher-item"
-#define LAUNCHER_MENUITEM_PROP_APP_NAME "application-name"
-#define LAUNCHER_MENUITEM_PROP_APP_DESC "application-description"
-
#define APPLICATION_MENUITEM_TYPE "application-item"
#define APPLICATION_MENUITEM_PROP_NAME "app-name"
#define APPLICATION_MENUITEM_PROP_COUNT "app-count"
diff --git a/src/indicator-messages.c b/src/indicator-messages.c
index acb2e68..3f533a5 100644
--- a/src/indicator-messages.c
+++ b/src/indicator-messages.c
@@ -337,40 +337,6 @@ new_indicator_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbusm
return TRUE;
}
-static gboolean
-new_launcher_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client)
-{
- 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 */
-
- GtkMenuItem * gmi = GTK_MENU_ITEM(gtk_menu_item_new());
-
- GtkWidget * vbox = gtk_vbox_new(TRUE, 2);
-
- GtkWidget * app_label = gtk_label_new(dbusmenu_menuitem_property_get(newitem, LAUNCHER_MENUITEM_PROP_APP_NAME));
- gtk_misc_set_alignment(GTK_MISC(app_label), 0.0, 0.5);
- GtkWidget * dsc_label = gtk_label_new("");
- gtk_misc_set_alignment(GTK_MISC(dsc_label), 0.0, 0.5);
- gtk_label_set_ellipsize(GTK_LABEL(dsc_label), PANGO_ELLIPSIZE_END);
- gtk_widget_set_size_request(dsc_label, 200, -1);
- gchar * markup = g_markup_printf_escaped("<span font-size=\"smaller\">%s</span>", dbusmenu_menuitem_property_get(newitem, LAUNCHER_MENUITEM_PROP_APP_DESC));
- gtk_label_set_markup(GTK_LABEL(dsc_label), markup);
- g_free(markup);
-
- gtk_box_pack_start(GTK_BOX(vbox), app_label, FALSE, FALSE, 0);
- gtk_widget_show(app_label);
- gtk_box_pack_start(GTK_BOX(vbox), dsc_label, FALSE, FALSE, 0);
- gtk_widget_show(dsc_label);
-
- gtk_container_add(GTK_CONTAINER(gmi), GTK_WIDGET(vbox));
- gtk_widget_show(GTK_WIDGET(vbox));
-
- dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, gmi, parent);
-
- return TRUE;
-}
-
static GtkImage *
get_icon (IndicatorObject * io)
{
@@ -409,7 +375,6 @@ get_menu (IndicatorObject * io)
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), LAUNCHER_MENUITEM_TYPE, new_launcher_item);
dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), INDICATOR_MENUITEM_TYPE, new_indicator_item);
return GTK_MENU(menu);
diff --git a/src/launcher-menu-item.c b/src/launcher-menu-item.c
index 50e8ce6..07b0546 100644
--- a/src/launcher-menu-item.c
+++ b/src/launcher-menu-item.c
@@ -27,6 +27,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#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"
@@ -42,16 +43,21 @@ struct _LauncherMenuItemPrivate
{
GAppInfo * appinfo;
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);
@@ -86,20 +92,21 @@ launcher_menu_item_init (LauncherMenuItem *self)
priv->appinfo = NULL;
priv->desktop = NULL;
+ priv->ids = NULL;
+ priv->shortcuts = NULL;
+
return;
}
static void
-launcher_menu_item_dispose (GObject *object)
+func_unref (gpointer data, gpointer user_data)
{
- // LauncherMenuItem * self = LAUNCHER_MENU_ITEM(object);
- // LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(self);
-
- G_OBJECT_CLASS (launcher_menu_item_parent_class)->dispose (object);
+ g_object_unref(G_OBJECT(data));
+ return;
}
static void
-launcher_menu_item_finalize (GObject *object)
+launcher_menu_item_dispose (GObject *object)
{
LauncherMenuItem * self = LAUNCHER_MENU_ITEM(object);
LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(self);
@@ -109,6 +116,26 @@ launcher_menu_item_finalize (GObject *object)
priv->appinfo = 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;
@@ -127,16 +154,36 @@ launcher_menu_item_new (const gchar * 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->desktop = g_strdup(desktop_file);
+ /* Set the appropriate values on this menu item based on the
+ app info that we've parsed */
g_debug("\tName: %s", launcher_menu_item_get_name(self));
- dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_TYPE, LAUNCHER_MENUITEM_TYPE);
- dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), LAUNCHER_MENUITEM_PROP_APP_NAME, launcher_menu_item_get_name(self));
- dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), LAUNCHER_MENUITEM_PROP_APP_DESC, launcher_menu_item_get_description(self));
+ dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_LABEL, launcher_menu_item_get_name(self));
+ gchar * iconstr = launcher_menu_item_get_icon(self);
+ dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_ICON_NAME, iconstr);
+ g_free(iconstr);
+ dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
g_signal_connect(G_OBJECT(self), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(activate_cb), NULL);
+ /* Start to build static shortcuts */
+ priv->ids = indicator_desktop_shortcuts_new(priv->desktop, "Messaging Menu");
+ const gchar ** nicks = indicator_desktop_shortcuts_get_nicks(priv->ids);
+ gint i;
+ for (i = 0; nicks[i] != NULL; i++) {
+ DbusmenuMenuitem * mi = dbusmenu_menuitem_new();
+ 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);
}
@@ -156,6 +203,41 @@ launcher_menu_item_get_name (LauncherMenuItem * appitem)
}
}
+/* 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;
+}
+
+gchar *
+launcher_menu_item_get_icon (LauncherMenuItem * appitem)
+{
+ LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(appitem);
+
+ if (priv->appinfo == NULL) {
+ return NULL;
+ } else {
+ GIcon * icon = g_app_info_get_icon(priv->appinfo);
+ gchar * iconstr = g_icon_to_string(icon);
+ return iconstr;
+ }
+}
+
/* When the menu item is clicked on it tries to launch
the application that is represented by the desktop file */
static void
@@ -191,26 +273,50 @@ launcher_menu_item_get_description (LauncherMenuItem * 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(DBUSMENU_MENUITEM(li), DBUSMENU_MENUITEM_PROP_VISIBLE, eclipsed ? "false" : "true");
+ 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));
+
return;
}
+/* Check to see if this item is eclipsed */
gboolean
launcher_menu_item_get_eclipsed (LauncherMenuItem * li)
{
- const gchar * show = dbusmenu_menuitem_property_get(DBUSMENU_MENUITEM(li), DBUSMENU_MENUITEM_PROP_VISIBLE);
- if (show == NULL) {
- return FALSE;
- }
- g_debug("Launcher check eclipse: %s", show);
- if (!g_strcmp0(show, "false")) {
- return TRUE;
- }
- return FALSE;
+ gboolean show = dbusmenu_menuitem_property_get_bool(DBUSMENU_MENUITEM(li), DBUSMENU_MENUITEM_PROP_VISIBLE);
+ g_debug("Launcher check eclipse: %s", show ? "false" : "true");
+ return !show;
+}
+
+/* Gets the shortcuts that are associated with this
+ launcher. They're a list of DbusmenuMenuitems */
+GList *
+launcher_menu_item_get_items (LauncherMenuItem * li)
+{
+ g_return_val_if_fail(IS_LAUNCHER_MENU_ITEM(li), NULL);
+ LauncherMenuItemPrivate * priv = LAUNCHER_MENU_ITEM_GET_PRIVATE(li);
+ return priv->shortcuts;
}
diff --git a/src/launcher-menu-item.h b/src/launcher-menu-item.h
index 3e031d5..ace1f85 100644
--- a/src/launcher-menu-item.h
+++ b/src/launcher-menu-item.h
@@ -57,8 +57,10 @@ 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
diff --git a/src/messages-service.c b/src/messages-service.c
index ca9e799..0ebab0b 100644
--- a/src/messages-service.c
+++ b/src/messages-service.c
@@ -31,6 +31,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#include <libdbusmenu-glib/client.h>
#include <libdbusmenu-glib/server.h>
+#include <libdbusmenu-glib/menuitem-proxy.h>
#include "im-menu-item.h"
#include "app-menu-item.h"
@@ -48,7 +49,10 @@ static GMainLoop * mainloop = NULL;
static MessageServiceDbus * dbus_interface = NULL;
+#define DESKTOP_FILE_GROUP "Messaging Menu"
+#define DESKTOP_FILE_KEY_DESKTOP "DesktopFile"
+static void server_shortcuts_changed (AppMenuItem * appitem, 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);
@@ -57,9 +61,14 @@ static void indicator_removed (IndicateListener * listener, IndicateListenerServ
static void check_eclipses (AppMenuItem * ai);
static void remove_eclipses (AppMenuItem * ai);
static gboolean build_launcher (gpointer data);
+static gboolean build_launcher_keyfile (gpointer data);
+static void build_launcher_core (const gchar * desktop);
static gboolean build_launchers (gpointer data);
static gboolean blacklist_init (gpointer data);
static gboolean blacklist_add (gpointer data);
+static gchar * desktop_file_from_keyfile (const gchar * definition_file);
+static gboolean blacklist_keyfile_add (gpointer udata);
+static void blacklist_add_core (gchar * desktop, gchar * definition);
static gboolean blacklist_remove (gpointer data);
static void blacklist_dir_changed (GFileMonitor * monitor, GFile * file, GFile * other_file, GFileMonitorEvent event_type, gpointer user_data);
static void app_dir_changed (GFileMonitor * monitor, GFile * file, GFile * other_file, GFileMonitorEvent event_type, gpointer user_data);
@@ -241,7 +250,11 @@ blacklist_init (gpointer data)
while ((filename = g_dir_read_name(dir)) != NULL) {
g_debug("Found file: %s", filename);
gchar * path = g_build_filename(blacklistdir, filename, NULL);
- g_idle_add(blacklist_add, path);
+ 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);
@@ -250,6 +263,53 @@ blacklist_init (gpointer data)
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
and launchers that have the same file. */
static gboolean
@@ -268,38 +328,51 @@ blacklist_add (gpointer udata)
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, trimdesktop);
+ gpointer data = g_hash_table_lookup(blacklist, desktop);
if (data != NULL) {
gchar * oldfile = (gchar *)data;
- if (!g_strcmp0(oldfile, definition_file)) {
+ 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'", trimdesktop, oldfile, definition_file);
+ g_warning("Already have desktop file '%s' in blacklist file '%s' not adding from '%s'", desktop, oldfile, definition);
}
- g_free(trimdesktop);
- g_free(definition_file);
- return FALSE;
+ return;
}
/* Actually blacklist this thing */
- g_hash_table_insert(blacklist, trimdesktop, definition_file);
- g_debug("Adding Blacklist item '%s' for desktop '%s'", definition_file, trimdesktop);
+ g_hash_table_insert(blacklist, desktop, 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(trimdesktop, launcher_menu_item_get_desktop(item->menuitem))) {
+ if (!g_strcmp0(desktop, launcher_menu_item_get_desktop(item->menuitem))) {
launcher_menu_item_set_eclipsed(item->menuitem, TRUE);
- dbusmenu_menuitem_property_set(item->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, "false");
+ 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 FALSE;
+ return;
}
/* Remove a black list item based on the definition file
@@ -340,7 +413,7 @@ blacklist_remove (gpointer data)
}
if (serveritem == NULL) {
launcher_menu_item_set_eclipsed(li->menuitem, FALSE);
- dbusmenu_menuitem_property_set(li->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, "true");
+ dbusmenu_menuitem_property_set_bool(li->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
}
}
}
@@ -506,11 +579,21 @@ server_added (IndicateListener * listener, IndicateListenerServer * server, gcha
/* 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_SHORTCUTS_CHANGED, G_CALLBACK(server_shortcuts_changed), 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);
@@ -519,6 +602,50 @@ server_added (IndicateListener * listener, IndicateListenerServer * server, gcha
return;
}
+/* The shortcuts have changed, let's just remove them and put
+ the back. */
+static void
+server_shortcuts_changed (AppMenuItem * appitem, gpointer data)
+{
+ g_debug("Application Shortcuts changed");
+ DbusmenuMenuitem * shell = DBUSMENU_MENUITEM(data);
+ gboolean appitemfound = FALSE;
+ GList * children = dbusmenu_menuitem_get_children(shell);
+ GList * removelist = NULL;
+
+ while (children != NULL) {
+ if (!appitemfound && children->data != appitem) {
+ children = g_list_next(children);
+ continue;
+ }
+ appitemfound = TRUE;
+
+ if (!DBUSMENU_IS_MENUITEM_PROXY(children->data)) {
+ break;
+ }
+
+ removelist = g_list_prepend(removelist, children->data);
+ }
+
+ GList * removeitem;
+ for (removeitem = removelist; removeitem != NULL; removeitem = g_list_next(removeitem)) {
+ dbusmenu_menuitem_child_delete(shell, DBUSMENU_MENUITEM(removeitem->data));
+ }
+ g_list_free(removeitem);
+
+ GList * shortcuts = app_menu_item_get_items(appitem);
+ 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(shell, mi);
+ shortcuts = g_list_next(shortcuts);
+ }
+
+ resort_menu(shell);
+
+ 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
@@ -626,14 +753,14 @@ server_removed (IndicateListener * listener, IndicateListenerServer * server, gc
/* If there is a menu item, let's get rid of it. */
if (sltp->menuitem != NULL) {
- dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(sltp->menuitem), DBUSMENU_MENUITEM_PROP_VISIBLE, "false");
+ dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(sltp->menuitem), DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
dbusmenu_menuitem_child_delete(DBUSMENU_MENUITEM(data), DBUSMENU_MENUITEM(sltp->menuitem));
g_object_unref(G_OBJECT(sltp->menuitem));
}
/* If there is a separator, let's get rid of it. */
if (sltp->separator != NULL) {
- dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(sltp->separator), DBUSMENU_MENUITEM_PROP_VISIBLE, "false");
+ 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));
}
@@ -724,12 +851,21 @@ resort_menu (DbusmenuMenuitem * menushell)
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(li->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, "true");
+ dbusmenu_menuitem_property_set_bool(li->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
last_separator = li->separator;
}
position++;
@@ -746,6 +882,15 @@ resort_menu (DbusmenuMenuitem * menushell)
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
@@ -765,7 +910,7 @@ resort_menu (DbusmenuMenuitem * menushell)
if (si->separator != NULL) {
g_debug("\tMoving app %s separator to position %d", INDICATE_LISTENER_SERVER_DBUS_NAME(si->server), position);
dbusmenu_menuitem_child_reorder(DBUSMENU_MENUITEM(menushell), DBUSMENU_MENUITEM(si->separator), position);
- dbusmenu_menuitem_property_set(si->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, "true");
+ dbusmenu_menuitem_property_set_bool(si->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
position++;
last_separator = si->separator;
}
@@ -780,12 +925,21 @@ resort_menu (DbusmenuMenuitem * menushell)
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(li->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, "true");
+ dbusmenu_menuitem_property_set_bool(li->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
last_separator = li->separator;
}
position++;
@@ -794,7 +948,7 @@ resort_menu (DbusmenuMenuitem * menushell)
}
if (last_separator != NULL) {
- dbusmenu_menuitem_property_set(last_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, "false");
+ dbusmenu_menuitem_property_set_bool(last_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
} else {
g_warning("No last separator on resort");
}
@@ -953,7 +1107,7 @@ indicator_removed (IndicateListener * listener, IndicateListenerServer * server,
/* Hide the item immediately, and then remove it
which might take a little longer. */
- dbusmenu_menuitem_property_set(menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE, "false");
+ dbusmenu_menuitem_property_set_bool(menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
dbusmenu_menuitem_child_delete(DBUSMENU_MENUITEM(data), menuitem);
removed = TRUE;
}
@@ -981,7 +1135,11 @@ app_dir_changed (GFileMonitor * monitor, GFile * file, GFile * other_file, GFile
case G_FILE_MONITOR_EVENT_CREATED: {
gchar * path = g_file_get_path(file);
g_debug("\tCreate: %s", path);
- g_idle_add(build_launcher, path);
+ if (g_str_has_suffix(path, "keyfile")) {
+ g_idle_add(build_launcher_keyfile, path);
+ } else {
+ g_idle_add(build_launcher, path);
+ }
break;
}
default:
@@ -1010,7 +1168,7 @@ check_eclipses (AppMenuItem * ai)
if (!g_strcmp0(aidesktop, lidesktop)) {
launcher_menu_item_set_eclipsed(ll->menuitem, TRUE);
- dbusmenu_menuitem_property_set(ll->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, "false");
+ dbusmenu_menuitem_property_set_bool(ll->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
break;
}
}
@@ -1035,7 +1193,7 @@ remove_eclipses (AppMenuItem * ai)
if (!g_strcmp0(aidesktop, lidesktop)) {
launcher_menu_item_set_eclipsed(ll->menuitem, FALSE);
- dbusmenu_menuitem_property_set(ll->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, "true");
+ dbusmenu_menuitem_property_set_bool(ll->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
break;
}
}
@@ -1087,7 +1245,7 @@ destroy_launcher (gpointer data)
g_list_free(li->appdiritems);
if (li->menuitem != NULL) {
- dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(li->menuitem), DBUSMENU_MENUITEM_PROP_VISIBLE, "false");
+ 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;
@@ -1119,11 +1277,34 @@ build_launcher (gpointer data)
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), trimdesktop)) {
+ if (!g_strcmp0(launcher_menu_item_get_desktop(li->menuitem), desktop)) {
break;
}
}
@@ -1132,9 +1313,8 @@ build_launcher (gpointer data)
/* If not */
/* Build the item */
launcherList_t * ll = g_new0(launcherList_t, 1);
- ll->menuitem = launcher_menu_item_new(trimdesktop);
- g_free(trimdesktop);
- ll->appdiritems = g_list_append(NULL, path);
+ ll->menuitem = launcher_menu_item_new(desktop);
+ ll->appdiritems = g_list_append(NULL, g_strdup(desktop));
/* Build a separator */
ll->separator = dbusmenu_menuitem_new();
@@ -1145,6 +1325,11 @@ build_launcher (gpointer data)
/* Add it to the menu */
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
@@ -1152,7 +1337,7 @@ build_launcher (gpointer data)
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(ll->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, "false");
+ dbusmenu_menuitem_property_set_bool(ll->separator, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
}
resort_menu(root_menuitem);
@@ -1160,10 +1345,10 @@ build_launcher (gpointer data)
} else {
/* If so add ourselves */
launcherList_t * ll = (launcherList_t *)listitem->data;
- ll->appdiritems = g_list_append(ll->appdiritems, path);
+ ll->appdiritems = g_list_append(ll->appdiritems, g_strdup(desktop));
}
- return FALSE;
+ return;
}
/* This function goes through all the launchers that we're
@@ -1197,7 +1382,11 @@ build_launchers (gpointer data)
while ((filename = g_dir_read_name(dir)) != NULL) {
g_debug("Found file: %s", filename);
gchar * path = g_build_filename(directory, filename, NULL);
- g_idle_add(build_launcher, path);
+ 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);