emacs-diffs
[Top][All Lists]
Advanced

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

master 8b853b3f98 1/2: Reported taken action correctly when dragging to


From: Po Lu
Subject: master 8b853b3f98 1/2: Reported taken action correctly when dragging to another frame on X
Date: Tue, 22 Mar 2022 21:21:57 -0400 (EDT)

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

    Reported taken action correctly when dragging to another frame on X
    
    * src/xterm.c (x_dnd_cleanup_drag_and_drop, x_dnd_update_state)
    (x_free_frame_resources, handle_one_xevent): Set
    `x_dnd_end_window'.
    (x_dnd_begin_drag_and_drop): Return `XdndActionPrivate' if the
    drop landed on one of our own frames.
---
 src/xterm.c | 383 ++++++++++++++++++++++++++++++++----------------------------
 1 file changed, 205 insertions(+), 178 deletions(-)

diff --git a/src/xterm.c b/src/xterm.c
index a7d8445502..550515aeff 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -805,6 +805,7 @@ static int x_dnd_return_frame;
 static struct frame *x_dnd_return_frame_object;
 
 static Window x_dnd_last_seen_window;
+static Window x_dnd_end_window;
 static int x_dnd_last_protocol_version;
 static Time x_dnd_selection_timestamp;
 
@@ -1173,6 +1174,8 @@ x_dnd_cleanup_drag_and_drop (void *frame)
                          x_dnd_last_seen_window);
       unblock_input ();
 
+      x_dnd_end_window = x_dnd_last_seen_window;
+      x_dnd_last_seen_window = None;
       x_dnd_in_progress = false;
       x_set_dnd_targets (NULL, 0);
     }
@@ -1194,184 +1197,6 @@ x_dnd_cleanup_drag_and_drop (void *frame)
   x_dnd_frame = NULL;
 }
 
-Lisp_Object
-x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
-                          bool return_frame_p)
-{
-#ifndef USE_GTK
-  XEvent next_event;
-  int finish;
-#endif
-  XWindowAttributes root_window_attrs;
-
-  struct input_event hold_quit;
-  char *atom_name;
-  Lisp_Object action, ltimestamp;
-  specpdl_ref ref;
-
-  if (!FRAME_VISIBLE_P (f))
-    error ("Frame is invisible");
-
-  if (x_dnd_in_progress || x_dnd_waiting_for_finish)
-    error ("A drag-and-drop session is already in progress");
-
-  ltimestamp = x_timestamp_for_selection (FRAME_DISPLAY_INFO (f),
-                                         QXdndSelection);
-
-  if (NILP (ltimestamp))
-    error ("No local value for XdndSelection");
-
-  if (BIGNUMP (ltimestamp))
-    x_dnd_selection_timestamp = bignum_to_intmax (ltimestamp);
-  else
-    x_dnd_selection_timestamp = XFIXNUM (ltimestamp);
-
-  x_dnd_in_progress = true;
-  x_dnd_frame = f;
-  x_dnd_last_seen_window = FRAME_X_WINDOW (f);
-  x_dnd_last_protocol_version = -1;
-  x_dnd_mouse_rect_target = None;
-  x_dnd_action = None;
-  x_dnd_wanted_action = xaction;
-  x_dnd_return_frame = 0;
-  x_dnd_waiting_for_finish = false;
-
-  if (return_frame_p)
-    x_dnd_return_frame = 1;
-
-#ifdef USE_GTK
-  current_count = 0;
-#endif
-
-  /* Now select for SubstructureNotifyMask and PropertyNotifyMask on
-     the root window, so we can get notified when window stacking
-     changes, a common operation during drag-and-drop.  */
-
-  block_input ();
-  XGetWindowAttributes (FRAME_X_DISPLAY (f),
-                       FRAME_DISPLAY_INFO (f)->root_window,
-                       &root_window_attrs);
-
-  XSelectInput (FRAME_X_DISPLAY (f),
-               FRAME_DISPLAY_INFO (f)->root_window,
-               root_window_attrs.your_event_mask
-               | SubstructureNotifyMask
-               | PropertyChangeMask);
-
-  while (x_dnd_in_progress || x_dnd_waiting_for_finish)
-    {
-      hold_quit.kind = NO_EVENT;
-#ifdef USE_GTK
-      current_finish = X_EVENT_NORMAL;
-      current_hold_quit = &hold_quit;
-#endif
-
-#ifndef USE_GTK
-      XNextEvent (FRAME_X_DISPLAY (f), &next_event);
-
-#ifdef HAVE_X_I18N
-#ifdef HAVE_XINPUT2
-      if (next_event.type != GenericEvent
-         || !FRAME_DISPLAY_INFO (f)->supports_xi2
-         || (next_event.xgeneric.extension
-             != FRAME_DISPLAY_INFO (f)->xi2_opcode))
-       {
-#endif
-         if (!x_filter_event (FRAME_DISPLAY_INFO (f), &next_event))
-           handle_one_xevent (FRAME_DISPLAY_INFO (f),
-                              &next_event, &finish, &hold_quit);
-#ifdef HAVE_XINPUT2
-       }
-      else
-       handle_one_xevent (FRAME_DISPLAY_INFO (f),
-                          &next_event, &finish, &hold_quit);
-#endif
-#else
-      handle_one_xevent (FRAME_DISPLAY_INFO (f),
-                        &next_event, &finish, &hold_quit);
-#endif
-#else
-      gtk_main_iteration ();
-#endif
-
-      if (hold_quit.kind != NO_EVENT)
-       {
-         if (hold_quit.kind == SELECTION_REQUEST_EVENT)
-           {
-             x_dnd_old_window_attrs = root_window_attrs;
-             x_dnd_unwind_flag = true;
-
-             ref = SPECPDL_INDEX ();
-             record_unwind_protect_ptr (x_dnd_cleanup_drag_and_drop, f);
-             x_handle_selection_event ((struct selection_input_event *) 
&hold_quit);
-             x_dnd_unwind_flag = false;
-             unbind_to (ref, Qnil);
-             continue;
-           }
-
-         if (x_dnd_in_progress)
-           {
-             if (x_dnd_last_seen_window != None
-                 && x_dnd_last_protocol_version != -1)
-               x_dnd_send_leave (f, x_dnd_last_seen_window);
-
-             x_dnd_in_progress = false;
-             x_dnd_frame = NULL;
-             x_set_dnd_targets (NULL, 0);
-             x_dnd_waiting_for_finish = false;
-           }
-
-         FRAME_DISPLAY_INFO (f)->grabbed = 0;
-#ifdef USE_GTK
-         current_hold_quit = NULL;
-#endif
-         /* Restore the old event mask.  */
-         XSelectInput (FRAME_X_DISPLAY (f),
-                       FRAME_DISPLAY_INFO (f)->root_window,
-                       root_window_attrs.your_event_mask);
-         unblock_input ();
-         quit ();
-       }
-    }
-  x_set_dnd_targets (NULL, 0);
-  x_dnd_waiting_for_finish = false;
-
-#ifdef USE_GTK
-  current_hold_quit = NULL;
-#endif
-
-  /* Restore the old event mask.  */
-  XSelectInput (FRAME_X_DISPLAY (f),
-               FRAME_DISPLAY_INFO (f)->root_window,
-               root_window_attrs.your_event_mask);
-
-  unblock_input ();
-
-  if (x_dnd_return_frame == 3)
-    {
-      x_dnd_return_frame_object->mouse_moved = true;
-
-      XSETFRAME (action, x_dnd_return_frame_object);
-      return action;
-    }
-
-  FRAME_DISPLAY_INFO (f)->grabbed = 0;
-
-  if (x_dnd_action != None)
-    {
-      block_input ();
-      atom_name = XGetAtomName (FRAME_X_DISPLAY (f),
-                               x_dnd_action);
-      action = intern (atom_name);
-      XFree (atom_name);
-      unblock_input ();
-
-      return action;
-    }
-
-  return Qnil;
-}
-
 /* Flush display of frame F.  */
 
 static void
@@ -7112,6 +6937,198 @@ x_top_window_to_frame (struct x_display_info *dpyinfo, 
int wdesc)
 
 #endif /* USE_X_TOOLKIT || USE_GTK */
 
+/* This function is defined far away from the rest of the XDND code so
+   it can utilize `x_any_window_to_frame'.  */
+
+Lisp_Object
+x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
+                          bool return_frame_p)
+{
+#ifndef USE_GTK
+  XEvent next_event;
+  int finish;
+#endif
+  XWindowAttributes root_window_attrs;
+
+  struct input_event hold_quit;
+  char *atom_name;
+  Lisp_Object action, ltimestamp;
+  specpdl_ref ref;
+
+  if (!FRAME_VISIBLE_P (f))
+    error ("Frame is invisible");
+
+  if (x_dnd_in_progress || x_dnd_waiting_for_finish)
+    error ("A drag-and-drop session is already in progress");
+
+  ltimestamp = x_timestamp_for_selection (FRAME_DISPLAY_INFO (f),
+                                         QXdndSelection);
+
+  if (NILP (ltimestamp))
+    error ("No local value for XdndSelection");
+
+  if (BIGNUMP (ltimestamp))
+    x_dnd_selection_timestamp = bignum_to_intmax (ltimestamp);
+  else
+    x_dnd_selection_timestamp = XFIXNUM (ltimestamp);
+
+  x_dnd_in_progress = true;
+  x_dnd_frame = f;
+  x_dnd_last_seen_window = FRAME_X_WINDOW (f);
+  x_dnd_last_protocol_version = -1;
+  x_dnd_mouse_rect_target = None;
+  x_dnd_action = None;
+  x_dnd_wanted_action = xaction;
+  x_dnd_return_frame = 0;
+  x_dnd_waiting_for_finish = false;
+  x_dnd_end_window = None;
+
+  if (return_frame_p)
+    x_dnd_return_frame = 1;
+
+#ifdef USE_GTK
+  current_count = 0;
+#endif
+
+  /* Now select for SubstructureNotifyMask and PropertyNotifyMask on
+     the root window, so we can get notified when window stacking
+     changes, a common operation during drag-and-drop.  */
+
+  block_input ();
+  XGetWindowAttributes (FRAME_X_DISPLAY (f),
+                       FRAME_DISPLAY_INFO (f)->root_window,
+                       &root_window_attrs);
+
+  XSelectInput (FRAME_X_DISPLAY (f),
+               FRAME_DISPLAY_INFO (f)->root_window,
+               root_window_attrs.your_event_mask
+               | SubstructureNotifyMask
+               | PropertyChangeMask);
+
+  while (x_dnd_in_progress || x_dnd_waiting_for_finish)
+    {
+      hold_quit.kind = NO_EVENT;
+#ifdef USE_GTK
+      current_finish = X_EVENT_NORMAL;
+      current_hold_quit = &hold_quit;
+#endif
+
+#ifndef USE_GTK
+      XNextEvent (FRAME_X_DISPLAY (f), &next_event);
+
+#ifdef HAVE_X_I18N
+#ifdef HAVE_XINPUT2
+      if (next_event.type != GenericEvent
+         || !FRAME_DISPLAY_INFO (f)->supports_xi2
+         || (next_event.xgeneric.extension
+             != FRAME_DISPLAY_INFO (f)->xi2_opcode))
+       {
+#endif
+         if (!x_filter_event (FRAME_DISPLAY_INFO (f), &next_event))
+           handle_one_xevent (FRAME_DISPLAY_INFO (f),
+                              &next_event, &finish, &hold_quit);
+#ifdef HAVE_XINPUT2
+       }
+      else
+       handle_one_xevent (FRAME_DISPLAY_INFO (f),
+                          &next_event, &finish, &hold_quit);
+#endif
+#else
+      handle_one_xevent (FRAME_DISPLAY_INFO (f),
+                        &next_event, &finish, &hold_quit);
+#endif
+#else
+      gtk_main_iteration ();
+#endif
+
+      if (hold_quit.kind != NO_EVENT)
+       {
+         if (hold_quit.kind == SELECTION_REQUEST_EVENT)
+           {
+             x_dnd_old_window_attrs = root_window_attrs;
+             x_dnd_unwind_flag = true;
+
+             ref = SPECPDL_INDEX ();
+             record_unwind_protect_ptr (x_dnd_cleanup_drag_and_drop, f);
+             x_handle_selection_event ((struct selection_input_event *) 
&hold_quit);
+             x_dnd_unwind_flag = false;
+             unbind_to (ref, Qnil);
+             continue;
+           }
+
+         if (x_dnd_in_progress)
+           {
+             if (x_dnd_last_seen_window != None
+                 && x_dnd_last_protocol_version != -1)
+               x_dnd_send_leave (f, x_dnd_last_seen_window);
+
+             x_dnd_end_window = x_dnd_last_seen_window;
+             x_dnd_last_seen_window = None;
+             x_dnd_in_progress = false;
+             x_dnd_frame = NULL;
+             x_set_dnd_targets (NULL, 0);
+             x_dnd_waiting_for_finish = false;
+           }
+
+         FRAME_DISPLAY_INFO (f)->grabbed = 0;
+#ifdef USE_GTK
+         current_hold_quit = NULL;
+#endif
+         /* Restore the old event mask.  */
+         XSelectInput (FRAME_X_DISPLAY (f),
+                       FRAME_DISPLAY_INFO (f)->root_window,
+                       root_window_attrs.your_event_mask);
+         unblock_input ();
+         quit ();
+       }
+    }
+  x_set_dnd_targets (NULL, 0);
+  x_dnd_waiting_for_finish = false;
+
+#ifdef USE_GTK
+  current_hold_quit = NULL;
+#endif
+
+  /* Restore the old event mask.  */
+  XSelectInput (FRAME_X_DISPLAY (f),
+               FRAME_DISPLAY_INFO (f)->root_window,
+               root_window_attrs.your_event_mask);
+
+  unblock_input ();
+
+  if (x_dnd_return_frame == 3)
+    {
+      x_dnd_return_frame_object->mouse_moved = true;
+
+      XSETFRAME (action, x_dnd_return_frame_object);
+      return action;
+    }
+
+  FRAME_DISPLAY_INFO (f)->grabbed = 0;
+
+  /* Emacs can't respond to DND events inside the nested event
+     loop, so when dragging items to itself, always return
+     XdndActionPrivate.  */
+  if (x_dnd_end_window != None
+      && (x_any_window_to_frame (FRAME_DISPLAY_INFO (f),
+                                x_dnd_end_window) != f))
+    return QXdndActionPrivate;
+
+  if (x_dnd_action != None)
+    {
+      block_input ();
+      atom_name = XGetAtomName (FRAME_X_DISPLAY (f),
+                               x_dnd_action);
+      action = intern (atom_name);
+      XFree (atom_name);
+      unblock_input ();
+
+      return action;
+    }
+
+  return Qnil;
+}
+
 /* The focus may have changed.  Figure out if it is a real focus change,
    by checking both FocusIn/Out and Enter/LeaveNotify events.
 
@@ -10698,6 +10715,8 @@ x_dnd_update_state (struct x_display_info *dpyinfo)
          if (x_dnd_return_frame == 2
              && x_any_window_to_frame (dpyinfo, target))
            {
+             x_dnd_end_window = x_dnd_last_seen_window;
+             x_dnd_last_seen_window = None;
              x_dnd_in_progress = false;
              x_dnd_return_frame_object
                = x_any_window_to_frame (dpyinfo, target);
@@ -10728,6 +10747,8 @@ x_dnd_update_state (struct x_display_info *dpyinfo)
        x_dnd_send_leave (x_dnd_frame,
                          x_dnd_last_seen_window);
 
+      x_dnd_end_window = x_dnd_last_seen_window;
+      x_dnd_last_seen_window = None;
       x_dnd_in_progress = false;
       x_dnd_frame = NULL;
     }
@@ -12047,6 +12068,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                if (x_dnd_return_frame == 2
                    && x_any_window_to_frame (dpyinfo, target))
                  {
+                   x_dnd_end_window = x_dnd_last_seen_window;
+                   x_dnd_last_seen_window = None;
                    x_dnd_in_progress = false;
                    x_dnd_return_frame_object
                      = x_any_window_to_frame (dpyinfo, target);
@@ -12439,6 +12462,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
            if (dnd_grab && event->xbutton.type == ButtonRelease)
              {
+               x_dnd_end_window = x_dnd_last_seen_window;
                x_dnd_in_progress = false;
 
                if (x_dnd_last_seen_window != None
@@ -13436,6 +13460,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                  if (!dnd_grab
                      && xev->evtype == XI_ButtonRelease)
                    {
+                     x_dnd_end_window = x_dnd_last_seen_window;
                      x_dnd_in_progress = false;
 
                      if (x_dnd_last_seen_window != None
@@ -17571,6 +17596,8 @@ x_free_frame_resources (struct frame *f)
        x_dnd_send_leave (f, x_dnd_last_seen_window);
       unblock_input ();
 
+      x_dnd_end_window = x_dnd_last_seen_window;
+      x_dnd_last_seen_window = None;
       x_dnd_in_progress = false;
       x_dnd_waiting_for_finish = false;
       x_dnd_frame = NULL;



reply via email to

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