emacs-diffs
[Top][All Lists]
Advanced

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

master b89ae23636: Implement crossing event generation between windows f


From: Po Lu
Subject: master b89ae23636: Implement crossing event generation between windows for xwidgets on X
Date: Thu, 27 Jan 2022 01:00:57 -0500 (EST)

branch: master
commit b89ae23636f42962194f74e8958ac785b245590c
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Implement crossing event generation between windows for xwidgets on X
    
    * src/xwidget.c (enum xw_crossing_mode): New enum.
    (xwidget_motion_notify):
    (xwidget_motion_or_crossing): Synthesize crossing events if the
    pointer moved between different windows.
    (window_coords_from_toplevel):
    (xw_maybe_synthesize_crossing): New functions.
    (xwidget_init_view): Initialize new field to NULL.
    (Fdelete_xwidget_view): Clear last crossing window.
    
    * src/xwidget.h (struct xwidget_view): New field
    `last_crossing_window'.
---
 src/xwidget.c | 188 +++++++++++++++++++++++++++++++++++++++++++++++++++-------
 src/xwidget.h |   2 +
 2 files changed, 170 insertions(+), 20 deletions(-)

diff --git a/src/xwidget.c b/src/xwidget.c
index 822bed0349..c42d1609d7 100644
--- a/src/xwidget.c
+++ b/src/xwidget.c
@@ -224,6 +224,13 @@ xw_forward_event_from_view (GtkWidget *widget, GdkEvent 
*event,
 #endif
 
 #ifdef HAVE_X_WINDOWS
+enum xw_crossing_mode
+  {
+    XW_CROSSING_LEFT,
+    XW_CROSSING_ENTERED,
+    XW_CROSSING_NONE
+  };
+
 static guint
 xw_translate_x_modifiers (struct x_display_info *dpyinfo,
                          unsigned int modifiers)
@@ -253,6 +260,10 @@ xw_translate_x_modifiers (struct x_display_info *dpyinfo,
 
   return mods;
 }
+
+static bool xw_maybe_synthesize_crossing (struct xwidget_view *,
+                                         GdkWindow *, int, int, int,
+                                         Time, unsigned int);
 #endif
 
 DEFUN ("make-xwidget",
@@ -1222,10 +1233,14 @@ xwidget_motion_notify (struct xwidget_view *view,
 
   if (!target)
     {
-      target_x = lrint (x);
-      target_y = lrint (y);
+      target_x = lrint (x + view->clip_left);
+      target_y = lrint (y + view->clip_top);
       target = model->widget_osr;
     }
+  else if (xw_maybe_synthesize_crossing (view, gtk_widget_get_window (target),
+                                        x + view->clip_left, y + 
view->clip_top,
+                                        XW_CROSSING_NONE, time, state))
+    return;
 
   xg_event = gdk_event_new (GDK_MOTION_NOTIFY);
   xg_event->any.window = gtk_widget_get_window (target);
@@ -1377,13 +1392,106 @@ xi_translate_notify_detail (int detail)
 }
 #endif
 
+static void
+window_coords_from_toplevel (GdkWindow *window, GdkWindow *toplevel,
+                            int x, int y, int *out_x, int *out_y)
+{
+  GdkWindow *parent;
+  GList *children, *l;
+  gdouble x_out, y_out;
+
+  children = NULL;
+  while ((parent = gdk_window_get_parent (window)) != toplevel)
+    {
+      children = g_list_prepend (children, window);
+      window = parent;
+    }
+
+  for (l = children; l != NULL; l = l->next)
+    gdk_window_coords_from_parent (l->data, x, y, &x_out, &y_out);
+
+  g_list_free (children);
+
+  *out_x = x_out;
+  *out_y = y_out;
+}
+
+static bool
+xw_maybe_synthesize_crossing (struct xwidget_view *view,
+                             GdkWindow *current_window,
+                             int x, int y, int crossing,
+                             Time time, unsigned int state)
+{
+  GdkWindow *last_crossing;
+  GdkEvent *xg_event;
+  GdkWindow *toplevel;
+  int cx, cy;
+
+  if (view->last_crossing_window
+      && (gdk_window_is_destroyed (view->last_crossing_window)
+         || crossing == XW_CROSSING_LEFT))
+    g_clear_pointer (&view->last_crossing_window,
+                    g_object_unref);
+  last_crossing = view->last_crossing_window;
+
+  if (!last_crossing)
+    {
+      view->last_crossing_window = g_object_ref (current_window);
+      return false;
+    }
+
+  toplevel = gtk_widget_get_window (XXWIDGET (view->model)->widgetwindow_osr);
+
+  if (last_crossing != current_window)
+    {
+      view->last_crossing_window = g_object_ref (current_window);
+
+      xg_event = gdk_event_new (GDK_LEAVE_NOTIFY);
+      gdk_event_set_device (xg_event, find_suitable_pointer (view->frame));
+      window_coords_from_toplevel (last_crossing, toplevel,
+                                  x, y, &cx, &cy);
+      xg_event->crossing.x = cx;
+      xg_event->crossing.y = cy;
+      xg_event->crossing.time = time;
+      xg_event->crossing.focus = FALSE;
+      xg_event->crossing.state = state;
+      /* TODO: actually calculate the event detail and mode.  */
+      xg_event->crossing.detail = GDK_NOTIFY_NONLINEAR;
+      xg_event->crossing.mode = GDK_CROSSING_NORMAL;
+      xg_event->crossing.window = g_object_ref (last_crossing);
+
+      gtk_main_do_event (xg_event);
+      gdk_event_free (xg_event);
+
+      xg_event = gdk_event_new (GDK_ENTER_NOTIFY);
+      gdk_event_set_device (xg_event, find_suitable_pointer (view->frame));
+      window_coords_from_toplevel (current_window, toplevel,
+                                  x, y, &cx, &cy);
+      xg_event->crossing.x = cx;
+      xg_event->crossing.y = cy;
+      xg_event->crossing.time = time;
+      xg_event->crossing.focus = FALSE;
+      xg_event->crossing.state = state;
+      xg_event->crossing.detail = GDK_NOTIFY_NONLINEAR;
+      xg_event->crossing.mode = GDK_CROSSING_NORMAL;
+      xg_event->crossing.window = g_object_ref (current_window);
+
+      gtk_main_do_event (xg_event);
+      gdk_event_free (xg_event);
+      g_object_unref (last_crossing);
+
+      return true;
+    }
+
+  return false;
+}
+
 void
 xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event)
 {
   GdkEvent *xg_event;
   struct xwidget *model = XXWIDGET (view->model);
-  int x;
-  int y;
+  int x, y, toplevel_x, toplevel_y;
   GtkWidget *target;
 #ifdef HAVE_XINPUT2
   XIEnterEvent *xev = NULL;
@@ -1401,14 +1509,14 @@ xwidget_motion_or_crossing (struct xwidget_view *view, 
const XEvent *event)
                                : (event->type == LeaveNotify
                                   ? GDK_LEAVE_NOTIFY
                                   : GDK_ENTER_NOTIFY));
+      toplevel_x = (event->type == MotionNotify
+                   ? event->xmotion.x + view->clip_left
+                   : event->xcrossing.x + view->clip_left);
+      toplevel_y = (event->type == MotionNotify
+                   ? event->xmotion.y + view->clip_top
+                   : event->xcrossing.y + view->clip_top);
       target = find_widget_at_pos (model->widgetwindow_osr,
-                                  (event->type == MotionNotify
-                                   ? event->xmotion.x + view->clip_left
-                                   : event->xcrossing.x + view->clip_left),
-                                  (event->type == MotionNotify
-                                   ? event->xmotion.y + view->clip_top
-                                   : event->xcrossing.y + view->clip_top),
-                                  &x, &y);
+                                  toplevel_x, toplevel_y, &x, &y);
     }
 #ifdef HAVE_XINPUT2
   else
@@ -1421,8 +1529,10 @@ xwidget_motion_or_crossing (struct xwidget_view *view, 
const XEvent *event)
                                ? GDK_ENTER_NOTIFY
                                : GDK_LEAVE_NOTIFY);
       target = find_widget_at_pos (model->widgetwindow_osr,
-                                  lrint (xev->event_x + view->clip_left),
-                                  lrint (xev->event_y + view->clip_top),
+                                  (toplevel_x
+                                   = lrint (xev->event_x + view->clip_left)),
+                                  (toplevel_y
+                                   = lrint (xev->event_y + view->clip_top)),
                                   &x, &y);
     }
 #endif
@@ -1437,13 +1547,24 @@ xwidget_motion_or_crossing (struct xwidget_view *view, 
const XEvent *event)
 
   if (event->type == MotionNotify)
     {
-      xg_event->motion.x = x;
-      xg_event->motion.y = y;
-      xg_event->motion.x_root = event->xmotion.x_root;
-      xg_event->motion.y_root = event->xmotion.y_root;
-      xg_event->motion.time = event->xmotion.time;
-      xg_event->motion.state = event->xmotion.state;
-      xg_event->motion.device = find_suitable_pointer (view->frame);
+      if (!xw_maybe_synthesize_crossing (view, xg_event->any.window,
+                                        toplevel_x, toplevel_y,
+                                        XW_CROSSING_NONE, event->xmotion.time,
+                                        event->xmotion.state))
+       {
+         xg_event->motion.x = x;
+         xg_event->motion.y = y;
+         xg_event->motion.x_root = event->xmotion.x_root;
+         xg_event->motion.y_root = event->xmotion.y_root;
+         xg_event->motion.time = event->xmotion.time;
+         xg_event->motion.state = event->xmotion.state;
+         xg_event->motion.device = find_suitable_pointer (view->frame);
+       }
+      else
+       {
+         gdk_event_free (xg_event);
+         return;
+       }
     }
 #ifdef HAVE_XINPUT2
   else if (event->type == GenericEvent)
@@ -1468,11 +1589,34 @@ xwidget_motion_or_crossing (struct xwidget_view *view, 
const XEvent *event)
            xg_event->crossing.state |= GDK_BUTTON3_MASK;
        }
 
+      if (xw_maybe_synthesize_crossing (view, xg_event->any.window,
+                                       toplevel_x, toplevel_y,
+                                       (xev->type == XI_Enter
+                                        ? XW_CROSSING_ENTERED
+                                        : XW_CROSSING_LEFT),
+                                       xev->time, xg_event->crossing.state))
+       {
+         gdk_event_free (xg_event);
+         return;
+       }
+
       gdk_event_set_device (xg_event, find_suitable_pointer (view->frame));
     }
 #endif
   else
     {
+      if (xw_maybe_synthesize_crossing (view, xg_event->any.window,
+                                       toplevel_x, toplevel_y,
+                                       (event->type == EnterNotify
+                                        ? XW_CROSSING_ENTERED
+                                        : XW_CROSSING_LEFT),
+                                       event->xcrossing.time,
+                                       event->xcrossing.state))
+       {
+         gdk_event_free (xg_event);
+         return;
+       }
+
       xg_event->crossing.detail = min (5, event->xcrossing.detail);
       xg_event->crossing.time = event->xcrossing.time;
       xg_event->crossing.x = x;
@@ -2135,6 +2279,7 @@ xwidget_init_view (struct xwidget *xww,
   xv->frame = s->f;
   xv->cursor = cursor_for_hit (xww->hit_result, s->f);
   xv->just_resized = false;
+  xv->last_crossing_window = NULL;
 #elif defined HAVE_PGTK
   xv->dpyinfo = FRAME_DISPLAY_INFO (s->f);
   xv->widget = gtk_drawing_area_new ();
@@ -2757,6 +2902,9 @@ DEFUN ("delete-xwidget-view",
       XDestroyWindow (xv->dpy, xv->wdesc);
       Fremhash (make_fixnum (xv->wdesc), x_window_to_xwv_map);
     }
+
+  g_clear_pointer (&xv->last_crossing_window,
+                  g_object_unref);
 #else
   gtk_widget_destroy (xv->widget);
 #endif
diff --git a/src/xwidget.h b/src/xwidget.h
index ee74e53c4d..5f05a5f59d 100644
--- a/src/xwidget.h
+++ b/src/xwidget.h
@@ -118,6 +118,8 @@ struct xwidget_view
 #ifndef HAVE_PGTK
   Display *dpy;
   Window wdesc;
+
+  GdkWindow *last_crossing_window;
 #else
   struct pgtk_display_info *dpyinfo;
   GtkWidget *widget;



reply via email to

[Prev in Thread] Current Thread [Next in Thread]