aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIgnacio2022-03-13 21:05:18 +0100
committerPo Lu2022-04-01 20:57:54 +0800
commit2b564f504bbf7c050355840b40a9897f12ed91f9 (patch)
tree999cb1c07fc02c632d7adb8e10b7f6df18cb7757
parentff067408e460c02e69c5b7fd06a03c9b12a5744b (diff)
downloademacs-2b564f504bbf7c050355840b40a9897f12ed91f9.tar.gz
emacs-2b564f504bbf7c050355840b40a9897f12ed91f9.zip
Better check for when clipboard or primary selection have changed
Previously it was done by just comparing new and old selection text, now we use also selection timestamps for systems that support it (only enabled in X for now). (bug#53894) * lisp/select.el: (gui--last-selection-timestamp-clipboard) (gui--last-selection-timestamp-primary): New variables. (gui--set-last-clipboard-selection) (gui--set-last-primary-selection) (gui--clipboard-selection-unchanged-p) (gui--primary-selection-unchanged-p): New functions.
-rw-r--r--lisp/menu-bar.el3
-rw-r--r--lisp/select.el108
-rw-r--r--lisp/term/pc-win.el8
3 files changed, 87 insertions, 32 deletions
diff --git a/lisp/menu-bar.el b/lisp/menu-bar.el
index ab64928fe76..d8c8c760f78 100644
--- a/lisp/menu-bar.el
+++ b/lisp/menu-bar.el
@@ -606,7 +606,8 @@
606 "Insert the clipboard contents, or the last stretch of killed text." 606 "Insert the clipboard contents, or the last stretch of killed text."
607 (interactive "*") 607 (interactive "*")
608 (let ((select-enable-clipboard t) 608 (let ((select-enable-clipboard t)
609 ;; Ensure that we defeat the DWIM login in `gui-selection-value'. 609 ;; Ensure that we defeat the DWIM logic in `gui-selection-value'
610 ;; (i.e., that gui--clipboard-selection-unchanged-p returns nil).
610 (gui--last-selected-text-clipboard nil)) 611 (gui--last-selected-text-clipboard nil))
611 (yank))) 612 (yank)))
612 613
diff --git a/lisp/select.el b/lisp/select.el
index c352a482616..0b51f01cc58 100644
--- a/lisp/select.el
+++ b/lisp/select.el
@@ -25,9 +25,10 @@
25;; Based partially on earlier release by Lucid. 25;; Based partially on earlier release by Lucid.
26 26
27;; The functionality here is divided in two parts: 27;; The functionality here is divided in two parts:
28;; - Low-level: gui-get-selection, gui-set-selection, gui-selection-owner-p, 28;; - Low-level: gui-backend-get-selection, gui-backend-set-selection,
29;; gui-selection-exists-p are the backend-dependent functions meant to access 29;; gui-backend-selection-owner-p, gui-backend-selection-exists-p are
30;; various kinds of selections (CLIPBOARD, PRIMARY, SECONDARY). 30;; the backend-dependent functions meant to access various kinds of
31;; selections (CLIPBOARD, PRIMARY, SECONDARY).
31;; - Higher-level: gui-select-text and gui-selection-value go together to 32;; - Higher-level: gui-select-text and gui-selection-value go together to
32;; access the general notion of "GUI selection" for interoperation with other 33;; access the general notion of "GUI selection" for interoperation with other
33;; applications. This can use either the clipboard or the primary selection, 34;; applications. This can use either the clipboard or the primary selection,
@@ -108,9 +109,10 @@ E.g. it doesn't exist under MS-Windows."
108 :group 'killing 109 :group 'killing
109 :version "25.1") 110 :version "25.1")
110 111
111;; We keep track of the last text selected here, so we can check the 112;; We keep track of the last selection here, so we can check the
112;; current selection against it, and avoid passing back our own text 113;; current selection against it, and avoid passing back with
113;; from gui-selection-value. We track both 114;; gui-selection-value the same text we previously killed or
115;; yanked. We track both
114;; separately in case another X application only sets one of them 116;; separately in case another X application only sets one of them
115;; we aren't fooled by the PRIMARY or CLIPBOARD selection staying the same. 117;; we aren't fooled by the PRIMARY or CLIPBOARD selection staying the same.
116 118
@@ -119,22 +121,68 @@ E.g. it doesn't exist under MS-Windows."
119(defvar gui--last-selected-text-primary nil 121(defvar gui--last-selected-text-primary nil
120 "The value of the PRIMARY selection last seen.") 122 "The value of the PRIMARY selection last seen.")
121 123
124(defvar gui--last-selection-timestamp-clipboard nil
125 "The timestamp of the CLIPBOARD selection last seen.")
126(defvar gui--last-selection-timestamp-primary nil
127 "The timestamp of the PRIMARY selection last seen.")
128
129(defun gui--set-last-clipboard-selection (text)
130 "Save last clipboard selection.
131Save the selected text, passed as argument, and for window
132systems that support it, save the selection timestamp too."
133 (setq gui--last-selected-text-clipboard text)
134 (when (eq window-system 'x)
135 (setq gui--last-selection-timestamp-clipboard
136 (gui-backend-get-selection 'CLIPBOARD 'TIMESTAMP))))
137
138(defun gui--set-last-primary-selection (text)
139 "Save last primary selection.
140Save the selected text, passed as argument, and for window
141systems that support it, save the selection timestamp too."
142 (setq gui--last-selected-text-primary text)
143 (when (eq window-system 'x)
144 (setq gui--last-selection-timestamp-primary
145 (gui-backend-get-selection 'PRIMARY 'TIMESTAMP))))
146
147(defun gui--clipboard-selection-unchanged-p (text)
148 "Check whether the clipboard selection has changed.
149Compare the selection text, passed as argument, with the text
150from the last saved selection. For window systems that support
151it, compare the selection timestamp too."
152 (and
153 (equal text gui--last-selected-text-clipboard)
154 (or (not (eq window-system 'x))
155 (eq gui--last-selection-timestamp-clipboard
156 (gui-backend-get-selection 'CLIPBOARD 'TIMESTAMP)))))
157
158(defun gui--primary-selection-unchanged-p (text)
159 "Check whether the primary selection has changed.
160Compare the selection text, passed as argument, with the text
161from the last saved selection. For window systems that support
162it, compare the selection timestamp too."
163 (and
164 (equal text gui--last-selected-text-primary)
165 (or (not (eq window-system 'x))
166 (eq gui--last-selection-timestamp-primary
167 (gui-backend-get-selection 'PRIMARY 'TIMESTAMP)))))
168
169
122(defun gui-select-text (text) 170(defun gui-select-text (text)
123 "Select TEXT, a string, according to the window system. 171 "Select TEXT, a string, according to the window system.
124if `select-enable-clipboard' is non-nil, copy TEXT to the system's clipboard. 172If `select-enable-clipboard' is non-nil, copy TEXT to the system's clipboard.
125If `select-enable-primary' is non-nil, put TEXT in the primary selection. 173If `select-enable-primary' is non-nil, put TEXT in the primary selection.
126 174
127MS-Windows does not have a \"primary\" selection." 175MS-Windows does not have a \"primary\" selection."
128 (when select-enable-primary 176 (when select-enable-primary
129 (gui-set-selection 'PRIMARY text) 177 (gui-set-selection 'PRIMARY text)
130 (setq gui--last-selected-text-primary text)) 178 (gui--set-last-primary-selection text))
131 (when select-enable-clipboard 179 (when select-enable-clipboard
132 ;; When cutting, the selection is cleared and PRIMARY 180 ;; When cutting, the selection is cleared and PRIMARY
133 ;; set to the empty string. Prevent that, PRIMARY 181 ;; set to the empty string. Prevent that, PRIMARY
134 ;; should not be reset by cut (Bug#16382). 182 ;; should not be reset by cut (Bug#16382).
135 (setq saved-region-selection text) 183 (setq saved-region-selection text)
136 (gui-set-selection 'CLIPBOARD text) 184 (gui-set-selection 'CLIPBOARD text)
137 (setq gui--last-selected-text-clipboard text))) 185 (gui--set-last-clipboard-selection text)))
138(define-obsolete-function-alias 'x-select-text 'gui-select-text "25.1") 186(define-obsolete-function-alias 'x-select-text 'gui-select-text "25.1")
139 187
140(defcustom x-select-request-type nil 188(defcustom x-select-request-type nil
@@ -175,6 +223,7 @@ decoded. If `gui-get-selection' signals an error, return nil."
175 ;; some other window systems. 223 ;; some other window systems.
176 (memq window-system '(x haiku)) 224 (memq window-system '(x haiku))
177 (eq type 'CLIPBOARD) 225 (eq type 'CLIPBOARD)
226 ;; Should we unify this with gui--clipboard-selection-unchanged-p?
178 (gui-backend-selection-owner-p type)) 227 (gui-backend-selection-owner-p type))
179 (let ((request-type (if (memq window-system '(x pgtk haiku)) 228 (let ((request-type (if (memq window-system '(x pgtk haiku))
180 (or x-select-request-type 229 (or x-select-request-type
@@ -197,19 +246,17 @@ decoded. If `gui-get-selection' signals an error, return nil."
197 (let ((text (gui--selection-value-internal 'CLIPBOARD))) 246 (let ((text (gui--selection-value-internal 'CLIPBOARD)))
198 (when (string= text "") 247 (when (string= text "")
199 (setq text nil)) 248 (setq text nil))
200 ;; When `select-enable-clipboard' is non-nil, 249 ;; Check the CLIPBOARD selection for 'newness', i.e.,
201 ;; killing/copying text (with, say, `C-w') will push the 250 ;; whether it is different from the last time we did a
202 ;; text to the clipboard (and store it in 251 ;; yank operation or whether it was set by Emacs itself
203 ;; `gui--last-selected-text-clipboard'). We check 252 ;; with a kill operation, since in both cases the text
204 ;; whether the text on the clipboard is identical to this 253 ;; will already be in the kill ring. See (bug#27442) and
205 ;; text, and if so, we report that the clipboard is 254 ;; (bug#53894) for further discussion about this DWIM
206 ;; empty. See (bug#27442) for further discussion about 255 ;; action, and possible ways to make this check less
207 ;; this DWIM action, and possible ways to make this check 256 ;; fragile, if so desired.
208 ;; less fragile, if so desired. 257 (unless (gui--clipboard-selection-unchanged-p text)
209 (prog1 258 (gui--set-last-clipboard-selection text)
210 (unless (equal text gui--last-selected-text-clipboard) 259 text))))
211 text)
212 (setq gui--last-selected-text-clipboard text)))))
213 (primary-text 260 (primary-text
214 (when select-enable-primary 261 (when select-enable-primary
215 (let ((text (gui--selection-value-internal 'PRIMARY))) 262 (let ((text (gui--selection-value-internal 'PRIMARY)))
@@ -217,10 +264,9 @@ decoded. If `gui-get-selection' signals an error, return nil."
217 ;; Check the PRIMARY selection for 'newness', is it different 264 ;; Check the PRIMARY selection for 'newness', is it different
218 ;; from what we remembered them to be last time we did a 265 ;; from what we remembered them to be last time we did a
219 ;; cut/paste operation. 266 ;; cut/paste operation.
220 (prog1 267 (unless (gui--primary-selection-unchanged-p text)
221 (unless (equal text gui--last-selected-text-primary) 268 (gui--set-last-primary-selection text)
222 text) 269 text)))))
223 (setq gui--last-selected-text-primary text))))))
224 270
225 ;; As we have done one selection, clear this now. 271 ;; As we have done one selection, clear this now.
226 (setq next-selection-coding-system nil) 272 (setq next-selection-coding-system nil)
@@ -235,11 +281,11 @@ decoded. If `gui-get-selection' signals an error, return nil."
235 ;; something like the following has happened since the last time 281 ;; something like the following has happened since the last time
236 ;; we looked at the selections: Application X set all the 282 ;; we looked at the selections: Application X set all the
237 ;; selections, then Application Y set only one of them. 283 ;; selections, then Application Y set only one of them.
238 ;; In this case since we don't have 284 ;; In this case, for systems that support selection timestamps, we
239 ;; timestamps there is no way to know what the 'correct' value to 285 ;; could return the newer. For systems that don't, there is no
240 ;; return is. The nice thing to do would be to tell the user we 286 ;; way to know what the 'correct' value to return is. The nice
241 ;; saw multiple possible selections and ask the user which was the 287 ;; thing to do would be to tell the user we saw multiple possible
242 ;; one they wanted. 288 ;; selections and ask the user which was the one they wanted.
243 (or clip-text primary-text) 289 (or clip-text primary-text)
244 )) 290 ))
245 291
diff --git a/lisp/term/pc-win.el b/lisp/term/pc-win.el
index 327d51f2759..514267a52d6 100644
--- a/lisp/term/pc-win.el
+++ b/lisp/term/pc-win.el
@@ -246,6 +246,14 @@ Consult the selection. Treat empty strings as if they were unset."
246 ;; if it does not exist, or exists and compares 246 ;; if it does not exist, or exists and compares
247 ;; equal with the last text we've put into the 247 ;; equal with the last text we've put into the
248 ;; Windows clipboard. 248 ;; Windows clipboard.
249 ;; NOTE: that variable is actually the last text any program
250 ;; (not just Emacs) has put into the windows clipboard (up
251 ;; until the last time Emacs read or set the clipboard), so
252 ;; it's not suitable for checking actual selection
253 ;; ownership. This should not result in a bug for the current
254 ;; uses of gui-backend-selection-owner however, since they
255 ;; don't actually care about selection ownership, but about
256 ;; the selected text having changed.
249 (cond 257 (cond
250 ((not text) t) 258 ((not text) t)
251 ((equal text gui--last-selected-text-clipboard) text) 259 ((equal text gui--last-selected-text-clipboard) text)