[gimp] app: factor out a generic GimpPopup widget out of GimpContainerPopup



commit b0b8fda94cc2aa94e5f7b9c79bb545db0a5e2fdd
Author: Michael Natterer <mitch gimp org>
Date:   Fri Jun 6 00:57:20 2014 +0200

    app: factor out a generic GimpPopup widget out of GimpContainerPopup

 app/widgets/Makefile.am          |    2 +
 app/widgets/gimpcontainerpopup.c |  316 ++++----------------------------------
 app/widgets/gimpcontainerpopup.h |   14 +-
 app/widgets/gimpiconpicker.c     |    3 +-
 app/widgets/gimppopup.c          |  321 ++++++++++++++++++++++++++++++++++++++
 app/widgets/gimppopup.h          |   55 +++++++
 app/widgets/gimpviewablebutton.c |    2 +-
 app/widgets/widgets-types.h      |    1 +
 8 files changed, 415 insertions(+), 299 deletions(-)
---
diff --git a/app/widgets/Makefile.am b/app/widgets/Makefile.am
index 3a7df8e..73d3641 100644
--- a/app/widgets/Makefile.am
+++ b/app/widgets/Makefile.am
@@ -272,6 +272,8 @@ libappwidgets_a_sources = \
        gimppluginaction.h              \
        gimppolar.c                     \
        gimppolar.h                     \
+       gimppopup.c                     \
+       gimppopup.h                     \
        gimpprefsbox.c                  \
        gimpprefsbox.h                  \
        gimpprogressbox.c               \
diff --git a/app/widgets/gimpcontainerpopup.c b/app/widgets/gimpcontainerpopup.c
index 876e4ca..e16e554 100644
--- a/app/widgets/gimpcontainerpopup.c
+++ b/app/widgets/gimpcontainerpopup.c
@@ -2,7 +2,7 @@
  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  *
  * gimpcontainerpopup.c
- * Copyright (C) 2003-2005 Michael Natterer <mitch gimp org>
+ * Copyright (C) 2003-2014 Michael Natterer <mitch gimp org>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -31,7 +31,6 @@
 #include "core/gimp.h"
 #include "core/gimpcontext.h"
 #include "core/gimpcontainer.h"
-#include "core/gimpmarshal.h"
 #include "core/gimpviewable.h"
 
 #include "gimpcontainerbox.h"
@@ -47,92 +46,36 @@
 #include "gimp-intl.h"
 
 
-enum
-{
-  CANCEL,
-  CONFIRM,
-  LAST_SIGNAL
-};
-
-
-static void     gimp_container_popup_finalize     (GObject            *object);
+static void   gimp_container_popup_finalize         (GObject            *object);
 
-static void     gimp_container_popup_map          (GtkWidget          *widget);
-static gboolean gimp_container_popup_button_press (GtkWidget          *widget,
-                                                   GdkEventButton     *bevent);
-static gboolean gimp_container_popup_key_press    (GtkWidget          *widget,
-                                                   GdkEventKey        *kevent);
+static void   gimp_container_popup_confirm          (GimpPopup          *popup);
 
-static void     gimp_container_popup_real_cancel  (GimpContainerPopup *popup);
-static void     gimp_container_popup_real_confirm (GimpContainerPopup *popup);
+static void   gimp_container_popup_create_view      (GimpContainerPopup *popup);
 
-static void     gimp_container_popup_create_view  (GimpContainerPopup *popup);
+static void   gimp_container_popup_smaller_clicked  (GtkWidget          *button,
+                                                     GimpContainerPopup *popup);
+static void   gimp_container_popup_larger_clicked   (GtkWidget          *button,
+                                                     GimpContainerPopup *popup);
+static void   gimp_container_popup_view_type_toggled(GtkWidget          *button,
+                                                     GimpContainerPopup *popup);
+static void   gimp_container_popup_dialog_clicked   (GtkWidget          *button,
+                                                     GimpContainerPopup *popup);
 
-static void gimp_container_popup_smaller_clicked  (GtkWidget          *button,
-                                                   GimpContainerPopup *popup);
-static void gimp_container_popup_larger_clicked   (GtkWidget          *button,
-                                                   GimpContainerPopup *popup);
-static void gimp_container_popup_view_type_toggled(GtkWidget          *button,
-                                                   GimpContainerPopup *popup);
-static void gimp_container_popup_dialog_clicked   (GtkWidget          *button,
-                                                   GimpContainerPopup *popup);
 
-
-G_DEFINE_TYPE (GimpContainerPopup, gimp_container_popup, GTK_TYPE_WINDOW)
+G_DEFINE_TYPE (GimpContainerPopup, gimp_container_popup, GIMP_TYPE_POPUP)
 
 #define parent_class gimp_container_popup_parent_class
 
-static guint popup_signals[LAST_SIGNAL];
-
 
 static void
 gimp_container_popup_class_init (GimpContainerPopupClass *klass)
 {
   GObjectClass   *object_class = G_OBJECT_CLASS (klass);
-  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
-  GtkBindingSet  *binding_set;
-
-  popup_signals[CANCEL] =
-    g_signal_new ("cancel",
-                  G_OBJECT_CLASS_TYPE (klass),
-                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-                  G_STRUCT_OFFSET (GimpContainerPopupClass, cancel),
-                  NULL, NULL,
-                  gimp_marshal_VOID__VOID,
-                  G_TYPE_NONE, 0);
-
-  popup_signals[CONFIRM] =
-    g_signal_new ("confirm",
-                  G_OBJECT_CLASS_TYPE (klass),
-                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-                  G_STRUCT_OFFSET (GimpContainerPopupClass, confirm),
-                  NULL, NULL,
-                  gimp_marshal_VOID__VOID,
-                  G_TYPE_NONE, 0);
-
-  object_class->finalize           = gimp_container_popup_finalize;
-
-  widget_class->map                = gimp_container_popup_map;
-  widget_class->button_press_event = gimp_container_popup_button_press;
-  widget_class->key_press_event    = gimp_container_popup_key_press;
-
-  klass->cancel                    = gimp_container_popup_real_cancel;
-  klass->confirm                   = gimp_container_popup_real_confirm;
-
-  binding_set = gtk_binding_set_by_class (klass);
-
-  gtk_binding_entry_add_signal (binding_set, GDK_KEY_Escape, 0,
-                                "cancel", 0);
-  gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0,
-                                "confirm", 0);
-  gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0,
-                                "confirm", 0);
-  gtk_binding_entry_add_signal (binding_set, GDK_KEY_ISO_Enter, 0,
-                                "confirm", 0);
-  gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0,
-                                "confirm", 0);
-  gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, 0,
-                                "confirm", 0);
+  GimpPopupClass *popup_class  = GIMP_POPUP_CLASS (klass);
+
+  object_class->finalize = gimp_container_popup_finalize;
+
+  popup_class->confirm   = gimp_container_popup_confirm;
 }
 
 static void
@@ -182,160 +125,18 @@ gimp_container_popup_finalize (GObject *object)
 }
 
 static void
-gimp_container_popup_grab_notify (GtkWidget *widget,
-                                  gboolean   was_grabbed)
+gimp_container_popup_confirm (GimpPopup *popup)
 {
-  if (was_grabbed)
-    return;
-
-  /* ignore grabs on one of our children, like the scrollbar */
-  if (gtk_widget_is_ancestor (gtk_grab_get_current (), widget))
-    return;
-
-  g_signal_emit (widget, popup_signals[CANCEL], 0);
-}
-
-static gboolean
-gimp_container_popup_grab_broken_event (GtkWidget          *widget,
-                                        GdkEventGrabBroken *event)
-{
-  gimp_container_popup_grab_notify (widget, FALSE);
-
-  return FALSE;
-}
-
-static void
-gimp_container_popup_map (GtkWidget *widget)
-{
-  GTK_WIDGET_CLASS (parent_class)->map (widget);
-
-  /*  grab with owner_events == TRUE so the popup's widgets can
-   *  receive events. we filter away events outside this toplevel
-   *  away in button_press()
-   */
-  if (gdk_pointer_grab (gtk_widget_get_window (widget), TRUE,
-                        GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
-                        GDK_POINTER_MOTION_MASK,
-                        NULL, NULL, GDK_CURRENT_TIME) == 0)
-    {
-      if (gdk_keyboard_grab (gtk_widget_get_window (widget), TRUE,
-                             GDK_CURRENT_TIME) == 0)
-        {
-          gtk_grab_add (widget);
-
-          g_signal_connect (widget, "grab-notify",
-                            G_CALLBACK (gimp_container_popup_grab_notify),
-                            widget);
-          g_signal_connect (widget, "grab-broken-event",
-                            G_CALLBACK (gimp_container_popup_grab_broken_event),
-                            widget);
-
-          return;
-        }
-      else
-        {
-          gdk_display_pointer_ungrab (gtk_widget_get_display (widget),
-                                      GDK_CURRENT_TIME);
-        }
-    }
-
-  /*  if we could not grab, destroy the popup instead of leaving it
-   *  around uncloseable.
-   */
-  g_signal_emit (widget, popup_signals[CANCEL], 0);
-}
-
-static gboolean
-gimp_container_popup_button_press (GtkWidget      *widget,
-                                   GdkEventButton *bevent)
-{
-  GtkWidget *event_widget;
-  gboolean   cancel = FALSE;
-
-  event_widget = gtk_get_event_widget ((GdkEvent *) bevent);
-
-  if (event_widget == widget)
-    {
-      GtkAllocation allocation;
-
-      gtk_widget_get_allocation (widget, &allocation);
-
-      /*  the event was on the popup, which can either be really on the
-       *  popup or outside gimp (owner_events == TRUE, see map())
-       */
-      if (bevent->x < 0                ||
-          bevent->y < 0                ||
-          bevent->x > allocation.width ||
-          bevent->y > allocation.height)
-        {
-          /*  the event was outsde gimp  */
-
-          cancel = TRUE;
-        }
-    }
-  else if (gtk_widget_get_toplevel (event_widget) != widget)
-    {
-      /*  the event was on a gimp widget, but not inside the popup  */
-
-      cancel = TRUE;
-    }
-
-  if (cancel)
-    g_signal_emit (widget, popup_signals[CANCEL], 0);
-
-  return cancel;
-}
-
-static gboolean
-gimp_container_popup_key_press (GtkWidget   *widget,
-                                GdkEventKey *kevent)
-{
-  GtkBindingSet *binding_set;
-
-  binding_set =
-    gtk_binding_set_by_class (GIMP_CONTAINER_POPUP_GET_CLASS (widget));
-
-  /*  invoke the popup's binding entries manually, because otherwise
-   *  the focus widget (GtkTreeView e.g.) would consume it
-   */
-  if (gtk_binding_set_activate (binding_set,
-                                kevent->keyval,
-                                kevent->state,
-                                GTK_OBJECT (widget)))
-    {
-      return TRUE;
-    }
+  GimpContainerPopup *c_popup = GIMP_CONTAINER_POPUP (popup);
+  GimpObject         *object;
 
-  return GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, kevent);
-}
-
-static void
-gimp_container_popup_real_cancel (GimpContainerPopup *popup)
-{
-  GtkWidget *widget = GTK_WIDGET (popup);
-
-  if (gtk_grab_get_current () == widget)
-    gtk_grab_remove (widget);
-
-  gtk_widget_destroy (widget);
-}
-
-static void
-gimp_container_popup_real_confirm (GimpContainerPopup *popup)
-{
-  GtkWidget  *widget = GTK_WIDGET (popup);
-  GimpObject *object;
-
-  object = gimp_context_get_by_type (popup->context,
-                                     gimp_container_get_children_type (popup->container));
-  gimp_context_set_by_type (popup->orig_context,
-                            gimp_container_get_children_type (popup->container),
+  object = gimp_context_get_by_type (c_popup->context,
+                                     gimp_container_get_children_type (c_popup->container));
+  gimp_context_set_by_type (c_popup->orig_context,
+                            gimp_container_get_children_type (c_popup->container),
                             object);
 
-  if (gtk_grab_get_current () == widget)
-    gtk_grab_remove (widget);
-
-  gtk_widget_destroy (widget);
+  GIMP_POPUP_CLASS (parent_class)->confirm (popup);
 }
 
 static void
@@ -358,7 +159,7 @@ gimp_container_popup_context_changed (GimpContext        *context,
     }
 
   if (confirm)
-    g_signal_emit (popup, popup_signals[CONFIRM], 0);
+    g_signal_emit_by_name (popup, "confirm");
 }
 
 GtkWidget *
@@ -426,67 +227,6 @@ gimp_container_popup_new (GimpContainer     *container,
   return GTK_WIDGET (popup);
 }
 
-void
-gimp_container_popup_show (GimpContainerPopup *popup,
-                           GtkWidget          *widget)
-{
-  GdkScreen      *screen;
-  GtkRequisition  requisition;
-  GtkAllocation   allocation;
-  GdkRectangle    rect;
-  gint            monitor;
-  gint            orig_x;
-  gint            orig_y;
-  gint            x;
-  gint            y;
-
-  g_return_if_fail (GIMP_IS_CONTAINER_POPUP (popup));
-  g_return_if_fail (GTK_IS_WIDGET (widget));
-
-  gtk_widget_size_request (GTK_WIDGET (popup), &requisition);
-
-  gtk_widget_get_allocation (widget, &allocation);
-  gdk_window_get_origin (gtk_widget_get_window (widget), &orig_x, &orig_y);
-
-  if (! gtk_widget_get_has_window (widget))
-    {
-      orig_x += allocation.x;
-      orig_y += allocation.y;
-    }
-
-  screen = gtk_widget_get_screen (widget);
-
-  monitor = gdk_screen_get_monitor_at_point (screen, orig_x, orig_y);
-  gdk_screen_get_monitor_workarea (screen, monitor, &rect);
-
-  if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
-    {
-      x = orig_x + allocation.width - requisition.width;
-
-      if (x < rect.x)
-        x -= allocation.width - requisition.width;
-    }
-  else
-    {
-      x = orig_x;
-
-      if (x + requisition.width > rect.x + rect.width)
-        x += allocation.width - requisition.width;
-    }
-
-  y = orig_y + allocation.height;
-
-  if (y + requisition.height > rect.y + rect.height)
-    y = orig_y - requisition.height;
-
-  gtk_window_set_screen (GTK_WINDOW (popup), screen);
-  gtk_window_set_transient_for (GTK_WINDOW (popup),
-                                GTK_WINDOW (gtk_widget_get_toplevel (widget)));
-
-  gtk_window_move (GTK_WINDOW (popup), x, y);
-  gtk_widget_show (GTK_WIDGET (popup));
-}
-
 GimpViewType
 gimp_container_popup_get_view_type (GimpContainerPopup *popup)
 {
@@ -666,5 +406,5 @@ gimp_container_popup_dialog_clicked (GtkWidget          *button,
                                              gtk_widget_get_screen (button),
                                              gimp_widget_get_monitor (button),
                                              popup->dialog_identifier);
-  g_signal_emit (popup, popup_signals[CONFIRM], 0);
+  g_signal_emit_by_name (popup, "confirm");
 }
diff --git a/app/widgets/gimpcontainerpopup.h b/app/widgets/gimpcontainerpopup.h
index 1267b0c..7f91221 100644
--- a/app/widgets/gimpcontainerpopup.h
+++ b/app/widgets/gimpcontainerpopup.h
@@ -2,7 +2,7 @@
  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  *
  * gimpcontainerpopup.h
- * Copyright (C) 2003-2005 Michael Natterer <mitch gimp org>
+ * Copyright (C) 2003-2014 Michael Natterer <mitch gimp org>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -22,6 +22,9 @@
 #define __GIMP_CONTAINER_POPUP_H__
 
 
+#include "gimppopup.h"
+
+
 #define GIMP_TYPE_CONTAINER_POPUP            (gimp_container_popup_get_type ())
 #define GIMP_CONTAINER_POPUP(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_CONTAINER_POPUP, 
GimpContainerPopup))
 #define GIMP_CONTAINER_POPUP_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_CONTAINER_POPUP, 
GimpContainerPopupClass))
@@ -34,7 +37,7 @@ typedef struct _GimpContainerPopupClass  GimpContainerPopupClass;
 
 struct _GimpContainerPopup
 {
-  GtkWindow            parent_instance;
+  GimpPopup            parent_instance;
 
   GimpContainer       *container;
   GimpContext         *orig_context;
@@ -56,10 +59,7 @@ struct _GimpContainerPopup
 
 struct _GimpContainerPopupClass
 {
-  GtkWindowClass  parent_instance;
-
-  void (* cancel)  (GimpContainerPopup *popup);
-  void (* confirm) (GimpContainerPopup *popup);
+  GimpPopupClass  parent_instance;
 };
 
 
@@ -75,8 +75,6 @@ GtkWidget * gimp_container_popup_new      (GimpContainer      *container,
                                            const gchar        *dialog_identifier,
                                            const gchar        *dialog_icon_name,
                                            const gchar        *dialog_tooltip);
-void        gimp_container_popup_show     (GimpContainerPopup *popup,
-                                           GtkWidget          *widget);
 
 GimpViewType gimp_container_popup_get_view_type (GimpContainerPopup *popup);
 void         gimp_container_popup_set_view_type (GimpContainerPopup *popup,
diff --git a/app/widgets/gimpiconpicker.c b/app/widgets/gimpiconpicker.c
index a742d36..36868ac 100644
--- a/app/widgets/gimpiconpicker.c
+++ b/app/widgets/gimpiconpicker.c
@@ -640,6 +640,5 @@ gimp_icon_picker_menu_from_name (GtkWidget      *widget,
   gimp_container_popup_set_view_type (GIMP_CONTAINER_POPUP (popup),
                                       GIMP_VIEW_TYPE_GRID);
 
-  gimp_container_popup_show (GIMP_CONTAINER_POPUP (popup),
-                             GTK_WIDGET (picker));
+  gimp_popup_show (GIMP_POPUP (popup), GTK_WIDGET (picker));
 }
diff --git a/app/widgets/gimppopup.c b/app/widgets/gimppopup.c
new file mode 100644
index 0000000..1a1e5f5
--- /dev/null
+++ b/app/widgets/gimppopup.c
@@ -0,0 +1,321 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimppopup.c
+ * Copyright (C) 2003-2014 Michael Natterer <mitch gimp org>
+ *
+ * This program 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <gegl.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#include "libgimpwidgets/gimpwidgets.h"
+
+#include "widgets-types.h"
+
+#include "core/gimpmarshal.h"
+
+#include "gimppopup.h"
+
+
+enum
+{
+  CANCEL,
+  CONFIRM,
+  LAST_SIGNAL
+};
+
+
+static void     gimp_popup_map          (GtkWidget      *widget);
+static gboolean gimp_popup_button_press (GtkWidget      *widget,
+                                         GdkEventButton *bevent);
+static gboolean gimp_popup_key_press    (GtkWidget      *widget,
+                                         GdkEventKey    *kevent);
+
+static void     gimp_popup_real_cancel  (GimpPopup      *popup);
+static void     gimp_popup_real_confirm (GimpPopup      *popup);
+
+
+G_DEFINE_TYPE (GimpPopup, gimp_popup, GTK_TYPE_WINDOW)
+
+#define parent_class gimp_popup_parent_class
+
+static guint popup_signals[LAST_SIGNAL];
+
+
+static void
+gimp_popup_class_init (GimpPopupClass *klass)
+{
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+  GtkBindingSet  *binding_set;
+
+  popup_signals[CANCEL] =
+    g_signal_new ("cancel",
+                  G_OBJECT_CLASS_TYPE (klass),
+                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                  G_STRUCT_OFFSET (GimpPopupClass, cancel),
+                  NULL, NULL,
+                  gimp_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+
+  popup_signals[CONFIRM] =
+    g_signal_new ("confirm",
+                  G_OBJECT_CLASS_TYPE (klass),
+                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                  G_STRUCT_OFFSET (GimpPopupClass, confirm),
+                  NULL, NULL,
+                  gimp_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+
+  widget_class->map                = gimp_popup_map;
+  widget_class->button_press_event = gimp_popup_button_press;
+  widget_class->key_press_event    = gimp_popup_key_press;
+
+  klass->cancel                    = gimp_popup_real_cancel;
+  klass->confirm                   = gimp_popup_real_confirm;
+
+  binding_set = gtk_binding_set_by_class (klass);
+
+  gtk_binding_entry_add_signal (binding_set, GDK_KEY_Escape, 0,
+                                "cancel", 0);
+  gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0,
+                                "confirm", 0);
+  gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0,
+                                "confirm", 0);
+  gtk_binding_entry_add_signal (binding_set, GDK_KEY_ISO_Enter, 0,
+                                "confirm", 0);
+  gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0,
+                                "confirm", 0);
+  gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, 0,
+                                "confirm", 0);
+}
+
+static void
+gimp_popup_init (GimpPopup *popup)
+{
+}
+
+static void
+gimp_popup_grab_notify (GtkWidget *widget,
+                        gboolean   was_grabbed)
+{
+  if (was_grabbed)
+    return;
+
+  /* ignore grabs on one of our children, like a scrollbar */
+  if (gtk_widget_is_ancestor (gtk_grab_get_current (), widget))
+    return;
+
+  g_signal_emit (widget, popup_signals[CANCEL], 0);
+}
+
+static gboolean
+gimp_popup_grab_broken_event (GtkWidget          *widget,
+                              GdkEventGrabBroken *event)
+{
+  gimp_popup_grab_notify (widget, FALSE);
+
+  return FALSE;
+}
+
+static void
+gimp_popup_map (GtkWidget *widget)
+{
+  GTK_WIDGET_CLASS (parent_class)->map (widget);
+
+  /*  grab with owner_events == TRUE so the popup's widgets can
+   *  receive events. we filter away events outside this toplevel
+   *  away in button_press()
+   */
+  if (gdk_pointer_grab (gtk_widget_get_window (widget), TRUE,
+                        GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+                        GDK_POINTER_MOTION_MASK,
+                        NULL, NULL, GDK_CURRENT_TIME) == 0)
+    {
+      if (gdk_keyboard_grab (gtk_widget_get_window (widget), TRUE,
+                             GDK_CURRENT_TIME) == 0)
+        {
+          gtk_grab_add (widget);
+
+          g_signal_connect (widget, "grab-notify",
+                            G_CALLBACK (gimp_popup_grab_notify),
+                            widget);
+          g_signal_connect (widget, "grab-broken-event",
+                            G_CALLBACK (gimp_popup_grab_broken_event),
+                            widget);
+
+          return;
+        }
+      else
+        {
+          gdk_display_pointer_ungrab (gtk_widget_get_display (widget),
+                                      GDK_CURRENT_TIME);
+        }
+    }
+
+  /*  if we could not grab, destroy the popup instead of leaving it
+   *  around uncloseable.
+   */
+  g_signal_emit (widget, popup_signals[CANCEL], 0);
+}
+
+static gboolean
+gimp_popup_button_press (GtkWidget      *widget,
+                         GdkEventButton *bevent)
+{
+  GtkWidget *event_widget;
+  gboolean   cancel = FALSE;
+
+  event_widget = gtk_get_event_widget ((GdkEvent *) bevent);
+
+  if (event_widget == widget)
+    {
+      GtkAllocation allocation;
+
+      gtk_widget_get_allocation (widget, &allocation);
+
+      /*  the event was on the popup, which can either be really on the
+       *  popup or outside gimp (owner_events == TRUE, see map())
+       */
+      if (bevent->x < 0                ||
+          bevent->y < 0                ||
+          bevent->x > allocation.width ||
+          bevent->y > allocation.height)
+        {
+          /*  the event was outsde gimp  */
+
+          cancel = TRUE;
+        }
+    }
+  else if (gtk_widget_get_toplevel (event_widget) != widget)
+    {
+      /*  the event was on a gimp widget, but not inside the popup  */
+
+      cancel = TRUE;
+    }
+
+  if (cancel)
+    g_signal_emit (widget, popup_signals[CANCEL], 0);
+
+  return cancel;
+}
+
+static gboolean
+gimp_popup_key_press (GtkWidget   *widget,
+                      GdkEventKey *kevent)
+{
+  GtkBindingSet *binding_set;
+
+  binding_set = gtk_binding_set_by_class (GIMP_POPUP_GET_CLASS (widget));
+
+  /*  invoke the popup's binding entries manually, because otherwise
+   *  the focus widget (GtkTreeView e.g.) would consume it
+   */
+  if (gtk_binding_set_activate (binding_set,
+                                kevent->keyval,
+                                kevent->state,
+                                GTK_OBJECT (widget)))
+    {
+      return TRUE;
+    }
+
+  return GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, kevent);
+}
+
+static void
+gimp_popup_real_cancel (GimpPopup *popup)
+{
+  GtkWidget *widget = GTK_WIDGET (popup);
+
+  if (gtk_grab_get_current () == widget)
+    gtk_grab_remove (widget);
+
+  gtk_widget_destroy (widget);
+}
+
+static void
+gimp_popup_real_confirm (GimpPopup *popup)
+{
+  GtkWidget *widget = GTK_WIDGET (popup);
+
+  if (gtk_grab_get_current () == widget)
+    gtk_grab_remove (widget);
+
+  gtk_widget_destroy (widget);
+}
+
+void
+gimp_popup_show (GimpPopup *popup,
+                 GtkWidget *widget)
+{
+  GdkScreen      *screen;
+  GtkRequisition  requisition;
+  GtkAllocation   allocation;
+  GdkRectangle    rect;
+  gint            monitor;
+  gint            orig_x;
+  gint            orig_y;
+  gint            x;
+  gint            y;
+
+  g_return_if_fail (GIMP_IS_POPUP (popup));
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+
+  gtk_widget_size_request (GTK_WIDGET (popup), &requisition);
+
+  gtk_widget_get_allocation (widget, &allocation);
+  gdk_window_get_origin (gtk_widget_get_window (widget), &orig_x, &orig_y);
+
+  if (! gtk_widget_get_has_window (widget))
+    {
+      orig_x += allocation.x;
+      orig_y += allocation.y;
+    }
+
+  screen = gtk_widget_get_screen (widget);
+
+  monitor = gdk_screen_get_monitor_at_point (screen, orig_x, orig_y);
+  gdk_screen_get_monitor_workarea (screen, monitor, &rect);
+
+  if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
+    {
+      x = orig_x + allocation.width - requisition.width;
+
+      if (x < rect.x)
+        x -= allocation.width - requisition.width;
+    }
+  else
+    {
+      x = orig_x;
+
+      if (x + requisition.width > rect.x + rect.width)
+        x += allocation.width - requisition.width;
+    }
+
+  y = orig_y + allocation.height;
+
+  if (y + requisition.height > rect.y + rect.height)
+    y = orig_y - requisition.height;
+
+  gtk_window_set_screen (GTK_WINDOW (popup), screen);
+  gtk_window_set_transient_for (GTK_WINDOW (popup),
+                                GTK_WINDOW (gtk_widget_get_toplevel (widget)));
+
+  gtk_window_move (GTK_WINDOW (popup), x, y);
+  gtk_widget_show (GTK_WIDGET (popup));
+}
diff --git a/app/widgets/gimppopup.h b/app/widgets/gimppopup.h
new file mode 100644
index 0000000..48dc96e
--- /dev/null
+++ b/app/widgets/gimppopup.h
@@ -0,0 +1,55 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimppopup.h
+ * Copyright (C) 2003-2014 Michael Natterer <mitch gimp org>
+ *
+ * This program 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_POPUP_H__
+#define __GIMP_POPUP_H__
+
+
+#define GIMP_TYPE_POPUP            (gimp_popup_get_type ())
+#define GIMP_POPUP(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_POPUP, GimpPopup))
+#define GIMP_POPUP_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_POPUP, GimpPopupClass))
+#define GIMP_IS_POPUP(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_POPUP))
+#define GIMP_IS_POPUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_POPUP))
+#define GIMP_POPUP_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_POPUP, GimpPopupClass))
+
+
+typedef struct _GimpPopupClass  GimpPopupClass;
+
+struct _GimpPopup
+{
+  GtkWindow  parent_instance;
+};
+
+struct _GimpPopupClass
+{
+  GtkWindowClass  parent_instance;
+
+  void (* cancel)  (GimpPopup *popup);
+  void (* confirm) (GimpPopup *popup);
+};
+
+
+GType   gimp_popup_get_type (void) G_GNUC_CONST;
+
+void    gimp_popup_show     (GimpPopup *popup,
+                             GtkWidget *widget);
+
+
+#endif  /*  __GIMP_POPUP_H__  */
diff --git a/app/widgets/gimpviewablebutton.c b/app/widgets/gimpviewablebutton.c
index 07983f0..54c8bf4 100644
--- a/app/widgets/gimpviewablebutton.c
+++ b/app/widgets/gimpviewablebutton.c
@@ -255,7 +255,7 @@ gimp_viewable_button_clicked (GtkButton *button)
                     G_CALLBACK (gimp_viewable_button_popup_closed),
                     button);
 
-  gimp_container_popup_show (GIMP_CONTAINER_POPUP (popup), GTK_WIDGET (button));
+  gimp_popup_show (GIMP_POPUP (popup), GTK_WIDGET (button));
 }
 
 static void
diff --git a/app/widgets/widgets-types.h b/app/widgets/widgets-types.h
index d9d2275..3bb1680 100644
--- a/app/widgets/widgets-types.h
+++ b/app/widgets/widgets-types.h
@@ -190,6 +190,7 @@ typedef struct _GimpMessageBox               GimpMessageBox;
 typedef struct _GimpOverlayBox               GimpOverlayBox;
 typedef struct _GimpPickableButton           GimpPickableButton;
 typedef struct _GimpPolar                    GimpPolar;
+typedef struct _GimpPopup                    GimpPopup;
 typedef struct _GimpPrefsBox                 GimpPrefsBox;
 typedef struct _GimpProgressBox              GimpProgressBox;
 typedef struct _GimpScaleButton              GimpScaleButton;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]