[Xfce4-commits] <xfce4-appfinder:andrzejr/plugin> Factored out a popup class for overloading some widget event methods.

Andrzej noreply at xfce.org
Sat Feb 18 12:58:01 CET 2012


Updating branch refs/heads/andrzejr/plugin
         to 2cdb9c500f77e3321ffd519087a8daff3b9ab3de (commit)
       from cde7eeb485cbdf85727007e295f46a3940eb9117 (commit)

commit 2cdb9c500f77e3321ffd519087a8daff3b9ab3de
Author: Andrzej <ndrwrdck at gmail.com>
Date:   Sat Feb 18 20:55:49 2012 +0900

    Factored out a popup class for overloading some widget event methods.
    
    Added pointer and keyboard grabbing (so that the popup closes when user
    clicks outside of it).
    
    GtkSocket doesn't seem to work with gdk_pointer_grab - the widget doesn't
    receive any events. For comparison, a "local" button embedded in the window
    works just fine.
    If this cannot be resolved it is a "dead end" for the plugin in this form.

 panel-plugin/Makefile.am        |    2 +
 panel-plugin/appfinder-plugin.c |  236 +++++----------------
 panel-plugin/appfinder-plugin.h |    1 +
 panel-plugin/appfinder-popup.c  |  455 +++++++++++++++++++++++++++++++++++++++
 panel-plugin/appfinder-popup.h  |   45 ++++
 5 files changed, 556 insertions(+), 183 deletions(-)

diff --git a/panel-plugin/Makefile.am b/panel-plugin/Makefile.am
index fafd742..fae2800 100644
--- a/panel-plugin/Makefile.am
+++ b/panel-plugin/Makefile.am
@@ -9,6 +9,8 @@ plugin_LTLIBRARIES = \
         libappfinder.la
 
 libappfinder_la_SOURCES = \
+	appfinder-popup.c \
+	appfinder-popup.h \
 	appfinder-plugin.c \
 	appfinder-plugin.h
 
diff --git a/panel-plugin/appfinder-plugin.c b/panel-plugin/appfinder-plugin.c
index 39b67ce..53fbbe8 100644
--- a/panel-plugin/appfinder-plugin.c
+++ b/panel-plugin/appfinder-plugin.c
@@ -29,6 +29,7 @@
 
 #include <dbus/dbus-glib.h>
 
+#include "appfinder-popup.h"
 #include "appfinder-plugin.h"
 
 /* I18N: default tooltip of the appfinder */
@@ -36,13 +37,6 @@
 #define DEFAULT_ICON_NAME "gtk-find"
 #define DEFAULT_ICON_SIZE (16)
 
-#define APPFINDER_DBUS_SERVICE            "org.xfce.Appfinder"
-#define APPFINDER_DBUS_INTERFACE           APPFINDER_DBUS_SERVICE
-#define APPFINDER_DBUS_PATH               "/org/xfce/Appfinder"
-#define APPFINDER_DBUS_METHOD_OPEN        "OpenWindow"
-#define APPFINDER_DBUS_METHOD_OPEN_WIDGET "OpenWidget"
-#define APPFINDER_DBUS_METHOD_QUIT        "Quit"
-
 struct _XfceAppfinderPluginClass
 {
   XfcePanelPluginClass __parent__;
@@ -56,15 +50,7 @@ struct _XfceAppfinderPlugin
   GtkWidget       *box;
   GtkWidget       *icon;
   GtkWidget       *label;
-  GtkWidget       *appfinder_window;
-  GtkWidget       *appfinder_socket;
-
-  gboolean         visible;
-
-  gint             busy;
-  gint             handler;
-
-  DBusGProxy      *proxy;
+  GtkWidget       *popup;
 
   guint            show_button_title : 1;
   gchar           *button_title;
@@ -100,6 +86,9 @@ static gboolean  xfce_appfinder_plugin_remote_event     (XfcePanelPlugin
 static gboolean  xfce_appfinder_plugin_button_pressed   (GtkWidget              *widget,
                                                          GdkEventButton         *event,
                                                          XfceAppfinderPlugin    *plugin);
+static void    xfce_appfinder_plugin_visibility_changed (XfceAppfinderPopup     *popup,
+                                                         gboolean                visible,
+                                                         gpointer                data);
 
 
 
@@ -163,12 +152,7 @@ xfce_appfinder_plugin_init (XfceAppfinderPlugin *plugin)
 {
 
   plugin->show_button_title = TRUE;
-  plugin->visible = FALSE;
-  plugin->busy = 0;
-  plugin->handler = 0;
-  plugin->proxy = NULL;
-  plugin->appfinder_window = NULL;
-  plugin->appfinder_socket = NULL;
+  plugin->popup = NULL;
 
   plugin->button = xfce_panel_create_toggle_button ();
   xfce_panel_plugin_add_action_widget (XFCE_PANEL_PLUGIN (plugin), plugin->button);
@@ -300,167 +284,46 @@ xfce_appfinder_plugin_construct (XfcePanelPlugin *panel_plugin)
 
 
 
-static void
-xfce_appfinder_plugin_destroy_window (XfceAppfinderPlugin *plugin,
-                                      GtkWidget           *socket)
-{
-  appfinder_return_if_fail (XFCE_IS_APPFINDER_PLUGIN (plugin));
-
-  plugin->busy += 1;
-
-  if (plugin->appfinder_socket != NULL)
-    {
-      g_signal_handler_disconnect(socket, plugin->handler);
-      gtk_widget_destroy (plugin->appfinder_socket);
-      plugin->appfinder_socket = NULL;
-    }
-  if (plugin->appfinder_window != NULL)
-    {
-      gtk_widget_destroy (plugin->appfinder_window);
-      plugin->appfinder_window = NULL;
-    }
-
-  plugin->visible = FALSE;
-  if (plugin->button != NULL)
-    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (plugin->button), FALSE);
-
-  APPFINDER_DEBUG ("destroyed window");
-
-  plugin->busy -= 1;
-}
-
-
-
-static void
-xfce_appfinder_plugin_create_window (XfceAppfinderPlugin *plugin)
-{
-  GtkWidget     *window;
-  GtkWidget     *socket;
-  GtkWidget     *vbox;
-
-  appfinder_return_if_fail (XFCE_IS_APPFINDER_PLUGIN (plugin));
-
-  window = plugin->appfinder_window =
-    g_object_new (GTK_TYPE_WINDOW,
-                  "type", GTK_WINDOW_POPUP,
-                  //"child", socket,
-                  NULL);
-
-  gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
-  gtk_window_set_mnemonic_modifier (GTK_WINDOW (window), 0);
-  gtk_window_set_accept_focus (GTK_WINDOW (window), TRUE);
-
-  vbox = gtk_vbox_new (FALSE, 10);
-  gtk_container_add (GTK_CONTAINER (window), vbox);
-  gtk_container_set_border_width (GTK_CONTAINER (vbox), 7);
-  gtk_widget_show (vbox);
-
-  socket = plugin->appfinder_socket = gtk_socket_new ();
-  gtk_box_pack_start (GTK_BOX (vbox), socket, TRUE, TRUE, 0);
-  gtk_widget_show (socket);
-
-  plugin->handler = g_signal_connect_swapped
-    (G_OBJECT (socket), "destroy",
-     G_CALLBACK (xfce_appfinder_plugin_destroy_window), plugin);
-
-  APPFINDER_DEBUG ("contructed window");
-}
-
-
-
 static gboolean
-xfce_appfinder_plugin_activate_dbus (DBusGProxy       *proxy,
-                                     GdkNativeWindow   id,
-                                     GError          **error)
+xfce_appfinder_plugin_toggle (XfceAppfinderPlugin  *plugin,
+                              gboolean              visible)
 {
-  DBusGConnection  *connection;
-  gboolean          retval = FALSE;
+  gboolean       retval;
+  GtkWidget     *parent_toplevel;
+  gint           x, y;
 
-  /* connect to DBUS service and cache the proxy */
-  if (proxy == NULL)
-    {
-      connection = dbus_g_bus_get (DBUS_BUS_SESSION, error);
-      if (connection == NULL)
-        return retval;
-
-      proxy = dbus_g_proxy_new_for_name (connection,
-                                         APPFINDER_DBUS_SERVICE,
-                                         APPFINDER_DBUS_PATH,
-                                         APPFINDER_DBUS_INTERFACE);
-    }
+  appfinder_return_val_if_fail (XFCE_IS_APPFINDER_PLUGIN (plugin), FALSE);
 
-  if (G_LIKELY (proxy != NULL))
+  if (visible && plugin->popup == NULL)
     {
-      retval = dbus_g_proxy_call (proxy, APPFINDER_DBUS_METHOD_OPEN_WIDGET, error,
-                                  G_TYPE_UINT, id,
-                                  G_TYPE_INVALID,
-                                  G_TYPE_INVALID);
-
-      g_object_unref (G_OBJECT (proxy));
+      plugin->popup = g_object_new (XFCE_TYPE_APPFINDER_POPUP,
+                                    "type", GTK_WINDOW_POPUP,
+                                    NULL);
+      parent_toplevel = gtk_widget_get_toplevel (GTK_WIDGET (plugin));
+      if (GTK_IS_WINDOW (parent_toplevel))
+        gtk_window_set_transient_for (GTK_WINDOW (plugin->popup),
+                                      GTK_WINDOW (parent_toplevel));
+      g_signal_connect (G_OBJECT(plugin->popup), "popup-visibility-changed",
+                        G_CALLBACK(xfce_appfinder_plugin_visibility_changed), plugin->button);
     }
 
-  return retval;
-}
-
-
-
-static void
-xfce_appfinder_plugin_widget_toggle (XfceAppfinderPlugin  *plugin,
-                                     gboolean              visible)
-{
-  GError      *error = NULL;
-  gboolean     succeeded;
-  gint         x, y;
-
-  appfinder_return_if_fail (XFCE_IS_APPFINDER_PLUGIN (plugin));
-
-  if (plugin->busy > 0 || plugin->visible == visible)
-    return;
-
-  plugin->busy += 1;
-
-  plugin->visible = visible;
-
-  if (plugin->button != NULL)
-    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (plugin->button), visible);
-
   if (visible)
     {
-      if (plugin->appfinder_window == NULL)
-        xfce_appfinder_plugin_create_window (plugin);
-      gtk_widget_set_size_request (plugin->appfinder_window, 600, 400);
-
+      retval = xfce_appfinder_popup_popup (XFCE_APPFINDER_POPUP (plugin->popup));
       xfce_panel_plugin_position_widget
-        (XFCE_PANEL_PLUGIN (plugin), plugin->appfinder_window, NULL, &x, &y);
-      gtk_window_move (GTK_WINDOW (plugin->appfinder_window), x, y);
-
-      succeeded = xfce_appfinder_plugin_activate_dbus
-        (plugin->proxy,
-         gtk_socket_get_id (GTK_SOCKET (plugin->appfinder_socket)),
-         &error);
-
-      if (!succeeded)
-        {
-          xfce_dialog_show_error (NULL, error,
-                                  _("Failed to open Appfinder widget"));
-          g_error_free (error);
-          xfce_appfinder_plugin_destroy_window (plugin, plugin->appfinder_socket);
-          plugin->busy -= 1;
-          return;
-        }
-
-      if (visible)
-        gtk_widget_set_visible (plugin->appfinder_window, visible);
+        (XFCE_PANEL_PLUGIN (plugin), plugin->popup, NULL, &x, &y);
+      gtk_window_move (GTK_WINDOW (plugin->popup), x, y);
     }
   else
     {
-      xfce_appfinder_plugin_destroy_window (plugin, plugin->appfinder_socket);
+      retval = xfce_appfinder_popup_popdown (XFCE_APPFINDER_POPUP (plugin->popup));
     }
 
-  plugin->busy -= 1;
-
+  return retval;
 }
 
+
+
 static gboolean
 xfce_appfinder_plugin_button_pressed (GtkWidget            *button,
                                       GdkEventButton       *event,
@@ -475,9 +338,12 @@ xfce_appfinder_plugin_button_pressed (GtkWidget            *button,
     //&& !PANEL_HAS_FLAG (event->state, GDK_CONTROL_MASK)))
     return FALSE;
 
-  APPFINDER_DEBUG ("button pressed %d", plugin->busy);
+  APPFINDER_DEBUG ("button pressed");
 
-  xfce_appfinder_plugin_widget_toggle (plugin, !plugin->visible);
+  xfce_appfinder_plugin_toggle
+    (plugin,
+     plugin->popup == NULL ||
+     !xfce_appfinder_popup_is_visible (XFCE_APPFINDER_POPUP (plugin->popup)));
 
   return TRUE;
 }
@@ -584,19 +450,9 @@ xfce_appfinder_plugin_remote_event (XfcePanelPlugin *panel_plugin,
 
   APPFINDER_DEBUG ("remote event %s", name);
 
-  if (exo_str_is_equal (name, "popup")
-      && GTK_WIDGET_VISIBLE (panel_plugin)
-      && !plugin->visible)
-      //&& panel_utils_grab_available ())
-    {
-      /* show the widget at the button */
-      xfce_appfinder_plugin_widget_toggle (plugin, TRUE);
-
-      /* don't popup another widget */
-      return TRUE;
-    }
-
-  return FALSE;
+  return (exo_str_is_equal (name, "popup")
+          && GTK_WIDGET_VISIBLE (panel_plugin)
+          && xfce_appfinder_plugin_toggle (plugin, TRUE));
 }
 
 
@@ -607,9 +463,23 @@ xfce_appfinder_plugin_free_data (XfcePanelPlugin *panel_plugin)
   XfceAppfinderPlugin *plugin = XFCE_APPFINDER_PLUGIN (panel_plugin);
 
   appfinder_return_if_fail (XFCE_IS_APPFINDER_PLUGIN (panel_plugin));
-  if (plugin->visible)
-    xfce_appfinder_plugin_destroy_window (plugin, plugin->appfinder_socket);
+
+  if (plugin->popup != NULL)
+    gtk_widget_destroy (plugin->popup);
 
   g_free (plugin->button_title);
   g_free (plugin->button_icon);
 }
+
+
+static void
+xfce_appfinder_plugin_visibility_changed (XfceAppfinderPopup *popup,
+                                          gboolean            visible,
+                                          gpointer            data)
+{
+  GtkToggleButton *button = GTK_TOGGLE_BUTTON (data);
+
+  appfinder_return_if_fail (XFCE_IS_APPFINDER_POPUP (popup));
+
+  gtk_toggle_button_set_active (button, visible);
+}
diff --git a/panel-plugin/appfinder-plugin.h b/panel-plugin/appfinder-plugin.h
index 0c020fe..4c2f821 100644
--- a/panel-plugin/appfinder-plugin.h
+++ b/panel-plugin/appfinder-plugin.h
@@ -20,6 +20,7 @@
 #define __XFCE_APPFINDER_PLUGIN_H__
 
 #include <gtk/gtk.h>
+#include <libxfce4panel/libxfce4panel.h>
 
 G_BEGIN_DECLS
 
diff --git a/panel-plugin/appfinder-popup.c b/panel-plugin/appfinder-popup.c
new file mode 100644
index 0000000..85a0486
--- /dev/null
+++ b/panel-plugin/appfinder-popup.c
@@ -0,0 +1,455 @@
+/*
+ * Copyright (C) 2012 Andrzej <ndrwrdck at gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <exo/exo.h>
+#include <libxfce4ui/libxfce4ui.h>
+
+//#include <xfconf/xfconf.h>
+
+#include <dbus/dbus-glib.h>
+
+#include "appfinder-popup.h"
+#include "appfinder-plugin.h"
+
+#define APPFINDER_DBUS_SERVICE            "org.xfce.Appfinder"
+#define APPFINDER_DBUS_INTERFACE           APPFINDER_DBUS_SERVICE
+#define APPFINDER_DBUS_PATH               "/org/xfce/Appfinder"
+#define APPFINDER_DBUS_METHOD_OPEN        "OpenWindow"
+#define APPFINDER_DBUS_METHOD_OPEN_WIDGET "OpenWidget"
+#define APPFINDER_DBUS_METHOD_QUIT        "Quit"
+
+
+static void       xfce_appfinder_popup_socket_destroyed             (XfceAppfinderPopup     *popup,
+                                                                     GtkWidget              *socket);
+static void       xfce_appfinder_popup_proxy_destroyed              (XfceAppfinderPopup     *popup,
+                                                                     DBusGProxy             *proxy);
+static gboolean   xfce_appfinder_popup_button_press                 (GtkWidget              *widget,
+                                                                     GdkEventButton         *event);
+static gboolean   xfce_appfinder_popup_button_release               (GtkWidget              *widget,
+                                                                     GdkEventButton         *event);
+static gboolean   xfce_appfinder_popup_key_press                    (GtkWidget              *widget,
+                                                                     GdkEventKey            *event);
+
+
+struct _XfceAppfinderPopupClass
+{
+  GtkWindowClass   __parent__;
+};
+
+struct _XfceAppfinderPopup
+{
+  GtkWindow        __parent__;
+
+  GtkWidget       *vbox;
+  GtkWidget       *socket;
+
+  gboolean         visible;
+
+  gint             busy;
+  gint             handler;
+
+  DBusGProxy      *proxy;
+
+  GdkGrabStatus    grab_pointer;
+  GdkGrabStatus    grab_keyboard;
+
+  gboolean         ignore;
+};
+
+enum
+{
+  POPUP_VISIBILITY_CHANGED,
+  LAST_SIGNAL
+};
+
+
+
+static guint appfinder_popup_signals[LAST_SIGNAL];
+
+
+
+G_DEFINE_TYPE (XfceAppfinderPopup, xfce_appfinder_popup, GTK_TYPE_WINDOW)
+
+
+
+static void
+xfce_appfinder_popup_class_init (XfceAppfinderPopupClass *klass)
+{
+  GObjectClass         *gobject_class;
+  GtkWidgetClass       *widget_class;
+  //GtkWindowClass       *window_class;
+
+  widget_class = GTK_WIDGET_CLASS (klass);
+  widget_class->button_press_event = xfce_appfinder_popup_button_press;
+  widget_class->button_release_event = xfce_appfinder_popup_button_release;
+  widget_class->key_press_event = xfce_appfinder_popup_key_press;
+  //widget_class->focus = xfce_appfinder_popup_focus;
+
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  appfinder_popup_signals[POPUP_VISIBILITY_CHANGED] =
+    g_signal_new (g_intern_static_string ("popup-visibility-changed"),
+                  G_TYPE_FROM_CLASS (gobject_class),
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL,
+                  g_cclosure_marshal_VOID__BOOLEAN,
+                  G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
+
+}
+
+
+
+static void
+xfce_appfinder_popup_init (XfceAppfinderPopup *popup)
+{
+  popup->visible = FALSE;
+  popup->busy = 0;
+  popup->handler = 0;
+  popup->proxy = NULL;
+  popup->socket = NULL;
+  popup->grab_pointer = GDK_GRAB_FROZEN;
+  popup->grab_keyboard = GDK_GRAB_FROZEN;
+  popup->ignore = FALSE;
+
+  //g_object_set (G_OBJECT (popup), "type", GTK_WINDOW_POPUP, NULL);
+
+  gtk_window_set_resizable (GTK_WINDOW (popup), FALSE);
+  gtk_window_set_mnemonic_modifier (GTK_WINDOW (popup), 0);
+  gtk_window_set_accept_focus (GTK_WINDOW (popup), TRUE);
+  gtk_widget_set_can_focus (GTK_WIDGET (popup), TRUE);
+  gtk_widget_set_size_request (GTK_WIDGET (popup), 600, 400);
+
+  popup->vbox = gtk_vbox_new (FALSE, 10);
+  gtk_container_add (GTK_CONTAINER (popup), popup->vbox);
+  gtk_container_set_border_width (GTK_CONTAINER (popup->vbox), 7);
+  gtk_widget_show (popup->vbox);
+
+  {
+    GtkWidget       *button;
+    button = xfce_panel_create_toggle_button ();
+    gtk_box_pack_start (GTK_BOX (popup->vbox), button, TRUE, TRUE, 0);
+    gtk_widget_show (button);
+  }
+}
+
+
+
+static gboolean
+xfce_appfinder_popup_activate_dbus (XfceAppfinderPopup  *popup,
+                                    GdkNativeWindow      id,
+                                    GError              **error)
+{
+  DBusGConnection  *connection;
+  gboolean          retval = FALSE;
+
+  /* connect to DBUS service and cache the proxy */
+  if (popup->proxy == NULL)
+    {
+      connection = dbus_g_bus_get (DBUS_BUS_SESSION, error);
+      if (connection == NULL)
+        return retval;
+
+      popup->proxy = dbus_g_proxy_new_for_name (connection,
+                                         APPFINDER_DBUS_SERVICE,
+                                         APPFINDER_DBUS_PATH,
+                                         APPFINDER_DBUS_INTERFACE);
+
+      /* clear cached proxy reference when connection is lost */
+      g_signal_connect_swapped
+        (G_OBJECT (popup->proxy), "destroy",
+         G_CALLBACK (xfce_appfinder_popup_proxy_destroyed), popup);
+
+    }
+
+  if (G_LIKELY (popup->proxy != NULL))
+    {
+      retval = dbus_g_proxy_call (popup->proxy, APPFINDER_DBUS_METHOD_OPEN_WIDGET, error,
+                                  G_TYPE_UINT, id,
+                                  G_TYPE_INVALID,
+                                  G_TYPE_INVALID);
+    }
+
+  return retval;
+}
+
+
+
+static void
+xfce_appfinder_popup_grab_remove (XfceAppfinderPopup *popup)
+{
+  if (popup->grab_pointer == GDK_GRAB_SUCCESS)
+    gdk_pointer_ungrab (GDK_CURRENT_TIME);
+  if (popup->grab_keyboard == GDK_GRAB_SUCCESS)
+    gdk_keyboard_ungrab (GDK_CURRENT_TIME);
+}
+
+
+
+static gboolean
+xfce_appfinder_popup_grab (XfceAppfinderPopup *popup, gboolean keep)
+{
+  GdkWindow     *window;
+  gboolean       grab_succeed = FALSE;
+  guint          i;
+  GdkEventMask   pointer_mask = GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+                                | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK
+                                | GDK_POINTER_MOTION_MASK;
+
+  window = GTK_WIDGET (popup->socket)->window;
+
+  /* don't try to get the grab for longer then 1/4 second */
+  for (i = 0; i < (G_USEC_PER_SEC / 100 / 4); i++)
+    {
+      popup->grab_keyboard = gdk_keyboard_grab (window, TRUE, GDK_CURRENT_TIME);
+      if (popup->grab_keyboard == GDK_GRAB_SUCCESS)
+        {
+          popup->grab_pointer = gdk_pointer_grab (window, TRUE, pointer_mask,
+                                                  NULL, NULL, GDK_CURRENT_TIME);
+          if (popup->grab_pointer == GDK_GRAB_SUCCESS)
+            {
+              grab_succeed = TRUE;
+              break;
+            }
+        }
+
+      g_usleep (100);
+    }
+
+  /* release the grab */
+  if (!keep)
+    xfce_appfinder_popup_grab_remove (popup);
+
+  if (!grab_succeed)
+    {
+      xfce_appfinder_popup_grab_remove (popup);
+      g_printerr (PACKAGE_NAME ": Unable to get keyboard and mouse "
+                  "grab. Popup failed.\n");
+    }
+
+  return grab_succeed;
+}
+
+
+
+
+gboolean
+xfce_appfinder_popup_is_visible (XfceAppfinderPopup *popup)
+{
+  appfinder_return_val_if_fail (XFCE_IS_APPFINDER_POPUP (popup), FALSE);
+
+  return popup->visible;
+}
+
+
+
+gboolean
+xfce_appfinder_popup_popdown (XfceAppfinderPopup *popup)
+{
+  appfinder_return_val_if_fail (XFCE_IS_APPFINDER_POPUP (popup), FALSE);
+
+  if (!popup->visible || popup->busy > 0)
+    return FALSE;
+
+  popup->busy += 1;
+
+  xfce_appfinder_popup_grab_remove (popup);
+
+  if (popup->socket != NULL)
+    {
+      g_signal_handler_disconnect(popup->socket, popup->handler);
+      gtk_widget_destroy (popup->socket);
+      popup->socket = NULL;
+    }
+  //gtk_window_set_transient_for (GTK_WINDOW (popup), NULL);
+  gtk_widget_hide (GTK_WIDGET (popup));
+
+  popup->visible = FALSE;
+  g_signal_emit (G_OBJECT (popup), appfinder_popup_signals[POPUP_VISIBILITY_CHANGED], 0,
+                 FALSE);
+
+  APPFINDER_DEBUG ("popdown");
+
+  popup->busy -= 1;
+
+  return TRUE;
+}
+
+
+
+gboolean
+xfce_appfinder_popup_popup (XfceAppfinderPopup *popup)
+{
+  GError        *error = NULL;
+
+  appfinder_return_val_if_fail (XFCE_IS_APPFINDER_POPUP (popup), FALSE);
+
+  if (popup->visible || popup->busy > 0)
+    return FALSE;
+
+  popup->busy += 1;
+  popup->ignore = TRUE;
+
+  popup->socket = gtk_socket_new ();
+  gtk_box_pack_start (GTK_BOX (popup->vbox), popup->socket, TRUE, TRUE, 0);
+
+  popup->handler = g_signal_connect_swapped
+    (G_OBJECT (popup->socket), "destroy",
+     G_CALLBACK (xfce_appfinder_popup_socket_destroyed), popup);
+
+  if (!xfce_appfinder_popup_activate_dbus
+      (popup,
+       gtk_socket_get_id (GTK_SOCKET (popup->socket)),
+       &error))
+    {
+      xfce_dialog_show_error (NULL, error,
+                              _("Failed to open Appfinder widget"));
+      g_error_free (error);
+      xfce_appfinder_popup_popdown (popup);
+      popup->busy -= 1;
+      return FALSE;
+    }
+
+  gtk_widget_show (popup->socket);
+  gtk_widget_show (GTK_WIDGET (popup));
+
+  xfce_appfinder_popup_grab (popup, TRUE);
+
+  popup->visible = TRUE;
+  g_signal_emit (G_OBJECT (popup), appfinder_popup_signals[POPUP_VISIBILITY_CHANGED], 0,
+                 TRUE);
+
+  popup->busy -= 1;
+
+  APPFINDER_DEBUG ("popup");
+
+  return TRUE;
+}
+
+
+
+static void
+xfce_appfinder_popup_socket_destroyed (XfceAppfinderPopup *popup,
+                                       GtkWidget          *socket)
+{
+  appfinder_return_if_fail (XFCE_IS_APPFINDER_POPUP (popup));
+  appfinder_return_if_fail (GTK_IS_SOCKET (socket));
+
+  xfce_appfinder_popup_popdown (popup);
+}
+
+
+
+static void
+xfce_appfinder_popup_proxy_destroyed (XfceAppfinderPopup *popup,
+                                      DBusGProxy         *proxy)
+{
+  appfinder_return_if_fail (XFCE_IS_APPFINDER_POPUP (popup));
+  appfinder_return_if_fail (DBUS_IS_G_PROXY (proxy));
+
+  g_object_unref (G_OBJECT (popup->proxy));
+  popup->proxy = NULL;
+}
+
+
+
+static gboolean
+xfce_appfinder_popup_pointer_in_popup (GtkWidget *widget,
+                                       gdouble    x_root,
+                                       gdouble    y_root)
+{
+  if (gtk_widget_get_mapped (widget))
+    {
+      gint          window_x, window_y;
+
+      gdk_window_get_position (widget->window, &window_x, &window_y);
+
+      if (x_root >= window_x && x_root < window_x + widget->allocation.width &&
+          y_root >= window_y && y_root < window_y + widget->allocation.height)
+        return TRUE;
+    }
+
+  return FALSE;
+}
+
+
+
+static gboolean
+xfce_appfinder_popup_button_press (GtkWidget      *widget,
+                                   GdkEventButton *event)
+{
+  XfceAppfinderPopup *popup = XFCE_APPFINDER_POPUP (widget);
+
+  APPFINDER_DEBUG ("press   %d, %g %g\n", event->type, event->x_root, event->y_root);
+
+  if (event->type != GDK_BUTTON_PRESS)
+    return FALSE;
+
+  if (!xfce_appfinder_popup_pointer_in_popup (widget, event->x_root, event->y_root))
+    {
+      xfce_appfinder_popup_popdown (popup);
+      return TRUE;
+    }
+
+  return GTK_WIDGET_CLASS (xfce_appfinder_popup_parent_class)->button_press_event (widget, event);
+}
+
+
+
+static gboolean
+xfce_appfinder_popup_button_release (GtkWidget      *widget,
+                                     GdkEventButton *event)
+{
+  XfceAppfinderPopup *popup = XFCE_APPFINDER_POPUP (widget);
+
+  APPFINDER_DEBUG ("release %d, %g %g\n", event->type, event->x_root, event->y_root);
+
+  if (event->type != GDK_BUTTON_RELEASE || popup->ignore)
+    {
+      /* ignore the first release event (coming from the button?) */
+      popup->ignore = FALSE;
+      return FALSE;
+    }
+
+  return GTK_WIDGET_CLASS (xfce_appfinder_popup_parent_class)->button_release_event (widget, event);
+}
+
+
+
+
+static gboolean
+xfce_appfinder_popup_key_press (GtkWidget      *widget,
+                                GdkEventKey    *event)
+{
+  //XfceAppfinderPopup *popup = XFCE_APPFINDER_POPUP (widget);
+
+  APPFINDER_DEBUG ("press   %d, %s\n", event->type, event->string);
+
+  if (event->type != GDK_KEY_PRESS)
+    return FALSE;
+
+  return GTK_WIDGET_CLASS (xfce_appfinder_popup_parent_class)->key_press_event (widget, event);
+
+}
+
+
+
+
diff --git a/panel-plugin/appfinder-popup.h b/panel-plugin/appfinder-popup.h
new file mode 100644
index 0000000..34ba072
--- /dev/null
+++ b/panel-plugin/appfinder-popup.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2012 Andrzej <ndrwrdck at gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __XFCE_APPFINDER_POPUP_H__
+#define __XFCE_APPFINDER_POPUP_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+typedef struct _XfceAppfinderPopupClass      XfceAppfinderPopupClass;
+typedef struct _XfceAppfinderPopup           XfceAppfinderPopup;
+
+#define XFCE_TYPE_APPFINDER_POPUP            (xfce_appfinder_popup_get_type ())
+#define XFCE_APPFINDER_POPUP(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), XFCE_TYPE_APPFINDER_POPUP, XfceAppfinderPopup))
+#define XFCE_APPFINDER_POPUP_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), XFCE_TYPE_APPFINDER_POPUP, XfceAppfinderPopupClass))
+#define XFCE_IS_APPFINDER_POPUP(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XFCE_TYPE_APPFINDER_POPUP))
+#define XFCE_IS_APPFINDER_POPUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XFCE_TYPE_APPFINDER_POPUP))
+#define XFCE_APPFINDER_POPUP_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), XFCE_TYPE_APPFINDER_POPUP, XfceAppfinderPopupClass))
+
+GType     xfce_appfinder_popup_get_type      (void) G_GNUC_CONST;
+
+gboolean  xfce_appfinder_popup_popdown       (XfceAppfinderPopup *popup);
+gboolean  xfce_appfinder_popup_popup         (XfceAppfinderPopup *popup);
+gboolean  xfce_appfinder_popup_is_visible    (XfceAppfinderPopup *popup);
+
+
+G_END_DECLS
+
+#endif /* !__XFCE_APPFINDER_POPUP_H__ */


More information about the Xfce4-commits mailing list