[gtk+/wip/mir2] mir: fix issues with mouse over parent menu



commit e5a1f9a1d326c2e3dd33153d7df5ea13b4eb06bf
Author: William Hua <william attente ca>
Date:   Thu Jan 8 00:24:42 2015 -0500

    mir: fix issues with mouse over parent menu
    
    Mouse over a parent menu[bar] didn't work while the menu was open.
    The fix was to correct the behaviour of pointer crossing events so that
    the pointer appears to be only inside one window at a time.
    
    See: http://tronche.com/gui/x/xlib/events/window-entry-exit/normal.html

 gdk/mir/gdkmir-private.h    |   12 ++++
 gdk/mir/gdkmireventsource.c |  144 +++++++++++++++++++++++++++++++++++--------
 gdk/mir/gdkmirwindowimpl.c  |    2 +-
 3 files changed, 130 insertions(+), 28 deletions(-)
---
diff --git a/gdk/mir/gdkmir-private.h b/gdk/mir/gdkmir-private.h
index e819a7f..6f0b6c3 100644
--- a/gdk/mir/gdkmir-private.h
+++ b/gdk/mir/gdkmir-private.h
@@ -133,4 +133,16 @@ void _gdk_mir_print_resize_event (const MirResizeEvent *event);
 
 void _gdk_mir_print_event (const MirEvent *event);
 
+/* TODO: Remove once we have proper transient window support. */
+GdkWindow * _gdk_mir_window_get_visible_transient_child (GdkWindow *window,
+                                                         gdouble    x,
+                                                         gdouble    y,
+                                                         gdouble   *out_x,
+                                                         gdouble   *out_y);
+
+/* TODO: Remove once we have proper transient window support. */
+void _gdk_mir_window_transient_children_foreach (GdkWindow  *window,
+                                                 void      (*func) (GdkWindow *, gpointer),
+                                                 gpointer    user_data);
+
 #endif /* __GDK_PRIVATE_MIR_H__ */
diff --git a/gdk/mir/gdkmireventsource.c b/gdk/mir/gdkmireventsource.c
index b0e3771..b908366 100644
--- a/gdk/mir/gdkmireventsource.c
+++ b/gdk/mir/gdkmireventsource.c
@@ -292,6 +292,47 @@ handle_key_event (GdkWindow *window, const MirKeyEvent *event)
     }
 }
 
+/* TODO: Remove once we have proper transient window support. */
+typedef struct
+{
+  GdkWindow *except;
+  gdouble    x;
+  gdouble    y;
+  guint32    time;
+} LeaveInfo;
+
+/* TODO: Remove once we have proper transient window support. */
+/*
+ * leave_windows_except:
+ *
+ * Generate a leave event for every window except the one the cursor is in.
+ */
+static void
+leave_windows_except (GdkWindow *window,
+                      gpointer   user_data)
+{
+  LeaveInfo info = *((LeaveInfo *) user_data);
+
+  info.x -= window->x;
+  info.y -= window->y;
+
+  _gdk_mir_window_transient_children_foreach (window, leave_windows_except, &info);
+
+  if (window != info.except)
+    {
+      GdkMirWindowImpl *impl = GDK_MIR_WINDOW_IMPL (window->impl);
+      gboolean cursor_inside;
+      MirMotionButton button_state;
+
+      _gdk_mir_window_impl_get_cursor_state (impl, NULL, NULL, &cursor_inside, &button_state);
+
+      if (cursor_inside)
+        generate_crossing_event (window, GDK_LEAVE_NOTIFY, info.x, info.y, info.time);
+
+      _gdk_mir_window_impl_set_cursor_state (impl, info.x, info.y, FALSE, button_state);
+    }
+}
+
 static void
 handle_motion_event (GdkWindow *window, const MirMotionEvent *event)
 {
@@ -313,36 +354,85 @@ handle_motion_event (GdkWindow *window, const MirMotionEvent *event)
   modifier_state = get_modifier_state (event->modifiers, event->button_state);
   event_time = NANO_TO_MILLI (event->event_time);
 
-  /* Update which window has focus */
-  _gdk_mir_pointer_set_location (get_pointer (window), x, y, window, modifier_state);
-  switch (event->action)
+  /* TODO: Remove once we have proper transient window support. */
+  if (event->action == mir_motion_action_hover_exit)
     {
-    case mir_motion_action_down:
-    case mir_motion_action_up:
-      event_type = event->action == mir_motion_action_down ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE;
-      changed_button_state = button_state ^ event->button_state;
-      if (changed_button_state == 0 || (changed_button_state & mir_motion_button_primary) != 0)
-        generate_button_event (window, event_type, x, y, GDK_BUTTON_PRIMARY, modifier_state, event_time);
-      if ((changed_button_state & mir_motion_button_secondary) != 0)
-        generate_button_event (window, event_type, x, y, GDK_BUTTON_SECONDARY, modifier_state, event_time);
-      if ((changed_button_state & mir_motion_button_tertiary) != 0)
-        generate_button_event (window, event_type, x, y, GDK_BUTTON_MIDDLE, modifier_state, event_time);
-      button_state = event->button_state;
-      break;
-    case mir_motion_action_scroll:
-      generate_scroll_event (window, x, y, event->pointer_coordinates[0].hscroll, 
event->pointer_coordinates[0].vscroll, modifier_state, event_time);
-      break;
-    case mir_motion_action_move: // move with button
-    case mir_motion_action_hover_move: // move without button
-      generate_motion_event (window, x, y, modifier_state, event_time);
-      break;
-    case mir_motion_action_hover_exit:
-      cursor_inside = FALSE;
-      generate_crossing_event (window, GDK_LEAVE_NOTIFY, x, y, event_time);
-      break;
+      LeaveInfo info;
+
+      info.x = x;
+      info.y = y;
+      info.time = event_time;
+      info.except = window;
+
+      /* Leave all transient children from leaf to root, except the root since we do it later. */
+      _gdk_mir_window_transient_children_foreach (window, leave_windows_except, &info);
+    }
+  else
+    {
+      LeaveInfo info;
+
+      info.x = x;
+      info.y = y;
+      info.time = event_time;
+      info.except = _gdk_mir_window_get_visible_transient_child (window, x, y, &x, &y);
+
+      /* Leave all transient children from leaf to root, except the pointer window since we enter it. */
+      _gdk_mir_window_transient_children_foreach (window, leave_windows_except, &info);
+
+      window = info.except;
+
+      if (window)
+        {
+          /* Enter the pointer window. */
+          gboolean cursor_inside_pointer_window;
+
+          impl = GDK_MIR_WINDOW_IMPL (window->impl);
+          _gdk_mir_window_impl_get_cursor_state (impl, NULL, NULL, &cursor_inside_pointer_window, NULL);
+
+          if (!cursor_inside_pointer_window)
+            {
+              generate_crossing_event (window, GDK_ENTER_NOTIFY, x, y, event_time);
+              _gdk_mir_window_impl_set_cursor_state (impl, x, y, TRUE, event->button_state);
+            }
+        }
     }
 
-  _gdk_mir_window_impl_set_cursor_state (impl, x, y, cursor_inside, button_state);
+  if (window)
+    {
+      /* Update which window has focus */
+      _gdk_mir_pointer_set_location (get_pointer (window), x, y, window, modifier_state);
+      switch (event->action)
+        {
+        case mir_motion_action_down:
+        case mir_motion_action_up:
+          event_type = event->action == mir_motion_action_down ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE;
+          changed_button_state = button_state ^ event->button_state;
+          if (changed_button_state == 0 || (changed_button_state & mir_motion_button_primary) != 0)
+            generate_button_event (window, event_type, x, y, GDK_BUTTON_PRIMARY, modifier_state, event_time);
+          if ((changed_button_state & mir_motion_button_secondary) != 0)
+            generate_button_event (window, event_type, x, y, GDK_BUTTON_SECONDARY, modifier_state, 
event_time);
+          if ((changed_button_state & mir_motion_button_tertiary) != 0)
+            generate_button_event (window, event_type, x, y, GDK_BUTTON_MIDDLE, modifier_state, event_time);
+          button_state = event->button_state;
+          break;
+        case mir_motion_action_scroll:
+          generate_scroll_event (window, x, y, event->pointer_coordinates[0].hscroll, 
event->pointer_coordinates[0].vscroll, modifier_state, event_time);
+          break;
+        case mir_motion_action_move: // move with button
+        case mir_motion_action_hover_move: // move without button
+          generate_motion_event (window, x, y, modifier_state, event_time);
+          break;
+        case mir_motion_action_hover_exit:
+          if (cursor_inside)
+            {
+              cursor_inside = FALSE;
+              generate_crossing_event (window, GDK_LEAVE_NOTIFY, x, y, event_time);
+            }
+          break;
+        }
+
+      _gdk_mir_window_impl_set_cursor_state (impl, x, y, cursor_inside, button_state);
+    }
 }
 
 static void
diff --git a/gdk/mir/gdkmirwindowimpl.c b/gdk/mir/gdkmirwindowimpl.c
index d4a4f2d..37f96dc 100644
--- a/gdk/mir/gdkmirwindowimpl.c
+++ b/gdk/mir/gdkmirwindowimpl.c
@@ -288,7 +288,7 @@ redraw_transient (GdkWindow *window)
   gdk_window_invalidate_rect (GDK_MIR_WINDOW_IMPL (window->impl)->transient_for, &r, FALSE);
 }
 
-/* Remove once we have proper transient window support. */
+/* TODO: Remove once we have proper transient window support. */
 static gboolean
 should_render_in_parent (GdkWindow *window)
 {


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