aboutsummaryrefslogtreecommitdiff
path: root/src/app-indicator.c
diff options
context:
space:
mode:
authorMarco Trevisan (Treviño) <mail@3v1n0.net>2011-07-20 02:57:51 +0200
committerMarco Trevisan (Treviño) <mail@3v1n0.net>2011-07-20 02:57:51 +0200
commit8f71358509ec3e2a6e2fe633c4dfc07c58f450ed (patch)
tree84a92968fe93fb4cc422a1411cca63a3eef08e5b /src/app-indicator.c
parentd54d1e78545ee8cbeb7d3b0d276665290de7f296 (diff)
downloadlibayatana-appindicator-8f71358509ec3e2a6e2fe633c4dfc07c58f450ed.tar.gz
libayatana-appindicator-8f71358509ec3e2a6e2fe633c4dfc07c58f450ed.tar.bz2
libayatana-appindicator-8f71358509ec3e2a6e2fe633c4dfc07c58f450ed.zip
app-indicator: Move from "secondary-activate" signal to secondary_activate target
To avoid appindicators writers to use the "secondary-activate" event to perform actions that can't be done via a menu item we added a new API: - app_indicator_set_secondary_activate_target - app_indicator_get_secondary_activate_target With it, an appindicator writer can simply define a new GtkWidget that will be activated when a secondary activation will occur. The GtkWidget must be a sensitive and visible inner child of the appindicator MenuItem.
Diffstat (limited to 'src/app-indicator.c')
-rw-r--r--src/app-indicator.c150
1 files changed, 120 insertions, 30 deletions
diff --git a/src/app-indicator.c b/src/app-indicator.c
index 30e2e0a..1dc91d8 100644
--- a/src/app-indicator.c
+++ b/src/app-indicator.c
@@ -77,6 +77,8 @@ struct _AppIndicatorPrivate {
gchar *icon_theme_path;
DbusmenuServer *menuservice;
GtkWidget *menu;
+ GtkWidget *sec_activate_target;
+ gboolean sec_activate_enabled;
guint32 ordering_index;
gchar * label;
gchar * label_guide;
@@ -106,7 +108,6 @@ enum {
CONNECTION_CHANGED,
NEW_ICON_THEME_PATH,
SCROLL_EVENT,
- SECONDARY_ACTIVATE,
LAST_SIGNAL
};
@@ -187,6 +188,7 @@ static void unfallback (AppIndicator * self, GtkStatusIcon * status_icon);
static gchar * append_panel_icon_suffix (const gchar * icon_name);
static void watcher_owner_changed (GObject * obj, GParamSpec * pspec, gpointer user_data);
static void theme_changed_cb (GtkIconTheme * theme, gpointer user_data);
+static void sec_activate_target_parent_changed(GtkWidget *menuitem, GtkWidget *old_parent, gpointer user_data);
static GVariant * bus_get_prop (GDBusConnection * connection, const gchar * sender, const gchar * path, const gchar * interface, const gchar * property, GError ** error, gpointer user_data);
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 void bus_creation (GObject * obj, GAsyncResult * res, gpointer user_data);
@@ -520,23 +522,6 @@ app_indicator_class_init (AppIndicatorClass *klass)
_application_service_marshal_VOID__INT_UINT,
G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_UINT);
- /**
- AppIndicator::secondary-activate:
- @arg0: The #AppIndicator object
- @arg1: The x pointer position of the secondary activation
- @arg2: The y pointer position of the secondary activation
-
- Signaled when the #AppIndicator receives a secondary activate event
- (i.e. a middle-click over the #AppIndicator icon/label).
- */
- signals[SECONDARY_ACTIVATE] = g_signal_new (APP_INDICATOR_SIGNAL_SECONDARY_ACTIVATE,
- G_TYPE_FROM_CLASS(klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (AppIndicatorClass, secondary_activate),
- NULL, NULL,
- _application_service_marshal_VOID__INT_INT,
- G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
-
/* DBus interfaces */
if (item_node_info == NULL) {
GError * error = NULL;
@@ -606,6 +591,9 @@ app_indicator_init (AppIndicator *self)
priv->shorties = NULL;
+ priv->sec_activate_target = NULL;
+ priv->sec_activate_enabled = FALSE;
+
/* Start getting the session bus */
g_object_ref(self); /* ref for the bus creation callback */
g_bus_get(G_BUS_TYPE_SESSION, NULL, bus_creation, self);
@@ -681,6 +669,12 @@ app_indicator_dispose (GObject *object)
priv->connection = NULL;
}
+ if (priv->sec_activate_target != NULL) {
+ g_signal_handlers_disconnect_by_func (priv->sec_activate_target, sec_activate_target_parent_changed, self);
+ g_object_unref(G_OBJECT(priv->sec_activate_target));
+ priv->sec_activate_target = NULL;
+ }
+
g_signal_handlers_disconnect_by_func(gtk_icon_theme_get_default(), G_CALLBACK(theme_changed_cb), self);
G_OBJECT_CLASS (app_indicator_parent_class)->dispose (object);
@@ -1008,6 +1002,7 @@ bus_method_call (GDBusConnection * connection, const gchar * sender,
g_return_if_fail(IS_APP_INDICATOR(user_data));
AppIndicator * app = APP_INDICATOR(user_data);
+ AppIndicatorPrivate * priv = app->priv;
GVariant * retval = NULL;
if (g_strcmp0(method, "Scroll") == 0) {
@@ -1030,10 +1025,14 @@ bus_method_call (GDBusConnection * connection, const gchar * sender,
g_signal_emit(app, signals[SCROLL_EVENT], 0, delta, direction);
} else if (g_strcmp0(method, "SecondaryActivate") == 0) {
- gint x, y;
-
- g_variant_get(params, "(ii)", &x, &y);
- g_signal_emit(app, signals[SECONDARY_ACTIVATE], 0, x, y);
+ GtkWidget *menuitem = priv->sec_activate_target;
+
+ if (priv->sec_activate_enabled && menuitem &&
+ gtk_widget_get_visible (menuitem) &&
+ gtk_widget_get_sensitive (menuitem))
+ {
+ gtk_widget_activate (menuitem);
+ }
} else {
g_warning("Calling method '%s' on the app-indicator and it's unknown", method);
}
@@ -1495,19 +1494,21 @@ middle_click_wrapper (GtkWidget *status_icon, GdkEventButton *event, gpointer da
{
g_return_val_if_fail(IS_APP_INDICATOR(data), FALSE);
AppIndicator * app = APP_INDICATOR(data);
+ AppIndicatorPrivate *priv = app->priv;
if (event->button == 2 && event->type == GDK_BUTTON_RELEASE) {
GtkAllocation alloc;
gint px = event->x;
gint py = event->y;
gtk_widget_get_allocation (status_icon, &alloc);
-
- if (px >= 0 && px < alloc.width && py >= 0 && py < alloc.height) {
- gint wx, wy;
- gdk_window_get_origin(event->window, &wx, &wy);
-
- g_signal_emit(app, signals[SECONDARY_ACTIVATE], wx+px, wy+py);
-
+ GtkWidget *menuitem = priv->sec_activate_target;
+
+ if (px >= 0 && px < alloc.width && py >= 0 && py < alloc.height &&
+ priv->sec_activate_enabled && menuitem &&
+ gtk_widget_get_visible (menuitem) &&
+ gtk_widget_get_sensitive (menuitem))
+ {
+ gtk_widget_activate (menuitem);
return TRUE;
}
}
@@ -1607,6 +1608,38 @@ append_panel_icon_suffix (const gchar *icon_name)
return long_name;
}
+static gboolean
+widget_is_menu_child(AppIndicator * self, GtkWidget *child)
+{
+ g_return_val_if_fail(IS_APP_INDICATOR(self), FALSE);
+
+ if (!self->priv->menu) return FALSE;
+ if (!child) return FALSE;
+
+ GtkWidget *parent;
+
+ while ((parent = gtk_widget_get_parent(child))) {
+ if (parent == self->priv->menu)
+ return TRUE;
+
+ if (GTK_IS_MENU(parent))
+ child = gtk_menu_get_attach_widget(GTK_MENU(parent));
+ else
+ child = parent;
+ }
+
+ return FALSE;
+}
+
+static void
+sec_activate_target_parent_changed(GtkWidget *menuitem, GtkWidget *old_parent,
+ gpointer data)
+{
+ g_return_if_fail(IS_APP_INDICATOR(data));
+ AppIndicator *self = data;
+ self->priv->sec_activate_enabled = widget_is_menu_child(self, menuitem);
+}
+
/* ************************* */
/* Public Functions */
@@ -1996,6 +2029,8 @@ app_indicator_set_menu (AppIndicator *self, GtkMenu *menu)
setup_dbusmenu (self);
+ priv->sec_activate_enabled = widget_is_menu_child (self, priv->sec_activate_target);
+
check_connect (self);
return;
@@ -2023,6 +2058,45 @@ app_indicator_set_ordering_index (AppIndicator *self, guint32 ordering_index)
}
/**
+ app_indicator_set_secondary_activate_target:
+ @self: The #AppIndicator
+ @menuitem: A #GtkWidget to be activated on secondary activation
+
+ Set the @menuitem to be activated when a secondary activation event (i.e. a
+ middle-click) is emitted over the #AppIndicator icon/label.
+
+ The @menuitem can be also a complex #GtkWidget, but to get activated when
+ a secondary activation occurs in the #Appindicator, it must be a visible and
+ active child (or inner-child) of the #AppIndicator:menu.
+
+ Setting @menuitem to %NULL causes to disable this feature.
+**/
+void
+app_indicator_set_secondary_activate_target (AppIndicator *self, GtkWidget *menuitem)
+{
+ g_return_if_fail (IS_APP_INDICATOR (self));
+ AppIndicatorPrivate *priv = self->priv;
+
+ if (menuitem == NULL) {
+ if (priv->sec_activate_target) {
+ g_object_unref(G_OBJECT(priv->sec_activate_target));
+ g_signal_handlers_disconnect_by_func (priv->sec_activate_target,
+ sec_activate_target_parent_changed,
+ self);
+ priv->sec_activate_target = NULL;
+ }
+
+ return;
+ }
+
+ g_return_if_fail (GTK_IS_WIDGET (menuitem));
+
+ priv->sec_activate_target = g_object_ref(G_OBJECT(menuitem));
+ priv->sec_activate_enabled = widget_is_menu_child(self, menuitem);
+ g_signal_connect(menuitem, "parent-set", G_CALLBACK(sec_activate_target_parent_changed), self);
+}
+
+/**
app_indicator_get_id:
@self: The #AppIndicator object to use
@@ -2157,7 +2231,7 @@ app_indicator_get_attention_icon_desc (AppIndicator *self)
Gets the menu being used for this application indicator.
Wrapper function for property #AppIndicator:menu.
- Return value: (transfer none): A #GtkMenu object or %NULL if one hasn't been set.
+ Return value: (transfer full): A #GtkMenu object or %NULL if one hasn't been set.
*/
GtkMenu *
app_indicator_get_menu (AppIndicator *self)
@@ -2223,6 +2297,22 @@ app_indicator_get_ordering_index (AppIndicator *self)
}
}
+/**
+ app_indicator_get_secondary_activate_target:
+ @self: The #AppIndicator object to use
+
+ Gets the menuitem being called on secondary-activate event.
+
+ Return value: (transfer full): A #GtkWidget object or %NULL if none has been set.
+*/
+GtkWidget *
+app_indicator_get_secondary_activate_target (AppIndicator *self)
+{
+ g_return_val_if_fail (IS_APP_INDICATOR (self), NULL);
+
+ return GTK_WIDGET(self->priv->sec_activate_target);
+}
+
#define APP_INDICATOR_SHORTY_NICK "app-indicator-shorty-nick"
/* Callback when an item from the desktop shortcuts gets