diff options
Diffstat (limited to 'services')
| -rw-r--r-- | services/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | services/panel-main.c | 33 | ||||
| -rw-r--r-- | services/panel-service.c | 212 | ||||
| -rw-r--r-- | services/panel-service.h | 11 |
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, ×tamp, &x, &y, &button, NULL); + guint32 button; + guint32 timestamp; + g_variant_get (parameters, "(suiiuu)", &entry_id, &xid, &x, &y, &button, ×tamp, 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, ×tamp, 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, |
