[Xfce4-commits] <xfce4-clipman-plugin:master> Fix popup from keyboard shortcut not always working #bug 5909

Mike Massonnet noreply at xfce.org
Sun Nov 1 02:46:01 CET 2009


Updating branch refs/heads/master
         to 5a06e78aabb5e76fb732424ca4402323f0c83a71 (commit)
       from f4923bc34b4d123a973f6b5354ae93c880bf481b (commit)

commit 5a06e78aabb5e76fb732424ca4402323f0c83a71
Author: Mike Massonnet <mmassonnet at gmail.com>
Date:   Sat Oct 31 17:37:04 2009 +0100

    Fix popup from keyboard shortcut not always working #bug 5909

 ChangeLog                        |    9 +++
 panel-plugin/main-panel-plugin.c |   32 +++++++-----
 panel-plugin/main-status-icon.c  |    8 ++--
 panel-plugin/plugin.c            |  103 +++++++++++++++++++++++++++++++++-----
 panel-plugin/plugin.h            |    6 ++-
 5 files changed, 125 insertions(+), 33 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index d5d17cd..00f5597 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2009-10-31	Mike Massonnet
+Fix popup from keyboard shortcut not always working #bug 5909
+
+	Factorize the popup action inside plugin.c(plugin_popup_menu) and add
+	a menu position function callback pointer within the MyPlugin
+	structure.
+	Add workaround from xfdesktop for the popup action called through a
+	keyboard shortcut.
+
 2009-09-30	Mike Massonnet
 === Release 1.1.1 ===
 
diff --git a/panel-plugin/main-panel-plugin.c b/panel-plugin/main-panel-plugin.c
index c3941c7..6ca334a 100644
--- a/panel-plugin/main-panel-plugin.c
+++ b/panel-plugin/main-panel-plugin.c
@@ -42,7 +42,8 @@ XFCE_PANEL_PLUGIN_REGISTER_EXTERNAL (panel_plugin_register);
 
 static gboolean         panel_plugin_set_size           (MyPlugin *plugin,
                                                          gint size);
-static void             cb_button_toggled               (GtkToggleButton *button,
+static gboolean         cb_button_pressed               (GtkButton *button,
+                                                         GdkEventButton *event,
                                                          MyPlugin *plugin);
 static void             cb_menu_deactivate              (GtkMenuShell *menu,
                                                          MyPlugin *plugin);
@@ -63,6 +64,9 @@ panel_plugin_register (XfcePanelPlugin *panel_plugin)
 {
   MyPlugin *plugin = plugin_register ();
 
+  /* Menu Position Func */
+  plugin->menu_position_func = (GtkMenuPositionFunc)my_plugin_position_menu;
+
   /* Panel Plugin */
   plugin->panel_plugin = panel_plugin;
 #if GTK_CHECK_VERSION (2,12,0)
@@ -76,8 +80,8 @@ panel_plugin_register (XfcePanelPlugin *panel_plugin)
   gtk_container_add (GTK_CONTAINER (plugin->button), plugin->image);
   gtk_container_add (GTK_CONTAINER (panel_plugin), plugin->button);
   xfce_panel_plugin_add_action_widget (panel_plugin, plugin->button);
-  g_signal_connect (plugin->button, "toggled",
-                    G_CALLBACK (cb_button_toggled), plugin);
+  g_signal_connect (plugin->button, "button-press-event",
+                    G_CALLBACK (cb_button_pressed), plugin);
 
   /* Signals */
   g_signal_connect_swapped (panel_plugin, "size-changed",
@@ -115,18 +119,18 @@ panel_plugin_set_size (MyPlugin *plugin,
   return TRUE;
 }
 
-static void
-cb_button_toggled (GtkToggleButton *button,
+static gboolean
+cb_button_pressed (GtkButton *button,
+                   GdkEventButton *event,
                    MyPlugin *plugin)
 {
-  if (gtk_toggle_button_get_active (button))
-    {
-      gtk_menu_set_screen (GTK_MENU (plugin->menu), gtk_widget_get_screen (plugin->button));
-      xfce_panel_plugin_register_menu (plugin->panel_plugin, GTK_MENU (plugin->menu));
-      gtk_menu_popup (GTK_MENU (plugin->menu), NULL, NULL,
-                      (GtkMenuPositionFunc)my_plugin_position_menu, plugin,
-                      0, gtk_get_current_event_time ());
-    }
+  if (event->button != 1 && !(event->state & GDK_CONTROL_MASK))
+    return FALSE;
+
+  if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)))
+    plugin_popup_menu (plugin);
+
+  return TRUE;
 }
 
 static void
@@ -150,7 +154,7 @@ my_plugin_position_menu (GtkMenu *menu,
   button = plugin->button;
   orientation = xfce_panel_plugin_get_orientation (plugin->panel_plugin);
   gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
-  gdk_window_get_origin (button->window, x, y);
+  gdk_window_get_origin (GTK_WIDGET (plugin->panel_plugin)->window, x, y);
 
   switch (orientation)
     {
diff --git a/panel-plugin/main-status-icon.c b/panel-plugin/main-status-icon.c
index d1f28e9..9a8db73 100644
--- a/panel-plugin/main-status-icon.c
+++ b/panel-plugin/main-status-icon.c
@@ -80,6 +80,9 @@ status_icon_register ()
 {
   MyPlugin *plugin = plugin_register ();
 
+  /* Menu Position Func */
+  plugin->menu_position_func = (GtkMenuPositionFunc)gtk_status_icon_position_menu;
+
   /* Status Icon */
   plugin->status_icon = gtk_status_icon_new_from_stock (GTK_STOCK_PASTE);
   gtk_status_icon_set_tooltip (plugin->status_icon, _("Clipman"));
@@ -110,10 +113,7 @@ cb_status_icon_is_embedded (GtkStatusIcon *status_icon)
 static void
 cb_status_icon_activate (MyPlugin *plugin)
 {
-  gtk_menu_set_screen (GTK_MENU (plugin->menu), gtk_status_icon_get_screen (plugin->status_icon));
-  gtk_menu_popup (GTK_MENU (plugin->menu), NULL, NULL,
-                  (GtkMenuPositionFunc)gtk_status_icon_position_menu, plugin->status_icon,
-                  0, gtk_get_current_event_time ());
+  plugin_popup_menu (plugin);
 }
 
 static void
diff --git a/panel-plugin/plugin.c b/panel-plugin/plugin.c
index b3f7f2d..56387d2 100644
--- a/panel-plugin/plugin.c
+++ b/panel-plugin/plugin.c
@@ -38,12 +38,14 @@
 #include "menu.h"
 
 /*
- * X11 Selection for the popup command
+ * Popup command
  */
 
 static gboolean         my_plugin_set_popup_selection   (MyPlugin *plugin);
 static gboolean         cb_popup_message_received       (MyPlugin *plugin,
                                                          GdkEventClient *ev);
+static gboolean         xfce_popup_grab_available       (GdkWindow *win,
+                                                         guint32 timestamp);
 
 
 
@@ -331,6 +333,27 @@ plugin_configure (MyPlugin *plugin)
   }
 }
 
+void
+plugin_popup_menu (MyPlugin *plugin)
+{
+#ifdef PANEL_PLUGIN
+  gtk_menu_set_screen (GTK_MENU (plugin->menu), gtk_widget_get_screen (plugin->button));
+  gtk_menu_popup (GTK_MENU (plugin->menu), NULL, NULL,
+                  plugin->menu_position_func, plugin,
+                  0, gtk_get_current_event_time ());
+  if (gtk_grab_get_current () == plugin->menu)
+    {
+      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (plugin->button), TRUE);
+      xfce_panel_plugin_register_menu (plugin->panel_plugin, GTK_MENU (plugin->menu));
+    }
+#elif STATUS_ICON
+  gtk_menu_set_screen (GTK_MENU (plugin->menu), gtk_status_icon_get_screen (plugin->status_icon));
+  gtk_menu_popup (GTK_MENU (plugin->menu), NULL, NULL,
+                  plugin->menu_position_func, plugin->status_icon,
+                  0, gtk_get_current_event_time ());
+#endif
+}
+
 /*
  * X11 Selection for the popup command
  */
@@ -372,26 +395,80 @@ static gboolean
 cb_popup_message_received (MyPlugin *plugin,
                            GdkEventClient *ev)
 {
+  {
+    /* Copy workaround from xfdesktop to handle the awkward case where binding
+     * a keyboard shortcut to the popup command doesn't always work out... */
+#ifdef PANEL_PLUGIN
+    GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (plugin->button));
+#elif STATUS_ICON
+    GdkScreen *screen = gtk_status_icon_get_screen (plugin->status_icon);
+#endif
+    GdkWindow *root = gdk_screen_get_root_window (screen);
+    if (!xfce_popup_grab_available (root, GDK_CURRENT_TIME))
+      {
+        g_critical ("Unable to get keyboard/mouse grab.");
+        return FALSE;
+      }
+  }
+
   if (G_LIKELY (ev->data_format == 8 && *(ev->data.b) != '\0'))
     {
       if (!g_ascii_strcasecmp (XFCE_CLIPMAN_MESSAGE, ev->data.b))
         {
           DBG ("Message received: %s", ev->data.b);
-
-#ifdef PANEL_PLUGIN
-          xfce_panel_plugin_set_panel_hidden (plugin->panel_plugin, FALSE);
-#endif
-          while (gtk_events_pending ())
-            gtk_main_iteration ();
-
-#ifdef PANEL_PLUGIN
-          gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (plugin->button), TRUE);
-#elif STATUS_ICON
-          g_signal_emit_by_name (plugin->status_icon, "activate", NULL);
-#endif
+          plugin_popup_menu (plugin);
           return TRUE;
         }
     }
+
   return FALSE;
 }
 
+/* Code taken from xfwm4/src/menu.c:grab_available().  This should fix the case
+ * where binding 'xfdesktop -menu' to a keyboard shortcut sometimes works and
+ * sometimes doesn't.  Credit for this one goes to Olivier.
+ */
+static gboolean
+xfce_popup_grab_available (GdkWindow *win, guint32 timestamp)
+{
+    GdkEventMask mask =
+        GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+        GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
+        GDK_POINTER_MOTION_MASK;
+    GdkGrabStatus g1;
+    GdkGrabStatus g2;
+    gboolean grab_failed = FALSE;
+    gint i = 0;
+
+    TRACE ("entering grab_available");
+
+    g1 = gdk_pointer_grab (win, TRUE, mask, NULL, NULL, timestamp);
+    g2 = gdk_keyboard_grab (win, TRUE, timestamp);
+
+    while ((i++ < 2500) && (grab_failed = ((g1 != GDK_GRAB_SUCCESS)
+                || (g2 != GDK_GRAB_SUCCESS))))
+    {
+        TRACE ("grab not available yet, waiting... (%i)", i);
+        g_usleep (100);
+        if (g1 != GDK_GRAB_SUCCESS)
+        {
+            g1 = gdk_pointer_grab (win, TRUE, mask, NULL, NULL, timestamp);
+        }
+        if (g2 != GDK_GRAB_SUCCESS)
+        {
+            g2 = gdk_keyboard_grab (win, TRUE, timestamp);
+        }
+    }
+
+    if (g1 == GDK_GRAB_SUCCESS)
+    {
+        gdk_pointer_ungrab (timestamp);
+    }
+    if (g2 == GDK_GRAB_SUCCESS)
+    {
+        gdk_keyboard_ungrab (timestamp);
+    }
+
+    return (!grab_failed);
+}
+
diff --git a/panel-plugin/plugin.h b/panel-plugin/plugin.h
index 47d4f89..2cbccd1 100644
--- a/panel-plugin/plugin.h
+++ b/panel-plugin/plugin.h
@@ -44,6 +44,8 @@ struct _MyPlugin
 {
 #ifdef PANEL_PLUGIN
   XfcePanelPlugin      *panel_plugin;
+  GtkWidget            *button;
+  GtkWidget            *image;
 #elif STATUS_ICON
   GtkStatusIcon        *status_icon;
 #endif
@@ -52,9 +54,8 @@ struct _MyPlugin
   ClipmanActions       *actions;
   ClipmanCollector     *collector;
   ClipmanHistory       *history;
-  GtkWidget            *button;
-  GtkWidget            *image;
   GtkWidget            *menu;
+  GtkMenuPositionFunc   menu_position_func;
   GtkWidget            *popup_menu;
   gulong                popup_menu_id;
 };
@@ -69,6 +70,7 @@ void                    plugin_save                     (MyPlugin *plugin);
 void                    plugin_free                     (MyPlugin *plugin);
 void                    plugin_about                    (MyPlugin *plugin);
 void                    plugin_configure                (MyPlugin *plugin);
+void                    plugin_menu_popup               (MyPlugin *plugin);
 
 #endif /* !__CLIPMAN_PLUGIN_H__ */
 



More information about the Xfce4-commits mailing list