[goocanvas/goocanvas-2.0] Fix stuck grab bug #711709



commit 9ad26d107dfa4c690d4364a389dc4e47a471c1ff
Author: Damon Chaplin <Damon A Chaplin gmail com>
Date:   Wed Aug 30 11:22:37 2017 +0100

    Fix stuck grab bug #711709
    
    2017-08-30  Damon Chaplin  <damon gnome org>
    
        * src/goocanvas.c: If we receive a LEAVE_NOTIFY event with a mode of
          GDK_CROSSING_GRAB or GDK_CROSSING_GTK_GRAB we finish any passive grab
          we have underway. Hopefully fixes #711709
    
        * demo/mv-simple-demo.c (on_rect_button_press):
        * demo/simple-demo.c (on_rect_button_press): show a dialog to test
          the grab bug fix above.

 .gitignore            |    1 +
 ChangeLog             |   10 +++++++
 demo/mv-simple-demo.c |   17 +++++++++--
 demo/simple-demo.c    |   17 +++++++++--
 src/goocanvas.c       |   73 +++++++++++++++++++++++++++++-------------------
 5 files changed, 83 insertions(+), 35 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index 74b5531..2635757 100644
--- a/.gitignore
+++ b/.gitignore
@@ -45,6 +45,7 @@ Makefile.in
 /install-sh
 /libtool
 /ltmain.sh
+/m4
 /missing
 /mkinstalldirs
 /py-compile
diff --git a/ChangeLog b/ChangeLog
index 9a8d576..0a022af 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2017-08-30  Damon Chaplin  <damon gnome org>
+
+       * src/goocanvas.c: If we receive a LEAVE_NOTIFY event with a mode of
+       GDK_CROSSING_GRAB or GDK_CROSSING_GTK_GRAB we finish any passive grab
+       we have underway. Hopefully fixes #711709
+
+       * demo/mv-simple-demo.c (on_rect_button_press): 
+       * demo/simple-demo.c (on_rect_button_press): show a dialog to test
+       the grab bug fix above.
+
 2017-08-29  Damon Chaplin  <damon gnome org>
 
        * src/goocanvas.c:
diff --git a/demo/mv-simple-demo.c b/demo/mv-simple-demo.c
index 74c1b34..39c5edd 100644
--- a/demo/mv-simple-demo.c
+++ b/demo/mv-simple-demo.c
@@ -72,15 +72,26 @@ main (int argc, char *argv[])
 }
 
 
-/* This handles button presses in item views. We simply output a message to
-   the console. */
+/* The signal handler for the rectangle item. We show a dialog here. */
 static gboolean
 on_rect_button_press (GooCanvasItem  *item,
                      GooCanvasItem  *target,
                      GdkEventButton *event,
                      gpointer        data)
 {
-  g_print ("rect item received button press event\n");
+  GooCanvas *canvas;
+  GtkWidget *window, *dialog;
+
+  canvas = goo_canvas_item_get_canvas (item);
+  window = gtk_widget_get_toplevel (GTK_WIDGET (canvas));
+  dialog = gtk_message_dialog_new (GTK_WINDOW (window),
+                                  GTK_DIALOG_DESTROY_WITH_PARENT,
+                                  GTK_MESSAGE_INFO,
+                                  GTK_BUTTONS_CLOSE,
+                                  "rect item received button press event");
+  gtk_dialog_run (GTK_DIALOG (dialog));
+  gtk_widget_destroy (dialog);
+
   return TRUE;
 }
 
diff --git a/demo/simple-demo.c b/demo/simple-demo.c
index 0cb64d5..3da3d62 100644
--- a/demo/simple-demo.c
+++ b/demo/simple-demo.c
@@ -68,15 +68,26 @@ main (int argc, char *argv[])
 }
 
 
-/* This handles button presses in item views. We simply output a message to
-   the console. */
+/* The signal handler for the rectangle item. We show a dialog here. */
 static gboolean
 on_rect_button_press (GooCanvasItem  *item,
                      GooCanvasItem  *target,
                      GdkEventButton *event,
                      gpointer        data)
 {
-  g_print ("rect item received button press event\n");
+  GooCanvas *canvas;
+  GtkWidget *window, *dialog;
+
+  canvas = goo_canvas_item_get_canvas (item);
+  window = gtk_widget_get_toplevel (GTK_WIDGET (canvas));
+  dialog = gtk_message_dialog_new (GTK_WINDOW (window),
+                                  GTK_DIALOG_DESTROY_WITH_PARENT,
+                                  GTK_MESSAGE_INFO,
+                                  GTK_BUTTONS_CLOSE,
+                                  "rect item received button press event");
+  gtk_dialog_run (GTK_DIALOG (dialog));
+  gtk_widget_destroy (dialog);
+
   return TRUE;
 }
 
diff --git a/src/goocanvas.c b/src/goocanvas.c
index 180d1fa..a7d7a21 100644
--- a/src/goocanvas.c
+++ b/src/goocanvas.c
@@ -122,6 +122,7 @@ struct _GooCanvasPrivate {
   gint static_window_x, static_window_y;
   GdkRGBA background_color;
   guint background_color_set : 1;
+  guint pointer_grab_is_implicit : 1;
 };
 
 
@@ -3209,17 +3210,51 @@ update_pointer_item (GooCanvas *canvas,
 }
 
 
+static void
+goo_canvas_finish_pointer_grab (GooCanvas *canvas,
+                               GdkEvent  *event)
+{
+  /* We set the pointer item back to the item it was in before the
+     grab, so we'll synthesize enter/leave notify events as appropriate. */
+  if (canvas->pointer_grab_initial_item
+      && ITEM_IS_VALID (canvas->pointer_grab_initial_item))
+    set_item_pointer (&canvas->pointer_item,
+                     canvas->pointer_grab_initial_item);
+  else
+    set_item_pointer (&canvas->pointer_item, NULL);
+
+  set_item_pointer (&canvas->pointer_grab_item, NULL);
+  set_item_pointer (&canvas->pointer_grab_initial_item, NULL);
+
+  update_pointer_item (canvas, event);
+}
+
+
 static gboolean
 goo_canvas_crossing        (GtkWidget        *widget,
                            GdkEventCrossing *event)
 {
   GooCanvas *canvas = GOO_CANVAS (widget);
+  GooCanvasPrivate *priv = GOO_CANVAS_GET_PRIVATE (canvas);
 
   if (event->window != canvas->canvas_window)
     return FALSE;
 
-  /* This will result in synthesizing focus_in/out events as appropriate. */
-  update_pointer_item (canvas, (GdkEvent*) event);
+    /* If the pointer has left the canvas window due to a grab, then finish any
+       implicit pointer grab we have underway. */
+    if (event->type == GDK_LEAVE_NOTIFY
+      && (event->mode == GDK_CROSSING_GRAB
+         || event->mode == GDK_CROSSING_GTK_GRAB)
+      && canvas->pointer_grab_item
+      && priv->pointer_grab_is_implicit)
+    {
+      goo_canvas_finish_pointer_grab (canvas, (GdkEvent*) event);
+    }
+  else
+    {
+      /* This will result in synthesizing focus_in/out events as appropriate. */
+      update_pointer_item (canvas, (GdkEvent*) event);
+    }
 
   return FALSE;
 }
@@ -3251,6 +3286,7 @@ goo_canvas_button_press (GtkWidget      *widget,
                         GdkEventButton *event)
 {
   GooCanvas *canvas = GOO_CANVAS (widget);
+  GooCanvasPrivate *priv = GOO_CANVAS_GET_PRIVATE (canvas);
   GdkDevice *device = gdk_event_get_device ((GdkEvent*) event);
   GdkDisplay *display;
 
@@ -3270,6 +3306,7 @@ goo_canvas_button_press (GtkWidget      *widget,
       set_item_pointer (&canvas->pointer_grab_item,
                        canvas->pointer_item);
       canvas->pointer_grab_button = event->button;
+      priv->pointer_grab_is_implicit = TRUE;
     }
 
   return emit_pointer_event (canvas, "button_press_event", (GdkEvent*) event);
@@ -3299,19 +3336,7 @@ goo_canvas_button_release (GtkWidget      *widget,
       && event->button == canvas->pointer_grab_button
       && !gdk_display_device_is_grabbed (display, device))
     {
-      /* We set the pointer item back to the item it was in before the
-        grab, so we'll synthesize enter/leave notify events as appropriate. */
-      if (canvas->pointer_grab_initial_item
-         && ITEM_IS_VALID (canvas->pointer_grab_initial_item))
-       set_item_pointer (&canvas->pointer_item,
-                         canvas->pointer_grab_initial_item);
-      else
-       set_item_pointer (&canvas->pointer_item, NULL);
-
-      set_item_pointer (&canvas->pointer_grab_item, NULL);
-      set_item_pointer (&canvas->pointer_grab_initial_item, NULL);
-
-      update_pointer_item (canvas, (GdkEvent*) event);
+      goo_canvas_finish_pointer_grab (canvas, (GdkEvent*) event);
     }
 
   return retval;
@@ -3534,6 +3559,7 @@ goo_canvas_pointer_grab (GooCanvas     *canvas,
                         GdkCursor     *cursor,
                         guint32        time)
 {
+  GooCanvasPrivate *priv = GOO_CANVAS_GET_PRIVATE (canvas);
   GdkGrabStatus status = GDK_GRAB_SUCCESS;
   GdkDisplay *display;
 
@@ -3570,6 +3596,7 @@ goo_canvas_pointer_grab (GooCanvas     *canvas,
                             canvas->pointer_item);
       set_item_pointer (&canvas->pointer_grab_item,
                             item);
+      priv->pointer_grab_is_implicit = FALSE;
     }
 
   return status;
@@ -3610,20 +3637,8 @@ goo_canvas_pointer_ungrab (GooCanvas     *canvas,
     gdk_display_pointer_ungrab (display, time);
 #endif
 
-  /* We set the pointer item back to the item it was in before the
-     grab, so we'll synthesize enter/leave notify events as appropriate. */
-  if (canvas->pointer_grab_initial_item
-      && ITEM_IS_VALID (canvas->pointer_grab_initial_item))
-    set_item_pointer (&canvas->pointer_item,
-                     canvas->pointer_grab_initial_item);
-  else
-    set_item_pointer (&canvas->pointer_item, NULL);
-
-  set_item_pointer (&canvas->pointer_grab_item, NULL);
-  set_item_pointer (&canvas->pointer_grab_initial_item, NULL);
-
-  update_pointer_item (canvas, NULL);
- }
+  goo_canvas_finish_pointer_grab (canvas, NULL);
+}
 
 
 /**


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