emacs-diffs
[Top][All Lists]
Advanced

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

master 86d128c6c3: Try to save selections from being disowned during fra


From: Po Lu
Subject: master 86d128c6c3: Try to save selections from being disowned during frame deletion
Date: Mon, 11 Jul 2022 22:48:03 -0400 (EDT)

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

    Try to save selections from being disowned during frame deletion
    
    * lisp/cus-start.el (standard): Add
    `x-auto-preserve-selections'.
    * src/xselect.c (x_clear_frame_selections): Collect deleted
    selections into a variable and preserve them.
    * src/xterm.c (x_preserve_selections): New function.
    (syms_of_xterm): New variable `x-auto-preserve-selections'.
    * src/xterm.h: Update prototypes.
---
 etc/NEWS          |  9 ++++++++
 lisp/cus-start.el |  3 +++
 src/xselect.c     | 24 ++++++++++++++-------
 src/xterm.c       | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/xterm.h       |  1 +
 5 files changed, 93 insertions(+), 7 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index bf36316890..c2900b0bc4 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -2448,6 +2448,15 @@ be kept aligned with the buffer contents when the user 
switches
 This minor mode makes Emacs deactivate the mark in all buffers when
 the primary selection is obtained by another program.
 
+---
+** On X, Emacs will try to preserve selection ownership when a frame is 
deleted.
+This means that if you make Emacs the owner of a selection, such as by
+selecting some text into the clipboard or primary selection, and then
+delete the current frame, you will still be able to insert the
+contents of that selection into other programs as long as another
+frame is open on the same display.  This behavior can be disabled by
+setting the variable 'x-auto-preserve-selections' to nil.
+
 +++
 ** New predicate 'char-uppercase-p'.
 This returns non-nil if its argument its an uppercase character.
diff --git a/lisp/cus-start.el b/lisp/cus-start.el
index ca2fca4eb7..df919fd715 100644
--- a/lisp/cus-start.el
+++ b/lisp/cus-start.el
@@ -834,6 +834,7 @@ since it could result in memory overflow and make Emacs 
crash."
              (x-scroll-event-delta-factor mouse float "29.1")
              (x-gtk-use-native-input keyboard boolean "29.1")
              (x-dnd-disable-motif-drag dnd boolean "29.1")
+             (x-auto-preserve-selections x boolean "29.1")
             ;; xselect.c
             (x-select-enable-clipboard-manager killing boolean "24.1")
             ;; xsettings.c
@@ -874,6 +875,8 @@ since it could result in memory overflow and make Emacs 
crash."
                            (equal "x-scroll-event-delta-factor"
                                   (symbol-name symbol))
                            (equal "x-dnd-disable-motif-drag"
+                                  (symbol-name symbol))
+                           (equal "x-auto-preserve-selections"
                                   (symbol-name symbol)))
                       (featurep 'x))
                      ((string-match "\\`x-" (symbol-name symbol))
diff --git a/src/xselect.c b/src/xselect.c
index 25a75aec91..baab2c5c18 100644
--- a/src/xselect.c
+++ b/src/xselect.c
@@ -1091,20 +1091,23 @@ x_handle_selection_event (struct selection_input_event 
*event)
 void
 x_clear_frame_selections (struct frame *f)
 {
-  Lisp_Object frame;
-  Lisp_Object rest;
+  Lisp_Object frame, rest, lost;
   struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
   struct terminal *t = dpyinfo->terminal;
 
   XSETFRAME (frame, f);
+  lost = Qnil;
 
   /* Delete elements from the beginning of Vselection_alist.  */
   while (CONSP (t->Vselection_alist)
         && EQ (frame, XCAR (XCDR (XCDR (XCDR (XCAR (t->Vselection_alist)))))))
     {
-      /* Run the `x-lost-selection-functions' abnormal hook.  */
-      CALLN (Frun_hook_with_args, Qx_lost_selection_functions,
-            Fcar (Fcar (t->Vselection_alist)));
+      if (!x_auto_preserve_selections)
+       /* Run the `x-lost-selection-functions' abnormal hook.  */
+       CALLN (Frun_hook_with_args, Qx_lost_selection_functions,
+              Fcar (Fcar (t->Vselection_alist)));
+      else
+       lost = Fcons (Fcar (t->Vselection_alist), lost);
 
       tset_selection_alist (t, XCDR (t->Vselection_alist));
     }
@@ -1114,11 +1117,18 @@ x_clear_frame_selections (struct frame *f)
     if (CONSP (XCDR (rest))
        && EQ (frame, XCAR (XCDR (XCDR (XCDR (XCAR (XCDR (rest))))))))
       {
-       CALLN (Frun_hook_with_args, Qx_lost_selection_functions,
-              XCAR (XCAR (XCDR (rest))));
+       if (!x_auto_preserve_selections)
+         CALLN (Frun_hook_with_args, Qx_lost_selection_functions,
+                XCAR (XCAR (XCDR (rest))));
+       else
+         lost = Fcons (XCAR (XCDR (rest)), lost);
+
        XSETCDR (rest, XCDR (XCDR (rest)));
        break;
       }
+
+  if (x_auto_preserve_selections)
+    x_preserve_selections (dpyinfo, lost);
 }
 
 /* True if any properties for DISPLAY and WINDOW
diff --git a/src/xterm.c b/src/xterm.c
index 2b83efb228..f86e4708ec 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -27951,6 +27951,62 @@ x_uncatch_errors_for_lisp (struct x_display_info 
*dpyinfo)
     x_stop_ignoring_errors (dpyinfo);
 }
 
+/* Preserve the selections in LOST in another frame on DPYINFO.  LOST
+   is a list of local selections that were lost, due to their frame
+   being deleted.  */
+
+void
+x_preserve_selections (struct x_display_info *dpyinfo, Lisp_Object lost)
+{
+  Lisp_Object tail, frame, new_owner, tem;
+  Time timestamp;
+  Window owner;
+
+  new_owner = Qnil;
+
+  FOR_EACH_FRAME (tail, frame)
+    {
+      if (FRAME_X_P (XFRAME (frame))
+         && FRAME_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
+       {
+         new_owner = frame;
+         break;
+       }
+    }
+
+  tail = lost;
+
+  FOR_EACH_TAIL_SAFE (tail)
+    {
+      tem = XCAR (tail);
+
+      /* The selection is really lost (since we cannot find a new
+        owner), so run the appropriate hooks.  */
+      if (NILP (new_owner))
+       CALLN (Frun_hook_with_args, Qx_lost_selection_functions,
+              XCAR (tem));
+      else
+       {
+         CONS_TO_INTEGER (XCAR (XCDR (XCDR (tem))), Time, timestamp);
+
+         /* This shouldn't be able to signal any errors, despite the
+            call to `x_check_errors' inside.  */
+         x_own_selection (XCAR (tem), XCAR (XCDR (tem)),
+                          new_owner, XCAR (XCDR (XCDR (XCDR (XCDR (tem))))),
+                          timestamp);
+
+         /* Now check if we still don't own that selection, which can
+            happen if another program set itself as the owner.  */
+         owner = XGetSelectionOwner (dpyinfo->display,
+                                     symbol_to_x_atom (dpyinfo, XCAR (tem)));
+
+         if (owner != FRAME_X_WINDOW (XFRAME (new_owner)))
+           CALLN (Frun_hook_with_args, Qx_lost_selection_functions,
+                  XCAR (tem));
+       }
+    }
+}
+
 void
 syms_of_xterm (void)
 {
@@ -28265,4 +28321,11 @@ reply from the X server, and signal any errors that 
occurred while
 executing the protocol request.  Otherwise, errors will be silently
 ignored without waiting, which is generally faster.  */);
   x_fast_protocol_requests = false;
+
+  DEFVAR_BOOL ("x-auto-preserve-selections", x_auto_preserve_selections,
+    doc: /* Whether or not to transfer selection ownership when deleting a 
frame.
+When non-nil, deleting a frame that is currently the owner of a
+selection will cause its ownership to be transferred to another frame
+on the same display.  */);
+  x_auto_preserve_selections = true;
 }
diff --git a/src/xterm.h b/src/xterm.h
index a1ddf13463..9b91ee4556 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -1643,6 +1643,7 @@ extern void xic_set_statusarea (struct frame *);
 extern void xic_set_xfontset (struct frame *, const char *);
 extern bool x_defined_color (struct frame *, const char *, Emacs_Color *,
                              bool, bool);
+extern void x_preserve_selections (struct x_display_info *, Lisp_Object);
 #ifdef HAVE_X_I18N
 extern void free_frame_xic (struct frame *);
 # if defined HAVE_X_WINDOWS && defined USE_X_TOOLKIT



reply via email to

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