]> git.eshelyaron.com Git - emacs.git/commitdiff
Try to save selections from being disowned during frame deletion
authorPo Lu <luangruo@yahoo.com>
Tue, 12 Jul 2022 02:47:23 +0000 (10:47 +0800)
committerPo Lu <luangruo@yahoo.com>
Tue, 12 Jul 2022 02:47:51 +0000 (10:47 +0800)
* 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
lisp/cus-start.el
src/xselect.c
src/xterm.c
src/xterm.h

index bf363168906172243eac047c044a9ca4c654bdd5..c2900b0bc4c6bb00142ff8915253e1892afc3445 100644 (file)
--- 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.
index ca2fca4eb779a7bf53dcda64c91ba31c75dff13c..df919fd715541bd4150125b6b3174dc3c2376d14 100644 (file)
@@ -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))
index 25a75aec91757427ad7c100d09c37ffe33905402..baab2c5c18fbf27cbda4b63565c410e1be3f094a 100644 (file)
@@ -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);
 }
 \f
 /* True if any properties for DISPLAY and WINDOW
index 2b83efb2288c0ea551b52a732f52e2657ec1d98e..f86e4708ec53da8704b47659ded17a51713e1d65 100644 (file)
@@ -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;
 }
index a1ddf13463c506a40665a1766b23600d64e274c7..9b91ee45569705353eb2014246d0f3cc77e29739 100644 (file)
@@ -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