summaryrefslogtreecommitdiff
path: root/services
diff options
Diffstat (limited to 'services')
-rw-r--r--services/CMakeLists.txt2
-rw-r--r--services/panel-main.c33
-rw-r--r--services/panel-service.c212
-rw-r--r--services/panel-service.h11
4 files changed, 189 insertions, 69 deletions
diff --git a/services/CMakeLists.txt b/services/CMakeLists.txt
index 286b9cc1f..a1dc073f8 100644
--- a/services/CMakeLists.txt
+++ b/services/CMakeLists.txt
@@ -2,7 +2,7 @@
# Panel Service
#
find_package(PkgConfig)
-pkg_check_modules(SERVICE_DEPS REQUIRED gtk+-3.0>=3.3 gobject-2.0 gio-2.0 gthread-2.0 indicator3-0.4 x11 gconf-2.0)
+pkg_check_modules(SERVICE_DEPS REQUIRED gtk+-3.0>=3.3 gobject-2.0 gio-2.0 gthread-2.0 indicator3-0.4=>0.4.90 x11 gconf-2.0)
execute_process (COMMAND ${PKG_CONFIG_EXECUTABLE} indicator3-0.4 --variable indicatordir OUTPUT_VARIABLE _indicatordir OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process (COMMAND ${PKG_CONFIG_EXECUTABLE} indicator3-0.4 --variable iconsdir OUTPUT_VARIABLE _iconsdir OUTPUT_STRIP_TRAILING_WHITESPACE)
diff --git a/services/panel-main.c b/services/panel-main.c
index 317cf6c24..7a770b0c7 100644
--- a/services/panel-main.c
+++ b/services/panel-main.c
@@ -58,13 +58,21 @@ static const gchar introspection_xml[] =
" <method name='SyncGeometries'>"
" <arg type='a(ssiiii)' name='geometries' direction='in'/>"
" </method>"
- ""
+ ""
" <method name='ShowEntry'>"
" <arg type='s' name='entry_id' direction='in'/>"
+ " <arg type='u' name='xid' direction='in'/>"
+ " <arg type='i' name='x' direction='in'/>"
+ " <arg type='i' name='y' direction='in'/>"
+ " <arg type='u' name='button' direction='in'/>"
" <arg type='u' name='timestamp' direction='in'/>"
+ " </method>"
+ ""
+ " <method name='ShowAppMenu'>"
+ " <arg type='u' name='xid' direction='in'/>"
" <arg type='i' name='x' direction='in'/>"
" <arg type='i' name='y' direction='in'/>"
- " <arg type='i' name='button' direction='in'/>"
+ " <arg type='u' name='timestamp' direction='in'/>"
" </method>"
""
" <method name='SecondaryActivateEntry'>"
@@ -174,18 +182,31 @@ handle_method_call (GDBusConnection *connection,
}
else if (g_strcmp0 (method_name, "ShowEntry") == 0)
{
+ guint32 xid;
gchar *entry_id;
- guint32 timestamp;
gint32 x;
gint32 y;
- gint32 button;
- g_variant_get (parameters, "(suiii)", &entry_id, &timestamp, &x, &y, &button, NULL);
+ guint32 button;
+ guint32 timestamp;
+ g_variant_get (parameters, "(suiiuu)", &entry_id, &xid, &x, &y, &button, &timestamp, NULL);
- panel_service_show_entry (service, entry_id, timestamp, x, y, button);
+ panel_service_show_entry (service, entry_id, xid, x, y, button, timestamp);
g_dbus_method_invocation_return_value (invocation, NULL);
g_free (entry_id);
}
+ else if (g_strcmp0 (method_name, "ShowAppMenu") == 0)
+ {
+ guint32 xid;
+ gint32 x;
+ gint32 y;
+ guint32 timestamp;
+ g_variant_get (parameters, "(uiiu)", &xid, &x, &y, &timestamp, NULL);
+
+ panel_service_show_app_menu (service, xid, x, y, timestamp);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ }
else if (g_strcmp0 (method_name, "SecondaryActivateEntry") == 0)
{
gchar *entry_id;
diff --git a/services/panel-service.c b/services/panel-service.c
index d3a0e59b4..cbd8368ad 100644
--- a/services/panel-service.c
+++ b/services/panel-service.c
@@ -27,6 +27,7 @@
#include "panel-service.h"
#include <stdlib.h>
+#include <fcntl.h>
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
@@ -49,7 +50,6 @@ static PanelService *static_service = NULL;
struct _PanelServicePrivate
{
GSList *indicators;
- GHashTable *entry2indicator_hash;
GHashTable *panel2entries_hash;
guint initial_sync_id;
@@ -121,6 +121,7 @@ static void sort_indicators (PanelService *self);
static void notify_object (IndicatorObject *object);
static IndicatorObjectEntry *get_entry_at (PanelService *self, gint x, gint y);
+static IndicatorObject *get_entry_parent_indicator (IndicatorObjectEntry *entry);
static GdkFilterReturn event_filter (GdkXEvent *ev,
GdkEvent *gev,
@@ -136,7 +137,6 @@ panel_service_class_dispose (GObject *object)
PanelServicePrivate *priv = PANEL_SERVICE (object)->priv;
gint i;
- g_hash_table_destroy (priv->entry2indicator_hash);
g_hash_table_destroy (priv->panel2entries_hash);
gdk_window_remove_filter (NULL, (GdkFilterFunc)event_filter, object);
@@ -301,7 +301,7 @@ event_filter (GdkXEvent *ev, GdkEvent *gev, PanelService *self)
{
/* Middle clicks over an appmenu entry are considered just like
* all other clicks */
- IndicatorObject *obj = g_hash_table_lookup (priv->entry2indicator_hash, entry);
+ IndicatorObject *obj = get_entry_parent_indicator (entry);
if (g_strcmp0 (g_object_get_data (G_OBJECT (obj), "id"), "libappmenu.so") == 0)
{
@@ -392,30 +392,59 @@ get_entry_at (PanelService *self, gint x, gint y)
return NULL;
}
-static void
-panel_service_get_indicator_entry_by_id (PanelService *self,
- const gchar *entry_id,
- IndicatorObjectEntry **entry,
- IndicatorObject **object)
+static IndicatorObject *
+get_entry_parent_indicator (IndicatorObjectEntry *entry)
{
- IndicatorObject *indicator;
- IndicatorObjectEntry *probably_entry;
- PanelServicePrivate *priv = self->priv;
+ if (!entry || !INDICATOR_IS_OBJECT (entry->parent_object))
+ return NULL;
- /* FIXME: eeek, why do we even do this? */
- if (sscanf (entry_id, "%p", &probably_entry) == 1)
- {
- /* check that there really is such IndicatorObjectEntry */
- indicator = g_hash_table_lookup (priv->entry2indicator_hash,
- probably_entry);
- if (object) *object = indicator;
- if (entry) *entry = indicator != NULL ? probably_entry : NULL;
- }
- else
+ return INDICATOR_OBJECT (entry->parent_object);
+}
+
+static IndicatorObjectEntry *
+get_indicator_entry_by_id (const gchar *entry_id)
+{
+ IndicatorObjectEntry *entry;
+ entry = NULL;
+
+ if (sscanf (entry_id, "%p", &entry) == 1)
{
- if (object) *object = NULL;
- if (entry) *entry = NULL;
+ /* Checking that entry is really an IndicatorObjectEntry.
+ * To do that, we use an hack that allows to check if the pointer we read is
+ * actually a valid pointer without crashing. This can be done using the
+ * low-level write function to read from the pointer to a valid fds (we use
+ * a pipe for convenience). Write will fail without crashing if we try to
+ * read from an invalid pointer, so we can finally be pretty sure if the
+ * pointed entry is an IndicatorObjectEntry by checking if it has a valid
+ * parent IndicatorObject */
+
+ int fds[2];
+
+ if (pipe (fds) > -1)
+ {
+ size_t data_size = sizeof (IndicatorObjectEntry);
+
+ if (write (fds[1], entry, data_size) != data_size)
+ {
+ entry = NULL;
+ }
+ else
+ {
+ data_size = sizeof (IndicatorObject*);
+
+ if (write (fds[1], entry->parent_object, data_size) != data_size ||
+ !INDICATOR_IS_OBJECT (entry->parent_object))
+ {
+ entry = NULL;
+ }
+ }
+
+ close (fds[0]);
+ close (fds[1]);
+ }
}
+
+ return entry;
}
static gboolean
@@ -441,7 +470,6 @@ panel_service_init (PanelService *self)
gdk_window_add_filter (NULL, (GdkFilterFunc)event_filter, self);
- priv->entry2indicator_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
priv->panel2entries_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free,
(GDestroyNotify) g_hash_table_destroy);
@@ -480,8 +508,6 @@ panel_service_actually_remove_indicator (PanelService *self, IndicatorObject *in
{
for (l = entries; l; l = l->next)
{
- g_hash_table_remove (self->priv->entry2indicator_hash, l->data);
-
GHashTableIter iter;
gpointer key, value;
g_hash_table_iter_init (&iter, self->priv->panel2entries_hash);
@@ -694,13 +720,8 @@ on_entry_added (IndicatorObject *object,
IndicatorObjectEntry *entry,
PanelService *self)
{
- PanelServicePrivate *priv;
-
g_return_if_fail (PANEL_IS_SERVICE (self));
g_return_if_fail (entry != NULL);
- priv = self->priv;
-
- g_hash_table_insert (priv->entry2indicator_hash, entry, object);
if (GTK_IS_LABEL (entry->label))
{
@@ -747,13 +768,9 @@ on_entry_removed (IndicatorObject *object,
IndicatorObjectEntry *entry,
PanelService *self)
{
- PanelServicePrivate *priv;
g_return_if_fail (PANEL_IS_SERVICE (self));
g_return_if_fail (entry != NULL);
- priv = self->priv;
-
- g_hash_table_remove (priv->entry2indicator_hash, entry);
/* Don't remove here the value from priv->panel2entries_hash, this should
* be done in during the sync, to avoid false positive.
* FIXME this in libappmenu.so to avoid to send an "entry-removed" signal
@@ -1225,15 +1242,29 @@ panel_service_sync_geometry (PanelService *self,
{
IndicatorObject *object;
IndicatorObjectEntry *entry;
+ gboolean valid_entry = TRUE;
PanelServicePrivate *priv = self->priv;
- panel_service_get_indicator_entry_by_id (self, entry_id, &entry, &object);
+ entry = get_indicator_entry_by_id (entry_id);
+
+ /* If the entry we read is not valid, maybe it has already been removed
+ * or unparented, so we need to make sure that the related key on the
+ * entry2geometry_hash is correctly removed and the value is free'd */
+ if (!entry)
+ {
+ IndicatorObjectEntry *invalid_entry;
+ if (sscanf (entry_id, "%p", &invalid_entry) == 1)
+ {
+ entry = invalid_entry;
+ valid_entry = FALSE;
+ }
+ }
if (entry)
{
GHashTable *entry2geometry_hash = g_hash_table_lookup (priv->panel2entries_hash, panel_id);
- if (width < 0 || height < 0)
+ if (width < 0 || height < 0 || !valid_entry)
{
if (entry2geometry_hash)
{
@@ -1253,11 +1284,8 @@ panel_service_sync_geometry (PanelService *self,
if (entry2geometry_hash == NULL)
{
- //FIXME - this leaks memory but i'm not 100% on the logic,
- // using g_free as the keys destructor function causes all
- // kinds of problems
entry2geometry_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal,
- NULL, g_free);
+ NULL, g_free);
g_hash_table_insert (priv->panel2entries_hash, g_strdup (panel_id),
entry2geometry_hash);
}
@@ -1278,7 +1306,11 @@ panel_service_sync_geometry (PanelService *self,
geo->height = height;
}
- g_signal_emit (self, _service_signals[GEOMETRIES_CHANGED], 0, object, entry, x, y, width, height);
+ if (valid_entry)
+ {
+ object = get_entry_parent_indicator (entry);
+ g_signal_emit (self, _service_signals[GEOMETRIES_CHANGED], 0, object, entry, x, y, width, height);
+ }
}
}
@@ -1432,7 +1464,7 @@ on_active_menu_move_current (GtkMenu *menu,
}
/* Find the next/prev indicator */
- object = g_hash_table_lookup (priv->entry2indicator_hash, priv->last_entry);
+ object = get_entry_parent_indicator(priv->last_entry);
if (object == NULL)
{
g_warning ("Unable to find IndicatorObject for entry");
@@ -1449,23 +1481,25 @@ menu_deactivated (GtkWidget *menu)
gtk_widget_destroy (menu);
}
-void
-panel_service_show_entry (PanelService *self,
- const gchar *entry_id,
- guint32 timestamp,
- gint32 x,
- gint32 y,
- gint32 button)
+static void
+panel_service_actually_show_entry (PanelService *self,
+ IndicatorObject *object,
+ IndicatorObjectEntry *entry,
+ guint32 xid,
+ gint32 x,
+ gint32 y,
+ guint32 button,
+ guint32 timestamp)
{
- IndicatorObject *object;
- IndicatorObjectEntry *entry;
- GtkWidget *last_menu;
- PanelServicePrivate *priv = self->priv;
-
- panel_service_get_indicator_entry_by_id (self, entry_id, &entry, &object);
+ PanelServicePrivate *priv;
+ GtkWidget *last_menu;
+ g_return_if_fail (PANEL_IS_SERVICE (self));
+ g_return_if_fail (INDICATOR_IS_OBJECT (object));
g_return_if_fail (entry);
+ priv = self->priv;
+
if (priv->last_entry == entry)
return;
@@ -1488,7 +1522,18 @@ panel_service_show_entry (PanelService *self,
if (entry != NULL)
{
+ gchar *entry_id = g_strdup_printf ("%p", entry);
g_signal_emit (self, _service_signals[ENTRY_ACTIVATED], 0, entry_id);
+ g_free (entry_id);
+
+ if (xid > 0)
+ {
+ indicator_object_entry_activate_window (object, entry, xid, CurrentTime);
+ }
+ else
+ {
+ indicator_object_entry_activate (object, entry, CurrentTime);
+ }
if (GTK_IS_MENU (entry->menu))
{
@@ -1525,8 +1570,6 @@ panel_service_show_entry (PanelService *self,
priv->last_menu_move_id = g_signal_connect_after (priv->last_menu, "move-current",
G_CALLBACK (on_active_menu_move_current), self);
- indicator_object_entry_activate (object, entry, CurrentTime);
-
gtk_menu_popup (priv->last_menu, NULL, NULL, positon_menu, self, 0, CurrentTime);
GdkWindow *gdkwin = gtk_widget_get_window (GTK_WIDGET (priv->last_menu));
if (gdkwin != NULL)
@@ -1559,6 +1602,53 @@ panel_service_show_entry (PanelService *self,
}
void
+panel_service_show_entry (PanelService *self,
+ const gchar *entry_id,
+ guint32 xid,
+ gint32 x,
+ gint32 y,
+ guint32 button,
+ guint32 timestamp)
+{
+ IndicatorObject *object;
+ IndicatorObjectEntry *entry;
+
+ g_return_if_fail (PANEL_IS_SERVICE (self));
+
+ entry = get_indicator_entry_by_id (entry_id);
+ object = get_entry_parent_indicator (entry);
+
+ panel_service_actually_show_entry (self, object, entry, xid, x, y, button, timestamp);
+}
+
+void
+panel_service_show_app_menu (PanelService *self,
+ guint32 xid,
+ gint32 x,
+ gint32 y,
+ guint32 timestamp)
+{
+ IndicatorObject *object;
+ IndicatorObjectEntry *entry;
+ GList *entries;
+
+ g_return_if_fail (PANEL_IS_SERVICE (self));
+
+ object = panel_service_get_indicator (self, "libappmenu.so");
+ g_return_if_fail (INDICATOR_IS_OBJECT (object));
+
+ entries = indicator_object_get_entries (object);
+
+ if (entries)
+ {
+ entry = entries->data;
+ g_list_free (entries);
+
+ panel_service_actually_show_entry (self, object, entry, xid, x, y, 1, timestamp);
+ }
+}
+
+void
panel_service_secondary_activate_entry (PanelService *self,
const gchar *entry_id,
guint32 timestamp)
@@ -1566,9 +1656,10 @@ panel_service_secondary_activate_entry (PanelService *self,
IndicatorObject *object;
IndicatorObjectEntry *entry;
- panel_service_get_indicator_entry_by_id (self, entry_id, &entry, &object);
+ entry = get_indicator_entry_by_id (entry_id);
g_return_if_fail (entry);
+ object = get_entry_parent_indicator (entry);
g_signal_emit_by_name(object, INDICATOR_OBJECT_SIGNAL_SECONDARY_ACTIVATE, entry,
timestamp);
}
@@ -1581,11 +1672,12 @@ panel_service_scroll_entry (PanelService *self,
IndicatorObject *object;
IndicatorObjectEntry *entry;
- panel_service_get_indicator_entry_by_id (self, entry_id, &entry, &object);
+ entry = get_indicator_entry_by_id (entry_id);
g_return_if_fail (entry);
GdkScrollDirection direction = delta < 0 ? GDK_SCROLL_DOWN : GDK_SCROLL_UP;
+ object = get_entry_parent_indicator (entry);
g_signal_emit_by_name(object, INDICATOR_OBJECT_SIGNAL_ENTRY_SCROLLED, entry,
abs(delta/120), direction);
}
diff --git a/services/panel-service.h b/services/panel-service.h
index 861a67cf7..b7514f04b 100644
--- a/services/panel-service.h
+++ b/services/panel-service.h
@@ -95,10 +95,17 @@ void panel_service_sync_geometry (PanelService *self,
void panel_service_show_entry (PanelService *self,
const gchar *entry_id,
- guint32 timestamp,
+ guint32 xid,
gint32 x,
gint32 y,
- gint32 button);
+ guint32 button,
+ guint32 timestamp);
+
+void panel_service_show_app_menu (PanelService *self,
+ guint32 xid,
+ gint32 x,
+ gint32 y,
+ guint32 timestamp);
void panel_service_secondary_activate_entry (PanelService *self,
const gchar *entry_id,