diff options
| author | Chong Yidong | 2011-05-27 12:17:59 -0400 |
|---|---|---|
| committer | Chong Yidong | 2011-05-27 12:17:59 -0400 |
| commit | a9f737eef69ffe03dd045df555300ae6b41d0edf (patch) | |
| tree | 515b335a2f07a324ecc71b6a9331b7e0bc712586 | |
| parent | be520aca79dd429d55012a1916bdc97f06773fc5 (diff) | |
| download | emacs-a9f737eef69ffe03dd045df555300ae6b41d0edf.tar.gz emacs-a9f737eef69ffe03dd045df555300ae6b41d0edf.zip | |
Support X clipboard managers.
* lisp/select.el (xselect-convert-to-targets): Add MULTIPLE target to list.
(xselect-convert-to-save-targets): New function.
* src/xselect.c: Support for clipboard managers.
(Vselection_alist): Move to termhooks.h as terminal-local var.
(LOCAL_SELECTION): New macro.
(x_atom_to_symbol): Handle x_display_info_for_display fail case.
(symbol_to_x_atom): Remove gratuitous arg.
(x_handle_selection_request, lisp_data_to_selection_data)
(x_get_foreign_selection, Fx_register_dnd_atom): Callers changed.
(x_own_selection, x_get_local_selection, x_convert_selection): New
arg, specifying work frame. Use terminal-local Vselection_alist.
(some_frame_on_display): Delete unused function.
(Fx_own_selection_internal, Fx_get_selection_internal)
(Fx_disown_selection_internal, Fx_selection_owner_p)
(Fx_selection_exists_p): New optional frame arg.
(frame_for_x_selection, Fx_clipboard_manager_save): New functions.
(x_handle_selection_clear): Don't treat other terminals with the
same keyboard specially. Use the terminal-local Vselection_alist.
(x_clear_frame_selections): Use Frun_hook_with_args.
* src/termhooks.h (Vselection_alist): Make it terminal-local.
* src/terminal.c (create_terminal): Initialize it.
* src/xterm.c (x_term_init): Intern ATOM and CLIPBOARD_MANAGER atoms.
* src/xterm.h: Add support for those atoms.
| -rw-r--r-- | lisp/ChangeLog | 8 | ||||
| -rw-r--r-- | lisp/select.el | 15 | ||||
| -rw-r--r-- | src/ChangeLog | 28 | ||||
| -rw-r--r-- | src/termhooks.h | 16 | ||||
| -rw-r--r-- | src/terminal.c | 2 | ||||
| -rw-r--r-- | src/xselect.c | 654 | ||||
| -rw-r--r-- | src/xterm.c | 2 | ||||
| -rw-r--r-- | src/xterm.h | 4 |
8 files changed, 423 insertions, 306 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 2067128fbe8..ef35353bb0f 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,11 @@ | |||
| 1 | 2011-05-27 Chong Yidong <cyd@stupidchicken.com> | ||
| 2 | |||
| 3 | * select.el: Support clipboard managers with built-in function | ||
| 4 | x-clipboard-manager-save, via delete-frame-functions and | ||
| 5 | kill-emacs-hook. | ||
| 6 | (xselect-convert-to-targets): Add MULTIPLE target to list. | ||
| 7 | (xselect-convert-to-save-targets): New function. | ||
| 8 | |||
| 1 | 2011-05-27 Kenichi Handa <handa@m17n.org> | 9 | 2011-05-27 Kenichi Handa <handa@m17n.org> |
| 2 | 10 | ||
| 3 | * mail/sendmail.el (mail-encode-header): Avoid double encoding by | 11 | * mail/sendmail.el (mail-encode-header): Avoid double encoding by |
diff --git a/lisp/select.el b/lisp/select.el index 1f5191e86c1..5abbf8f795d 100644 --- a/lisp/select.el +++ b/lisp/select.el | |||
| @@ -289,7 +289,9 @@ two markers or an overlay. Otherwise, it is nil." | |||
| 289 | 289 | ||
| 290 | (defun xselect-convert-to-targets (_selection _type _value) | 290 | (defun xselect-convert-to-targets (_selection _type _value) |
| 291 | ;; return a vector of atoms, but remove duplicates first. | 291 | ;; return a vector of atoms, but remove duplicates first. |
| 292 | (let* ((all (cons 'TIMESTAMP (mapcar 'car selection-converter-alist))) | 292 | (let* ((all (cons 'TIMESTAMP |
| 293 | (cons 'MULTIPLE | ||
| 294 | (mapcar 'car selection-converter-alist)))) | ||
| 293 | (rest all)) | 295 | (rest all)) |
| 294 | (while rest | 296 | (while rest |
| 295 | (cond ((memq (car rest) (cdr rest)) | 297 | (cond ((memq (car rest) (cdr rest)) |
| @@ -365,6 +367,12 @@ This function returns the string \"emacs\"." | |||
| 365 | (defun xselect-convert-to-identity (_selection _type value) ; used internally | 367 | (defun xselect-convert-to-identity (_selection _type value) ; used internally |
| 366 | (vector value)) | 368 | (vector value)) |
| 367 | 369 | ||
| 370 | ;; Null target that tells clipboard managers we support SAVE_TARGETS | ||
| 371 | ;; (see freedesktop.org Clipboard Manager spec). | ||
| 372 | (defun xselect-convert-to-save-targets (selection _type _value) | ||
| 373 | (when (eq selection 'CLIPBOARD) | ||
| 374 | 'NULL)) | ||
| 375 | |||
| 368 | (setq selection-converter-alist | 376 | (setq selection-converter-alist |
| 369 | '((TEXT . xselect-convert-to-string) | 377 | '((TEXT . xselect-convert-to-string) |
| 370 | (COMPOUND_TEXT . xselect-convert-to-string) | 378 | (COMPOUND_TEXT . xselect-convert-to-string) |
| @@ -384,8 +392,13 @@ This function returns the string \"emacs\"." | |||
| 384 | (NAME . xselect-convert-to-name) | 392 | (NAME . xselect-convert-to-name) |
| 385 | (ATOM . xselect-convert-to-atom) | 393 | (ATOM . xselect-convert-to-atom) |
| 386 | (INTEGER . xselect-convert-to-integer) | 394 | (INTEGER . xselect-convert-to-integer) |
| 395 | (SAVE_TARGETS . xselect-convert-to-save-targets) | ||
| 387 | (_EMACS_INTERNAL . xselect-convert-to-identity))) | 396 | (_EMACS_INTERNAL . xselect-convert-to-identity))) |
| 388 | 397 | ||
| 398 | (when (fboundp 'x-clipboard-manager-save) | ||
| 399 | (add-hook 'delete-frame-functions 'x-clipboard-manager-save) | ||
| 400 | (add-hook 'kill-emacs-hook 'x-clipboard-manager-save)) | ||
| 401 | |||
| 389 | (provide 'select) | 402 | (provide 'select) |
| 390 | 403 | ||
| 391 | ;;; select.el ends here | 404 | ;;; select.el ends here |
diff --git a/src/ChangeLog b/src/ChangeLog index 85ea8a86e7b..93496a6cd86 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,31 @@ | |||
| 1 | 2011-05-27 Chong Yidong <cyd@stupidchicken.com> | ||
| 2 | |||
| 3 | * termhooks.h (Vselection_alist): Make it terminal-local. | ||
| 4 | |||
| 5 | * terminal.c (create_terminal): Initialize it. | ||
| 6 | |||
| 7 | * xselect.c: Support for clipboard managers. | ||
| 8 | (Vselection_alist): Move to termhooks.h as terminal-local var. | ||
| 9 | (LOCAL_SELECTION): New macro. | ||
| 10 | (x_atom_to_symbol): Handle x_display_info_for_display fail case. | ||
| 11 | (symbol_to_x_atom): Remove gratuitous arg. | ||
| 12 | (x_handle_selection_request, lisp_data_to_selection_data) | ||
| 13 | (x_get_foreign_selection, Fx_register_dnd_atom): Callers changed. | ||
| 14 | (x_own_selection, x_get_local_selection, x_convert_selection): New | ||
| 15 | arg, specifying work frame. Use terminal-local Vselection_alist. | ||
| 16 | (some_frame_on_display): Delete unused function. | ||
| 17 | (Fx_own_selection_internal, Fx_get_selection_internal) | ||
| 18 | (Fx_disown_selection_internal, Fx_selection_owner_p) | ||
| 19 | (Fx_selection_exists_p): New optional frame arg. | ||
| 20 | (frame_for_x_selection, Fx_clipboard_manager_save): New functions. | ||
| 21 | (x_handle_selection_clear): Don't treat other terminals with the | ||
| 22 | same keyboard specially. Use the terminal-local Vselection_alist. | ||
| 23 | (x_clear_frame_selections): Use Frun_hook_with_args. | ||
| 24 | |||
| 25 | * xterm.c (x_term_init): Intern ATOM and CLIPBOARD_MANAGER atoms. | ||
| 26 | |||
| 27 | * xterm.h: Add support for those atoms. | ||
| 28 | |||
| 1 | 2011-05-26 Chong Yidong <cyd@stupidchicken.com> | 29 | 2011-05-26 Chong Yidong <cyd@stupidchicken.com> |
| 2 | 30 | ||
| 3 | * xselect.c: ICCCM-compliant handling of MULTIPLE targets. | 31 | * xselect.c: ICCCM-compliant handling of MULTIPLE targets. |
diff --git a/src/termhooks.h b/src/termhooks.h index 34e1364effd..6a58517a85a 100644 --- a/src/termhooks.h +++ b/src/termhooks.h | |||
| @@ -335,6 +335,22 @@ struct terminal | |||
| 335 | the member terminal_coding. */ | 335 | the member terminal_coding. */ |
| 336 | Lisp_Object charset_list; | 336 | Lisp_Object charset_list; |
| 337 | 337 | ||
| 338 | /* This is an association list containing the X selections that | ||
| 339 | Emacs might own on this terminal. Each element has the form | ||
| 340 | (SELECTION-NAME SELECTION-VALUE SELECTION-TIMESTAMP FRAME) | ||
| 341 | SELECTION-NAME is a lisp symbol, whose name is the name of an X Atom. | ||
| 342 | SELECTION-VALUE is the value that emacs owns for that selection. | ||
| 343 | It may be any kind of Lisp object. | ||
| 344 | SELECTION-TIMESTAMP is the time at which emacs began owning this | ||
| 345 | selection, as a cons of two 16-bit numbers (making a 32 bit | ||
| 346 | time.) | ||
| 347 | FRAME is the frame for which we made the selection. If there is | ||
| 348 | an entry in this alist, then it can be assumed that Emacs owns | ||
| 349 | that selection. | ||
| 350 | The only (eq) parts of this list that are visible from Lisp are | ||
| 351 | the selection-values. */ | ||
| 352 | Lisp_Object Vselection_alist; | ||
| 353 | |||
| 338 | /* All fields before `next_terminal' should be Lisp_Object and are traced | 354 | /* All fields before `next_terminal' should be Lisp_Object and are traced |
| 339 | by the GC. All fields afterwards are ignored by the GC. */ | 355 | by the GC. All fields afterwards are ignored by the GC. */ |
| 340 | 356 | ||
diff --git a/src/terminal.c b/src/terminal.c index c5185601fb6..c135c0f93ef 100644 --- a/src/terminal.c +++ b/src/terminal.c | |||
| @@ -256,6 +256,8 @@ create_terminal (void) | |||
| 256 | setup_coding_system (terminal_coding, terminal->terminal_coding); | 256 | setup_coding_system (terminal_coding, terminal->terminal_coding); |
| 257 | 257 | ||
| 258 | terminal->param_alist = Qnil; | 258 | terminal->param_alist = Qnil; |
| 259 | terminal->charset_list = Qnil; | ||
| 260 | terminal->Vselection_alist = Qnil; | ||
| 259 | return terminal; | 261 | return terminal; |
| 260 | } | 262 | } |
| 261 | 263 | ||
diff --git a/src/xselect.c b/src/xselect.c index 15eb22c5d6f..f0ffbe0eb2d 100644 --- a/src/xselect.c +++ b/src/xselect.c | |||
| @@ -46,27 +46,25 @@ struct prop_location; | |||
| 46 | struct selection_data; | 46 | struct selection_data; |
| 47 | 47 | ||
| 48 | static Lisp_Object x_atom_to_symbol (Display *dpy, Atom atom); | 48 | static Lisp_Object x_atom_to_symbol (Display *dpy, Atom atom); |
| 49 | static Atom symbol_to_x_atom (struct x_display_info *, Display *, | 49 | static Atom symbol_to_x_atom (struct x_display_info *, Lisp_Object); |
| 50 | Lisp_Object); | 50 | static void x_own_selection (Lisp_Object, Lisp_Object, Lisp_Object); |
| 51 | static void x_own_selection (Lisp_Object, Lisp_Object); | 51 | static Lisp_Object x_get_local_selection (Lisp_Object, Lisp_Object, int, |
| 52 | static Lisp_Object x_get_local_selection (Lisp_Object, Lisp_Object, int); | 52 | struct x_display_info *); |
| 53 | static void x_decline_selection_request (struct input_event *); | 53 | static void x_decline_selection_request (struct input_event *); |
| 54 | static Lisp_Object x_selection_request_lisp_error (Lisp_Object); | 54 | static Lisp_Object x_selection_request_lisp_error (Lisp_Object); |
| 55 | static Lisp_Object queue_selection_requests_unwind (Lisp_Object); | 55 | static Lisp_Object queue_selection_requests_unwind (Lisp_Object); |
| 56 | static Lisp_Object some_frame_on_display (struct x_display_info *); | ||
| 57 | static Lisp_Object x_catch_errors_unwind (Lisp_Object); | 56 | static Lisp_Object x_catch_errors_unwind (Lisp_Object); |
| 58 | static void x_reply_selection_request (struct input_event *, struct x_display_info *); | 57 | static void x_reply_selection_request (struct input_event *, struct x_display_info *); |
| 59 | static int x_convert_selection (struct input_event *, Lisp_Object, Lisp_Object, | 58 | static int x_convert_selection (struct input_event *, Lisp_Object, Lisp_Object, |
| 60 | Atom, int); | 59 | Atom, int, struct x_display_info *); |
| 61 | static int waiting_for_other_props_on_window (Display *, Window); | 60 | static int waiting_for_other_props_on_window (Display *, Window); |
| 62 | static struct prop_location *expect_property_change (Display *, Window, | 61 | static struct prop_location *expect_property_change (Display *, Window, |
| 63 | Atom, int); | 62 | Atom, int); |
| 64 | static void unexpect_property_change (struct prop_location *); | 63 | static void unexpect_property_change (struct prop_location *); |
| 65 | static Lisp_Object wait_for_property_change_unwind (Lisp_Object); | 64 | static Lisp_Object wait_for_property_change_unwind (Lisp_Object); |
| 66 | static void wait_for_property_change (struct prop_location *); | 65 | static void wait_for_property_change (struct prop_location *); |
| 67 | static Lisp_Object x_get_foreign_selection (Lisp_Object, | 66 | static Lisp_Object x_get_foreign_selection (Lisp_Object, Lisp_Object, |
| 68 | Lisp_Object, | 67 | Lisp_Object, Lisp_Object); |
| 69 | Lisp_Object); | ||
| 70 | static void x_get_window_property (Display *, Window, Atom, | 68 | static void x_get_window_property (Display *, Window, Atom, |
| 71 | unsigned char **, int *, | 69 | unsigned char **, int *, |
| 72 | Atom *, int *, unsigned long *, int); | 70 | Atom *, int *, unsigned long *, int); |
| @@ -105,7 +103,7 @@ static Lisp_Object clean_local_selection_data (Lisp_Object); | |||
| 105 | 103 | ||
| 106 | static Lisp_Object QSECONDARY, QSTRING, QINTEGER, QCLIPBOARD, QTIMESTAMP, | 104 | static Lisp_Object QSECONDARY, QSTRING, QINTEGER, QCLIPBOARD, QTIMESTAMP, |
| 107 | QTEXT, QDELETE, QMULTIPLE, QINCR, QEMACS_TMP, QTARGETS, QATOM, QNULL, | 105 | QTEXT, QDELETE, QMULTIPLE, QINCR, QEMACS_TMP, QTARGETS, QATOM, QNULL, |
| 108 | QATOM_PAIR; | 106 | QATOM_PAIR, QCLIPBOARD_MANAGER, QSAVE_TARGETS; |
| 109 | 107 | ||
| 110 | static Lisp_Object QCOMPOUND_TEXT; /* This is a type of selection. */ | 108 | static Lisp_Object QCOMPOUND_TEXT; /* This is a type of selection. */ |
| 111 | static Lisp_Object QUTF8_STRING; /* This is a type of selection. */ | 109 | static Lisp_Object QUTF8_STRING; /* This is a type of selection. */ |
| @@ -124,20 +122,8 @@ static Lisp_Object Qforeign_selection; | |||
| 124 | 122 | ||
| 125 | #define SELECTION_QUANTUM(dpy) ((XMaxRequestSize(dpy) << 2) - 100) | 123 | #define SELECTION_QUANTUM(dpy) ((XMaxRequestSize(dpy) << 2) - 100) |
| 126 | 124 | ||
| 127 | /* This is an association list whose elements are of the form | 125 | #define LOCAL_SELECTION(selection_symbol,dpyinfo) \ |
| 128 | ( SELECTION-NAME SELECTION-VALUE SELECTION-TIMESTAMP FRAME) | 126 | assq_no_quit (selection_symbol, dpyinfo->terminal->Vselection_alist) |
| 129 | SELECTION-NAME is a lisp symbol, whose name is the name of an X Atom. | ||
| 130 | SELECTION-VALUE is the value that emacs owns for that selection. | ||
| 131 | It may be any kind of Lisp object. | ||
| 132 | SELECTION-TIMESTAMP is the time at which emacs began owning this selection, | ||
| 133 | as a cons of two 16-bit numbers (making a 32 bit time.) | ||
| 134 | FRAME is the frame for which we made the selection. | ||
| 135 | If there is an entry in this alist, then it can be assumed that Emacs owns | ||
| 136 | that selection. | ||
| 137 | The only (eq) parts of this list that are visible from Lisp are the | ||
| 138 | selection-values. */ | ||
| 139 | static Lisp_Object Vselection_alist; | ||
| 140 | |||
| 141 | 127 | ||
| 142 | 128 | ||
| 143 | /* Define a queue to save up SELECTION_REQUEST_EVENT events for later | 129 | /* Define a queue to save up SELECTION_REQUEST_EVENT events for later |
| @@ -224,7 +210,7 @@ x_stop_queuing_selection_requests (void) | |||
| 224 | roundtrip whenever possible. */ | 210 | roundtrip whenever possible. */ |
| 225 | 211 | ||
| 226 | static Atom | 212 | static Atom |
| 227 | symbol_to_x_atom (struct x_display_info *dpyinfo, Display *display, Lisp_Object sym) | 213 | symbol_to_x_atom (struct x_display_info *dpyinfo, Lisp_Object sym) |
| 228 | { | 214 | { |
| 229 | Atom val; | 215 | Atom val; |
| 230 | if (NILP (sym)) return 0; | 216 | if (NILP (sym)) return 0; |
| @@ -248,7 +234,7 @@ symbol_to_x_atom (struct x_display_info *dpyinfo, Display *display, Lisp_Object | |||
| 248 | 234 | ||
| 249 | TRACE1 (" XInternAtom %s", SSDATA (SYMBOL_NAME (sym))); | 235 | TRACE1 (" XInternAtom %s", SSDATA (SYMBOL_NAME (sym))); |
| 250 | BLOCK_INPUT; | 236 | BLOCK_INPUT; |
| 251 | val = XInternAtom (display, SSDATA (SYMBOL_NAME (sym)), False); | 237 | val = XInternAtom (dpyinfo->display, SSDATA (SYMBOL_NAME (sym)), False); |
| 252 | UNBLOCK_INPUT; | 238 | UNBLOCK_INPUT; |
| 253 | return val; | 239 | return val; |
| 254 | } | 240 | } |
| @@ -282,6 +268,8 @@ x_atom_to_symbol (Display *dpy, Atom atom) | |||
| 282 | } | 268 | } |
| 283 | 269 | ||
| 284 | dpyinfo = x_display_info_for_display (dpy); | 270 | dpyinfo = x_display_info_for_display (dpy); |
| 271 | if (dpyinfo == NULL) | ||
| 272 | return Qnil; | ||
| 285 | if (atom == dpyinfo->Xatom_CLIPBOARD) | 273 | if (atom == dpyinfo->Xatom_CLIPBOARD) |
| 286 | return QCLIPBOARD; | 274 | return QCLIPBOARD; |
| 287 | if (atom == dpyinfo->Xatom_TIMESTAMP) | 275 | if (atom == dpyinfo->Xatom_TIMESTAMP) |
| @@ -319,28 +307,20 @@ x_atom_to_symbol (Display *dpy, Atom atom) | |||
| 319 | } | 307 | } |
| 320 | 308 | ||
| 321 | /* Do protocol to assert ourself as a selection owner. | 309 | /* Do protocol to assert ourself as a selection owner. |
| 310 | FRAME shall be the owner; it must be a valid X frame. | ||
| 322 | Update the Vselection_alist so that we can reply to later requests for | 311 | Update the Vselection_alist so that we can reply to later requests for |
| 323 | our selection. */ | 312 | our selection. */ |
| 324 | 313 | ||
| 325 | static void | 314 | static void |
| 326 | x_own_selection (Lisp_Object selection_name, Lisp_Object selection_value) | 315 | x_own_selection (Lisp_Object selection_name, Lisp_Object selection_value, |
| 316 | Lisp_Object frame) | ||
| 327 | { | 317 | { |
| 328 | struct frame *sf = SELECTED_FRAME (); | 318 | struct frame *f = XFRAME (frame); |
| 329 | Window selecting_window; | 319 | Window selecting_window = FRAME_X_WINDOW (f); |
| 330 | Display *display; | 320 | struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f); |
| 321 | Display *display = dpyinfo->display; | ||
| 331 | Time timestamp = last_event_timestamp; | 322 | Time timestamp = last_event_timestamp; |
| 332 | Atom selection_atom; | 323 | Atom selection_atom = symbol_to_x_atom (dpyinfo, selection_name); |
| 333 | struct x_display_info *dpyinfo; | ||
| 334 | |||
| 335 | if (! FRAME_X_P (sf)) | ||
| 336 | return; | ||
| 337 | |||
| 338 | selecting_window = FRAME_X_WINDOW (sf); | ||
| 339 | display = FRAME_X_DISPLAY (sf); | ||
| 340 | dpyinfo = FRAME_X_DISPLAY_INFO (sf); | ||
| 341 | |||
| 342 | CHECK_SYMBOL (selection_name); | ||
| 343 | selection_atom = symbol_to_x_atom (dpyinfo, display, selection_name); | ||
| 344 | 324 | ||
| 345 | BLOCK_INPUT; | 325 | BLOCK_INPUT; |
| 346 | x_catch_errors (display); | 326 | x_catch_errors (display); |
| @@ -351,27 +331,26 @@ x_own_selection (Lisp_Object selection_name, Lisp_Object selection_value) | |||
| 351 | 331 | ||
| 352 | /* Now update the local cache */ | 332 | /* Now update the local cache */ |
| 353 | { | 333 | { |
| 354 | Lisp_Object selection_time; | ||
| 355 | Lisp_Object selection_data; | 334 | Lisp_Object selection_data; |
| 356 | Lisp_Object prev_value; | 335 | Lisp_Object prev_value; |
| 357 | 336 | ||
| 358 | selection_time = long_to_cons (timestamp); | ||
| 359 | selection_data = list4 (selection_name, selection_value, | 337 | selection_data = list4 (selection_name, selection_value, |
| 360 | selection_time, selected_frame); | 338 | long_to_cons (timestamp), frame); |
| 361 | prev_value = assq_no_quit (selection_name, Vselection_alist); | 339 | prev_value = LOCAL_SELECTION (selection_name, dpyinfo); |
| 362 | 340 | ||
| 363 | Vselection_alist = Fcons (selection_data, Vselection_alist); | 341 | dpyinfo->terminal->Vselection_alist |
| 342 | = Fcons (selection_data, dpyinfo->terminal->Vselection_alist); | ||
| 364 | 343 | ||
| 365 | /* If we already owned the selection, remove the old selection data. | 344 | /* If we already owned the selection, remove the old selection |
| 366 | Perhaps we should destructively modify it instead. | 345 | data. Don't use Fdelq as that may QUIT. */ |
| 367 | Don't use Fdelq as that may QUIT. */ | ||
| 368 | if (!NILP (prev_value)) | 346 | if (!NILP (prev_value)) |
| 369 | { | 347 | { |
| 370 | Lisp_Object rest; /* we know it's not the CAR, so it's easy. */ | 348 | /* We know it's not the CAR, so it's easy. */ |
| 371 | for (rest = Vselection_alist; CONSP (rest); rest = XCDR (rest)) | 349 | Lisp_Object rest = dpyinfo->terminal->Vselection_alist; |
| 350 | for (; CONSP (rest); rest = XCDR (rest)) | ||
| 372 | if (EQ (prev_value, Fcar (XCDR (rest)))) | 351 | if (EQ (prev_value, Fcar (XCDR (rest)))) |
| 373 | { | 352 | { |
| 374 | XSETCDR (rest, Fcdr (XCDR (rest))); | 353 | XSETCDR (rest, XCDR (XCDR (rest))); |
| 375 | break; | 354 | break; |
| 376 | } | 355 | } |
| 377 | } | 356 | } |
| @@ -387,17 +366,18 @@ x_own_selection (Lisp_Object selection_name, Lisp_Object selection_value) | |||
| 387 | This calls random Lisp code, and may signal or gc. */ | 366 | This calls random Lisp code, and may signal or gc. */ |
| 388 | 367 | ||
| 389 | static Lisp_Object | 368 | static Lisp_Object |
| 390 | x_get_local_selection (Lisp_Object selection_symbol, Lisp_Object target_type, int local_request) | 369 | x_get_local_selection (Lisp_Object selection_symbol, Lisp_Object target_type, |
| 370 | int local_request, struct x_display_info *dpyinfo) | ||
| 391 | { | 371 | { |
| 392 | Lisp_Object local_value; | 372 | Lisp_Object local_value; |
| 393 | Lisp_Object handler_fn, value, check; | 373 | Lisp_Object handler_fn, value, check; |
| 394 | int count; | 374 | int count; |
| 395 | 375 | ||
| 396 | local_value = assq_no_quit (selection_symbol, Vselection_alist); | 376 | local_value = LOCAL_SELECTION (selection_symbol, dpyinfo); |
| 397 | 377 | ||
| 398 | if (NILP (local_value)) return Qnil; | 378 | if (NILP (local_value)) return Qnil; |
| 399 | 379 | ||
| 400 | /* TIMESTAMP and MULTIPLE are special cases 'cause that's easiest. */ | 380 | /* TIMESTAMP is a special case. */ |
| 401 | if (EQ (target_type, QTIMESTAMP)) | 381 | if (EQ (target_type, QTIMESTAMP)) |
| 402 | { | 382 | { |
| 403 | handler_fn = Qnil; | 383 | handler_fn = Qnil; |
| @@ -585,23 +565,6 @@ queue_selection_requests_unwind (Lisp_Object tem) | |||
| 585 | return Qnil; | 565 | return Qnil; |
| 586 | } | 566 | } |
| 587 | 567 | ||
| 588 | /* Return some frame whose display info is DPYINFO. | ||
| 589 | Return nil if there is none. */ | ||
| 590 | |||
| 591 | static Lisp_Object | ||
| 592 | some_frame_on_display (struct x_display_info *dpyinfo) | ||
| 593 | { | ||
| 594 | Lisp_Object list, frame; | ||
| 595 | |||
| 596 | FOR_EACH_FRAME (list, frame) | ||
| 597 | { | ||
| 598 | if (FRAME_X_P (XFRAME (frame)) | ||
| 599 | && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo) | ||
| 600 | return frame; | ||
| 601 | } | ||
| 602 | |||
| 603 | return Qnil; | ||
| 604 | } | ||
| 605 | 568 | ||
| 606 | /* Send the reply to a selection request event EVENT. */ | 569 | /* Send the reply to a selection request event EVENT. */ |
| 607 | 570 | ||
| @@ -648,36 +611,36 @@ x_reply_selection_request (struct input_event *event, struct x_display_info *dpy | |||
| 648 | the conversion itself must be done in the same order. */ | 611 | the conversion itself must be done in the same order. */ |
| 649 | for (cs = converted_selections; cs; cs = cs->next) | 612 | for (cs = converted_selections; cs; cs = cs->next) |
| 650 | { | 613 | { |
| 651 | if (cs->property != None) | 614 | if (cs->property == None) |
| 615 | continue; | ||
| 616 | |||
| 617 | bytes_remaining = cs->size * (cs->format / 8); | ||
| 618 | if (bytes_remaining <= max_bytes) | ||
| 652 | { | 619 | { |
| 653 | bytes_remaining = cs->size * (cs->format / 8); | 620 | /* Send all the data at once, with minimal handshaking. */ |
| 654 | if (bytes_remaining <= max_bytes) | 621 | TRACE1 ("Sending all %d bytes", bytes_remaining); |
| 655 | { | 622 | XChangeProperty (display, window, cs->property, |
| 656 | /* Send all the data at once, with minimal handshaking. */ | 623 | cs->type, cs->format, PropModeReplace, |
| 657 | TRACE1 ("Sending all %d bytes", bytes_remaining); | 624 | cs->data, cs->size); |
| 658 | XChangeProperty (display, window, cs->property, | 625 | } |
| 659 | cs->type, cs->format, PropModeReplace, | 626 | else |
| 660 | cs->data, cs->size); | 627 | { |
| 661 | } | 628 | /* Send an INCR tag to initiate incremental transfer. */ |
| 662 | else | 629 | long value[1]; |
| 663 | { | 630 | |
| 664 | /* Send an INCR tag to initiate incremental transfer. */ | 631 | TRACE2 ("Start sending %d bytes incrementally (%s)", |
| 665 | long value[1]; | 632 | bytes_remaining, XGetAtomName (display, cs->property)); |
| 666 | 633 | cs->wait_object | |
| 667 | TRACE2 ("Start sending %d bytes incrementally (%s)", | 634 | = expect_property_change (display, window, cs->property, |
| 668 | bytes_remaining, XGetAtomName (display, cs->property)); | 635 | PropertyDelete); |
| 669 | cs->wait_object | 636 | |
| 670 | = expect_property_change (display, window, cs->property, | 637 | /* XChangeProperty expects an array of long even if long is |
| 671 | PropertyDelete); | 638 | more than 32 bits. */ |
| 672 | 639 | value[0] = bytes_remaining; | |
| 673 | /* XChangeProperty expects an array of long even if long | 640 | XChangeProperty (display, window, cs->property, |
| 674 | is more than 32 bits. */ | 641 | dpyinfo->Xatom_INCR, 32, PropModeReplace, |
| 675 | value[0] = bytes_remaining; | 642 | (unsigned char *) value, 1); |
| 676 | XChangeProperty (display, window, cs->property, | 643 | XSelectInput (display, window, PropertyChangeMask); |
| 677 | dpyinfo->Xatom_INCR, 32, PropModeReplace, | ||
| 678 | (unsigned char *) value, 1); | ||
| 679 | XSelectInput (display, window, PropertyChangeMask); | ||
| 680 | } | ||
| 681 | } | 644 | } |
| 682 | } | 645 | } |
| 683 | 646 | ||
| @@ -740,7 +703,8 @@ x_reply_selection_request (struct input_event *event, struct x_display_info *dpy | |||
| 740 | cs->type, cs->format, PropModeAppend, | 703 | cs->type, cs->format, PropModeAppend, |
| 741 | cs->data, i); | 704 | cs->data, i); |
| 742 | bytes_remaining -= i * format_bytes; | 705 | bytes_remaining -= i * format_bytes; |
| 743 | cs->data += i * ((cs->format == 32) ? sizeof (long) : format_bytes); | 706 | cs->data += i * ((cs->format == 32) ? sizeof (long) |
| 707 | : format_bytes); | ||
| 744 | XFlush (display); | 708 | XFlush (display); |
| 745 | had_errors = x_had_errors_p (display); | 709 | had_errors = x_had_errors_p (display); |
| 746 | UNBLOCK_INPUT; | 710 | UNBLOCK_INPUT; |
| @@ -800,19 +764,20 @@ x_handle_selection_request (struct input_event *event) | |||
| 800 | 764 | ||
| 801 | Display *display = SELECTION_EVENT_DISPLAY (event); | 765 | Display *display = SELECTION_EVENT_DISPLAY (event); |
| 802 | struct x_display_info *dpyinfo = x_display_info_for_display (display); | 766 | struct x_display_info *dpyinfo = x_display_info_for_display (display); |
| 803 | |||
| 804 | Atom selection = SELECTION_EVENT_SELECTION (event); | 767 | Atom selection = SELECTION_EVENT_SELECTION (event); |
| 805 | Lisp_Object selection_symbol = x_atom_to_symbol (display, selection); | 768 | Lisp_Object selection_symbol = x_atom_to_symbol (display, selection); |
| 806 | Atom target = SELECTION_EVENT_TARGET (event); | 769 | Atom target = SELECTION_EVENT_TARGET (event); |
| 807 | Lisp_Object target_symbol = x_atom_to_symbol (display, target); | 770 | Lisp_Object target_symbol = x_atom_to_symbol (display, target); |
| 808 | Atom property = SELECTION_EVENT_PROPERTY (event); | 771 | Atom property = SELECTION_EVENT_PROPERTY (event); |
| 809 | Lisp_Object local_selection_data | 772 | Lisp_Object local_selection_data; |
| 810 | = assq_no_quit (selection_symbol, Vselection_alist); | ||
| 811 | int success = 0; | 773 | int success = 0; |
| 812 | int count = SPECPDL_INDEX (); | 774 | int count = SPECPDL_INDEX (); |
| 813 | |||
| 814 | GCPRO2 (local_selection_data, target_symbol); | 775 | GCPRO2 (local_selection_data, target_symbol); |
| 815 | 776 | ||
| 777 | if (!dpyinfo) goto DONE; | ||
| 778 | |||
| 779 | local_selection_data = LOCAL_SELECTION (selection_symbol, dpyinfo); | ||
| 780 | |||
| 816 | /* Decline if we don't own any selections. */ | 781 | /* Decline if we don't own any selections. */ |
| 817 | if (NILP (local_selection_data)) goto DONE; | 782 | if (NILP (local_selection_data)) goto DONE; |
| 818 | 783 | ||
| @@ -846,8 +811,9 @@ x_handle_selection_request (struct input_event *event) | |||
| 846 | int j, nselections; | 811 | int j, nselections; |
| 847 | 812 | ||
| 848 | if (property == None) goto DONE; | 813 | if (property == None) goto DONE; |
| 849 | multprop = x_get_window_property_as_lisp_data (display, requestor, property, | 814 | multprop |
| 850 | QMULTIPLE, selection); | 815 | = x_get_window_property_as_lisp_data (display, requestor, property, |
| 816 | QMULTIPLE, selection); | ||
| 851 | 817 | ||
| 852 | if (!VECTORP (multprop) || ASIZE (multprop) % 2) | 818 | if (!VECTORP (multprop) || ASIZE (multprop) % 2) |
| 853 | goto DONE; | 819 | goto DONE; |
| @@ -858,12 +824,12 @@ x_handle_selection_request (struct input_event *event) | |||
| 858 | { | 824 | { |
| 859 | struct selection_data *cs = converted_selections + j; | 825 | struct selection_data *cs = converted_selections + j; |
| 860 | Lisp_Object subtarget = AREF (multprop, 2*j); | 826 | Lisp_Object subtarget = AREF (multprop, 2*j); |
| 861 | Atom subproperty = symbol_to_x_atom (dpyinfo, display, | 827 | Atom subproperty = symbol_to_x_atom (dpyinfo, |
| 862 | AREF (multprop, 2*j+1)); | 828 | AREF (multprop, 2*j+1)); |
| 863 | 829 | ||
| 864 | if (subproperty != None) | 830 | if (subproperty != None) |
| 865 | x_convert_selection (event, selection_symbol, subtarget, | 831 | x_convert_selection (event, selection_symbol, subtarget, |
| 866 | subproperty, 1); | 832 | subproperty, 1, dpyinfo); |
| 867 | } | 833 | } |
| 868 | success = 1; | 834 | success = 1; |
| 869 | } | 835 | } |
| @@ -872,7 +838,8 @@ x_handle_selection_request (struct input_event *event) | |||
| 872 | if (property == None) | 838 | if (property == None) |
| 873 | property = SELECTION_EVENT_TARGET (event); | 839 | property = SELECTION_EVENT_TARGET (event); |
| 874 | success = x_convert_selection (event, selection_symbol, | 840 | success = x_convert_selection (event, selection_symbol, |
| 875 | target_symbol, property, 0); | 841 | target_symbol, property, |
| 842 | 0, dpyinfo); | ||
| 876 | } | 843 | } |
| 877 | 844 | ||
| 878 | DONE: | 845 | DONE: |
| @@ -907,10 +874,9 @@ x_handle_selection_request (struct input_event *event) | |||
| 907 | Return 0 if the selection failed to convert, 1 otherwise. */ | 874 | Return 0 if the selection failed to convert, 1 otherwise. */ |
| 908 | 875 | ||
| 909 | static int | 876 | static int |
| 910 | x_convert_selection (struct input_event *event, | 877 | x_convert_selection (struct input_event *event, Lisp_Object selection_symbol, |
| 911 | Lisp_Object selection_symbol, | 878 | Lisp_Object target_symbol, Atom property, |
| 912 | Lisp_Object target_symbol, | 879 | int for_multiple, struct x_display_info *dpyinfo) |
| 913 | Atom property, int for_multiple) | ||
| 914 | { | 880 | { |
| 915 | struct gcpro gcpro1; | 881 | struct gcpro gcpro1; |
| 916 | Lisp_Object lisp_selection; | 882 | Lisp_Object lisp_selection; |
| @@ -918,7 +884,8 @@ x_convert_selection (struct input_event *event, | |||
| 918 | GCPRO1 (lisp_selection); | 884 | GCPRO1 (lisp_selection); |
| 919 | 885 | ||
| 920 | lisp_selection | 886 | lisp_selection |
| 921 | = x_get_local_selection (selection_symbol, target_symbol, 0); | 887 | = x_get_local_selection (selection_symbol, target_symbol, |
| 888 | 0, dpyinfo); | ||
| 922 | 889 | ||
| 923 | /* A nil return value means we can't perform the conversion. */ | 890 | /* A nil return value means we can't perform the conversion. */ |
| 924 | if (NILP (lisp_selection) | 891 | if (NILP (lisp_selection) |
| @@ -970,32 +937,14 @@ x_handle_selection_clear (struct input_event *event) | |||
| 970 | Lisp_Object selection_symbol, local_selection_data; | 937 | Lisp_Object selection_symbol, local_selection_data; |
| 971 | Time local_selection_time; | 938 | Time local_selection_time; |
| 972 | struct x_display_info *dpyinfo = x_display_info_for_display (display); | 939 | struct x_display_info *dpyinfo = x_display_info_for_display (display); |
| 973 | struct x_display_info *t_dpyinfo; | 940 | Lisp_Object Vselection_alist; |
| 974 | 941 | ||
| 975 | TRACE0 ("x_handle_selection_clear"); | 942 | TRACE0 ("x_handle_selection_clear"); |
| 976 | 943 | ||
| 977 | /* If the new selection owner is also Emacs, | 944 | if (!dpyinfo) return; |
| 978 | don't clear the new selection. */ | ||
| 979 | BLOCK_INPUT; | ||
| 980 | /* Check each display on the same terminal, | ||
| 981 | to see if this Emacs job now owns the selection | ||
| 982 | through that display. */ | ||
| 983 | for (t_dpyinfo = x_display_list; t_dpyinfo; t_dpyinfo = t_dpyinfo->next) | ||
| 984 | if (t_dpyinfo->terminal->kboard == dpyinfo->terminal->kboard) | ||
| 985 | { | ||
| 986 | Window owner_window | ||
| 987 | = XGetSelectionOwner (t_dpyinfo->display, selection); | ||
| 988 | if (x_window_to_frame (t_dpyinfo, owner_window) != 0) | ||
| 989 | { | ||
| 990 | UNBLOCK_INPUT; | ||
| 991 | return; | ||
| 992 | } | ||
| 993 | } | ||
| 994 | UNBLOCK_INPUT; | ||
| 995 | 945 | ||
| 996 | selection_symbol = x_atom_to_symbol (display, selection); | 946 | selection_symbol = x_atom_to_symbol (display, selection); |
| 997 | 947 | local_selection_data = LOCAL_SELECTION (selection_symbol, dpyinfo); | |
| 998 | local_selection_data = assq_no_quit (selection_symbol, Vselection_alist); | ||
| 999 | 948 | ||
| 1000 | /* Well, we already believe that we don't own it, so that's just fine. */ | 949 | /* Well, we already believe that we don't own it, so that's just fine. */ |
| 1001 | if (NILP (local_selection_data)) return; | 950 | if (NILP (local_selection_data)) return; |
| @@ -1003,43 +952,38 @@ x_handle_selection_clear (struct input_event *event) | |||
| 1003 | local_selection_time = (Time) | 952 | local_selection_time = (Time) |
| 1004 | cons_to_long (XCAR (XCDR (XCDR (local_selection_data)))); | 953 | cons_to_long (XCAR (XCDR (XCDR (local_selection_data)))); |
| 1005 | 954 | ||
| 1006 | /* This SelectionClear is for a selection that we no longer own, so we can | 955 | /* We have reasserted the selection since this SelectionClear was |
| 1007 | disregard it. (That is, we have reasserted the selection since this | 956 | generated, so we can disregard it. */ |
| 1008 | request was generated.) */ | ||
| 1009 | |||
| 1010 | if (changed_owner_time != CurrentTime | 957 | if (changed_owner_time != CurrentTime |
| 1011 | && local_selection_time > changed_owner_time) | 958 | && local_selection_time > changed_owner_time) |
| 1012 | return; | 959 | return; |
| 1013 | 960 | ||
| 1014 | /* Otherwise, we're really honest and truly being told to drop it. | 961 | /* Otherwise, really clear. Don't use Fdelq as that may QUIT;. */ |
| 1015 | Don't use Fdelq as that may QUIT;. */ | 962 | Vselection_alist = dpyinfo->terminal->Vselection_alist; |
| 1016 | 963 | if (EQ (local_selection_data, CAR (Vselection_alist))) | |
| 1017 | if (EQ (local_selection_data, Fcar (Vselection_alist))) | 964 | Vselection_alist = XCDR (Vselection_alist); |
| 1018 | Vselection_alist = Fcdr (Vselection_alist); | ||
| 1019 | else | 965 | else |
| 1020 | { | 966 | { |
| 1021 | Lisp_Object rest; | 967 | Lisp_Object rest; |
| 1022 | for (rest = Vselection_alist; CONSP (rest); rest = XCDR (rest)) | 968 | for (rest = Vselection_alist; CONSP (rest); rest = XCDR (rest)) |
| 1023 | if (EQ (local_selection_data, Fcar (XCDR (rest)))) | 969 | if (EQ (local_selection_data, CAR (XCDR (rest)))) |
| 1024 | { | 970 | { |
| 1025 | XSETCDR (rest, Fcdr (XCDR (rest))); | 971 | XSETCDR (rest, XCDR (XCDR (rest))); |
| 1026 | break; | 972 | break; |
| 1027 | } | 973 | } |
| 1028 | } | 974 | } |
| 975 | dpyinfo->terminal->Vselection_alist = Vselection_alist; | ||
| 1029 | 976 | ||
| 1030 | /* Let random lisp code notice that the selection has been stolen. */ | 977 | /* Run the `x-lost-selection-functions' abnormal hook. */ |
| 1031 | |||
| 1032 | { | 978 | { |
| 1033 | Lisp_Object rest; | 979 | Lisp_Object args[2]; |
| 1034 | rest = Vx_lost_selection_functions; | 980 | args[0] = Vx_lost_selection_functions; |
| 1035 | if (!EQ (rest, Qunbound)) | 981 | args[1] = selection_symbol; |
| 1036 | { | 982 | Frun_hook_with_args (2, args); |
| 1037 | for (; CONSP (rest); rest = Fcdr (rest)) | ||
| 1038 | call1 (Fcar (rest), selection_symbol); | ||
| 1039 | prepare_menu_bars (); | ||
| 1040 | redisplay_preserve_echo_area (20); | ||
| 1041 | } | ||
| 1042 | } | 983 | } |
| 984 | |||
| 985 | prepare_menu_bars (); | ||
| 986 | redisplay_preserve_echo_area (20); | ||
| 1043 | } | 987 | } |
| 1044 | 988 | ||
| 1045 | void | 989 | void |
| @@ -1063,55 +1007,34 @@ x_clear_frame_selections (FRAME_PTR f) | |||
| 1063 | { | 1007 | { |
| 1064 | Lisp_Object frame; | 1008 | Lisp_Object frame; |
| 1065 | Lisp_Object rest; | 1009 | Lisp_Object rest; |
| 1010 | struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f); | ||
| 1011 | struct terminal *t = dpyinfo->terminal; | ||
| 1066 | 1012 | ||
| 1067 | XSETFRAME (frame, f); | 1013 | XSETFRAME (frame, f); |
| 1068 | 1014 | ||
| 1069 | /* Otherwise, we're really honest and truly being told to drop it. | ||
| 1070 | Don't use Fdelq as that may QUIT;. */ | ||
| 1071 | |||
| 1072 | /* Delete elements from the beginning of Vselection_alist. */ | 1015 | /* Delete elements from the beginning of Vselection_alist. */ |
| 1073 | while (!NILP (Vselection_alist) | 1016 | while (CONSP (t->Vselection_alist) |
| 1074 | && EQ (frame, Fcar (Fcdr (Fcdr (Fcdr (Fcar (Vselection_alist))))))) | 1017 | && EQ (frame, XCAR (XCDR (XCDR (XCDR (XCAR (t->Vselection_alist))))))) |
| 1075 | { | 1018 | { |
| 1076 | /* Let random Lisp code notice that the selection has been stolen. */ | 1019 | /* Run the `x-lost-selection-functions' abnormal hook. */ |
| 1077 | Lisp_Object hooks, selection_symbol; | 1020 | Lisp_Object args[2]; |
| 1078 | 1021 | args[0] = Vx_lost_selection_functions; | |
| 1079 | hooks = Vx_lost_selection_functions; | 1022 | args[1] = Fcar (Fcar (t->Vselection_alist)); |
| 1080 | selection_symbol = Fcar (Fcar (Vselection_alist)); | 1023 | Frun_hook_with_args (2, args); |
| 1081 | |||
| 1082 | if (!EQ (hooks, Qunbound)) | ||
| 1083 | { | ||
| 1084 | for (; CONSP (hooks); hooks = Fcdr (hooks)) | ||
| 1085 | call1 (Fcar (hooks), selection_symbol); | ||
| 1086 | #if 0 /* This can crash when deleting a frame | ||
| 1087 | from x_connection_closed. Anyway, it seems unnecessary; | ||
| 1088 | something else should cause a redisplay. */ | ||
| 1089 | redisplay_preserve_echo_area (21); | ||
| 1090 | #endif | ||
| 1091 | } | ||
| 1092 | 1024 | ||
| 1093 | Vselection_alist = Fcdr (Vselection_alist); | 1025 | t->Vselection_alist = XCDR (t->Vselection_alist); |
| 1094 | } | 1026 | } |
| 1095 | 1027 | ||
| 1096 | /* Delete elements after the beginning of Vselection_alist. */ | 1028 | /* Delete elements after the beginning of Vselection_alist. */ |
| 1097 | for (rest = Vselection_alist; CONSP (rest); rest = XCDR (rest)) | 1029 | for (rest = t->Vselection_alist; CONSP (rest); rest = XCDR (rest)) |
| 1098 | if (EQ (frame, Fcar (Fcdr (Fcdr (Fcdr (Fcar (XCDR (rest)))))))) | 1030 | if (CONSP (XCDR (rest)) |
| 1031 | && EQ (frame, XCAR (XCDR (XCDR (XCDR (XCAR (XCDR (rest)))))))) | ||
| 1099 | { | 1032 | { |
| 1100 | /* Let random Lisp code notice that the selection has been stolen. */ | 1033 | Lisp_Object args[2]; |
| 1101 | Lisp_Object hooks, selection_symbol; | 1034 | args[0] = Vx_lost_selection_functions; |
| 1102 | 1035 | args[1] = XCAR (XCAR (XCDR (rest))); | |
| 1103 | hooks = Vx_lost_selection_functions; | 1036 | Frun_hook_with_args (2, args); |
| 1104 | selection_symbol = Fcar (Fcar (XCDR (rest))); | 1037 | XSETCDR (rest, XCDR (XCDR (rest))); |
| 1105 | |||
| 1106 | if (!EQ (hooks, Qunbound)) | ||
| 1107 | { | ||
| 1108 | for (; CONSP (hooks); hooks = Fcdr (hooks)) | ||
| 1109 | call1 (Fcar (hooks), selection_symbol); | ||
| 1110 | #if 0 /* See above */ | ||
| 1111 | redisplay_preserve_echo_area (22); | ||
| 1112 | #endif | ||
| 1113 | } | ||
| 1114 | XSETCDR (rest, Fcdr (XCDR (rest))); | ||
| 1115 | break; | 1038 | break; |
| 1116 | } | 1039 | } |
| 1117 | } | 1040 | } |
| @@ -1265,37 +1188,29 @@ static Lisp_Object reading_selection_reply; | |||
| 1265 | static Window reading_selection_window; | 1188 | static Window reading_selection_window; |
| 1266 | 1189 | ||
| 1267 | /* Do protocol to read selection-data from the server. | 1190 | /* Do protocol to read selection-data from the server. |
| 1268 | Converts this to Lisp data and returns it. */ | 1191 | Converts this to Lisp data and returns it. |
| 1192 | FRAME is the frame whose X window shall request the selection. */ | ||
| 1269 | 1193 | ||
| 1270 | static Lisp_Object | 1194 | static Lisp_Object |
| 1271 | x_get_foreign_selection (Lisp_Object selection_symbol, Lisp_Object target_type, Lisp_Object time_stamp) | 1195 | x_get_foreign_selection (Lisp_Object selection_symbol, Lisp_Object target_type, |
| 1196 | Lisp_Object time_stamp, Lisp_Object frame) | ||
| 1272 | { | 1197 | { |
| 1273 | struct frame *sf = SELECTED_FRAME (); | 1198 | struct frame *f = XFRAME (frame); |
| 1274 | Window requestor_window; | 1199 | struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f); |
| 1275 | Display *display; | 1200 | Display *display = dpyinfo->display; |
| 1276 | struct x_display_info *dpyinfo; | 1201 | Window requestor_window = FRAME_X_WINDOW (f); |
| 1277 | Time requestor_time = last_event_timestamp; | 1202 | Time requestor_time = last_event_timestamp; |
| 1278 | Atom target_property; | 1203 | Atom target_property = dpyinfo->Xatom_EMACS_TMP; |
| 1279 | Atom selection_atom; | 1204 | Atom selection_atom = symbol_to_x_atom (dpyinfo, selection_symbol); |
| 1280 | Atom type_atom; | 1205 | Atom type_atom = (CONSP (target_type) |
| 1206 | ? symbol_to_x_atom (dpyinfo, XCAR (target_type)) | ||
| 1207 | : symbol_to_x_atom (dpyinfo, target_type)); | ||
| 1281 | int secs, usecs; | 1208 | int secs, usecs; |
| 1282 | int count = SPECPDL_INDEX (); | 1209 | int count = SPECPDL_INDEX (); |
| 1283 | Lisp_Object frame; | ||
| 1284 | 1210 | ||
| 1285 | if (! FRAME_X_P (sf)) | 1211 | if (!FRAME_LIVE_P (f)) |
| 1286 | return Qnil; | 1212 | return Qnil; |
| 1287 | 1213 | ||
| 1288 | requestor_window = FRAME_X_WINDOW (sf); | ||
| 1289 | display = FRAME_X_DISPLAY (sf); | ||
| 1290 | dpyinfo = FRAME_X_DISPLAY_INFO (sf); | ||
| 1291 | target_property = dpyinfo->Xatom_EMACS_TMP; | ||
| 1292 | selection_atom = symbol_to_x_atom (dpyinfo, display, selection_symbol); | ||
| 1293 | |||
| 1294 | if (CONSP (target_type)) | ||
| 1295 | type_atom = symbol_to_x_atom (dpyinfo, display, XCAR (target_type)); | ||
| 1296 | else | ||
| 1297 | type_atom = symbol_to_x_atom (dpyinfo, display, target_type); | ||
| 1298 | |||
| 1299 | if (! NILP (time_stamp)) | 1214 | if (! NILP (time_stamp)) |
| 1300 | { | 1215 | { |
| 1301 | if (CONSP (time_stamp)) | 1216 | if (CONSP (time_stamp)) |
| @@ -1329,18 +1244,13 @@ x_get_foreign_selection (Lisp_Object selection_symbol, Lisp_Object target_type, | |||
| 1329 | reading_which_selection = selection_atom; | 1244 | reading_which_selection = selection_atom; |
| 1330 | XSETCAR (reading_selection_reply, Qnil); | 1245 | XSETCAR (reading_selection_reply, Qnil); |
| 1331 | 1246 | ||
| 1332 | frame = some_frame_on_display (dpyinfo); | ||
| 1333 | |||
| 1334 | /* It should not be necessary to stop handling selection requests | 1247 | /* It should not be necessary to stop handling selection requests |
| 1335 | during this time. In fact, the SAVE_TARGETS mechanism requires | 1248 | during this time. In fact, the SAVE_TARGETS mechanism requires |
| 1336 | us to handle a clipboard manager's requests before it returns | 1249 | us to handle a clipboard manager's requests before it returns |
| 1337 | SelectionNotify. */ | 1250 | SelectionNotify. */ |
| 1338 | #if 0 | 1251 | #if 0 |
| 1339 | if (!NILP (frame)) | 1252 | x_start_queuing_selection_requests (); |
| 1340 | { | 1253 | record_unwind_protect (queue_selection_requests_unwind, Qnil); |
| 1341 | x_start_queuing_selection_requests (); | ||
| 1342 | record_unwind_protect (queue_selection_requests_unwind, Qnil); | ||
| 1343 | } | ||
| 1344 | #endif | 1254 | #endif |
| 1345 | 1255 | ||
| 1346 | UNBLOCK_INPUT; | 1256 | UNBLOCK_INPUT; |
| @@ -1820,7 +1730,7 @@ lisp_data_to_selection_data (Display *display, Lisp_Object obj, | |||
| 1820 | *size_ret = 1; | 1730 | *size_ret = 1; |
| 1821 | *data_ret = (unsigned char *) xmalloc (sizeof (Atom) + 1); | 1731 | *data_ret = (unsigned char *) xmalloc (sizeof (Atom) + 1); |
| 1822 | (*data_ret) [sizeof (Atom)] = 0; | 1732 | (*data_ret) [sizeof (Atom)] = 0; |
| 1823 | (*(Atom **) data_ret) [0] = symbol_to_x_atom (dpyinfo, display, obj); | 1733 | (*(Atom **) data_ret) [0] = symbol_to_x_atom (dpyinfo, obj); |
| 1824 | if (NILP (type)) type = QATOM; | 1734 | if (NILP (type)) type = QATOM; |
| 1825 | } | 1735 | } |
| 1826 | else if (INTEGERP (obj) | 1736 | else if (INTEGERP (obj) |
| @@ -1868,7 +1778,7 @@ lisp_data_to_selection_data (Display *display, Lisp_Object obj, | |||
| 1868 | *data_ret = (unsigned char *) xmalloc ((*size_ret) * sizeof (Atom)); | 1778 | *data_ret = (unsigned char *) xmalloc ((*size_ret) * sizeof (Atom)); |
| 1869 | for (i = 0; i < *size_ret; i++) | 1779 | for (i = 0; i < *size_ret; i++) |
| 1870 | (*(Atom **) data_ret) [i] | 1780 | (*(Atom **) data_ret) [i] |
| 1871 | = symbol_to_x_atom (dpyinfo, display, XVECTOR (obj)->contents [i]); | 1781 | = symbol_to_x_atom (dpyinfo, XVECTOR (obj)->contents [i]); |
| 1872 | } | 1782 | } |
| 1873 | else | 1783 | else |
| 1874 | /* This vector is an INTEGER set, or something like it */ | 1784 | /* This vector is an INTEGER set, or something like it */ |
| @@ -1902,7 +1812,7 @@ lisp_data_to_selection_data (Display *display, Lisp_Object obj, | |||
| 1902 | else | 1812 | else |
| 1903 | signal_error (/* Qselection_error */ "Unrecognized selection data", obj); | 1813 | signal_error (/* Qselection_error */ "Unrecognized selection data", obj); |
| 1904 | 1814 | ||
| 1905 | *type_ret = symbol_to_x_atom (dpyinfo, display, type); | 1815 | *type_ret = symbol_to_x_atom (dpyinfo, type); |
| 1906 | } | 1816 | } |
| 1907 | 1817 | ||
| 1908 | static Lisp_Object | 1818 | static Lisp_Object |
| @@ -1959,19 +1869,74 @@ x_handle_selection_notify (XSelectionEvent *event) | |||
| 1959 | } | 1869 | } |
| 1960 | 1870 | ||
| 1961 | 1871 | ||
| 1872 | /* From a Lisp_Object, return a suitable frame for selection | ||
| 1873 | operations. OBJECT may be a frame, a terminal object, or nil | ||
| 1874 | (which stands for the selected frame--or, if that is not an X | ||
| 1875 | frame, the first X display on the list). If no suitable frame can | ||
| 1876 | be found, return NULL. */ | ||
| 1877 | |||
| 1878 | static struct frame * | ||
| 1879 | frame_for_x_selection (Lisp_Object object) | ||
| 1880 | { | ||
| 1881 | Lisp_Object tail, frame; | ||
| 1882 | struct frame *f; | ||
| 1883 | |||
| 1884 | if (NILP (object)) | ||
| 1885 | { | ||
| 1886 | f = XFRAME (selected_frame); | ||
| 1887 | if (FRAME_X_P (f) && FRAME_LIVE_P (f)) | ||
| 1888 | return f; | ||
| 1889 | |||
| 1890 | for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail)) | ||
| 1891 | { | ||
| 1892 | f = XFRAME (XCAR (tail)); | ||
| 1893 | if (FRAME_X_P (f) && FRAME_LIVE_P (f)) | ||
| 1894 | return f; | ||
| 1895 | } | ||
| 1896 | } | ||
| 1897 | else if (TERMINALP (object)) | ||
| 1898 | { | ||
| 1899 | struct terminal *t = get_terminal (object, 1); | ||
| 1900 | if (t->type == output_x_window) | ||
| 1901 | { | ||
| 1902 | for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail)) | ||
| 1903 | { | ||
| 1904 | f = XFRAME (XCAR (tail)); | ||
| 1905 | if (FRAME_LIVE_P (f) && f->terminal == t) | ||
| 1906 | return f; | ||
| 1907 | } | ||
| 1908 | } | ||
| 1909 | } | ||
| 1910 | else if (FRAMEP (object)) | ||
| 1911 | { | ||
| 1912 | f = XFRAME (object); | ||
| 1913 | if (FRAME_X_P (f) && FRAME_LIVE_P (f)) | ||
| 1914 | return f; | ||
| 1915 | } | ||
| 1916 | |||
| 1917 | return NULL; | ||
| 1918 | } | ||
| 1919 | |||
| 1920 | |||
| 1962 | DEFUN ("x-own-selection-internal", Fx_own_selection_internal, | 1921 | DEFUN ("x-own-selection-internal", Fx_own_selection_internal, |
| 1963 | Sx_own_selection_internal, 2, 2, 0, | 1922 | Sx_own_selection_internal, 2, 3, 0, |
| 1964 | doc: /* Assert an X selection of type SELECTION and value VALUE. | 1923 | doc: /* Assert an X selection of type SELECTION and value VALUE. |
| 1965 | SELECTION is a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'. | 1924 | SELECTION is a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'. |
| 1966 | \(Those are literal upper-case symbol names, since that's what X expects.) | 1925 | \(Those are literal upper-case symbol names, since that's what X expects.) |
| 1967 | VALUE is typically a string, or a cons of two markers, but may be | 1926 | VALUE is typically a string, or a cons of two markers, but may be |
| 1968 | anything that the functions on `selection-converter-alist' know about. */) | 1927 | anything that the functions on `selection-converter-alist' know about. |
| 1969 | (Lisp_Object selection, Lisp_Object value) | 1928 | |
| 1929 | FRAME should be a frame that should own the selection. If omitted or | ||
| 1930 | nil, it defaults to the selected frame. */) | ||
| 1931 | (Lisp_Object selection, Lisp_Object value, Lisp_Object frame) | ||
| 1970 | { | 1932 | { |
| 1971 | check_x (); | 1933 | if (NILP (frame)) frame = selected_frame; |
| 1934 | if (!FRAME_LIVE_P (XFRAME (frame)) || !FRAME_X_P (XFRAME (frame))) | ||
| 1935 | error ("X selection unavailable for this frame"); | ||
| 1936 | |||
| 1972 | CHECK_SYMBOL (selection); | 1937 | CHECK_SYMBOL (selection); |
| 1973 | if (NILP (value)) error ("VALUE may not be nil"); | 1938 | if (NILP (value)) error ("VALUE may not be nil"); |
| 1974 | x_own_selection (selection, value); | 1939 | x_own_selection (selection, value, frame); |
| 1975 | return value; | 1940 | return value; |
| 1976 | } | 1941 | } |
| 1977 | 1942 | ||
| @@ -1981,38 +1946,42 @@ anything that the functions on `selection-converter-alist' know about. */) | |||
| 1981 | will block until all of the data has arrived. */ | 1946 | will block until all of the data has arrived. */ |
| 1982 | 1947 | ||
| 1983 | DEFUN ("x-get-selection-internal", Fx_get_selection_internal, | 1948 | DEFUN ("x-get-selection-internal", Fx_get_selection_internal, |
| 1984 | Sx_get_selection_internal, 2, 3, 0, | 1949 | Sx_get_selection_internal, 2, 4, 0, |
| 1985 | doc: /* Return text selected from some X window. | 1950 | doc: /* Return text selected from some X window. |
| 1986 | SELECTION is a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'. | 1951 | SELECTION is a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'. |
| 1987 | \(Those are literal upper-case symbol names, since that's what X expects.) | 1952 | \(Those are literal upper-case symbol names, since that's what X expects.) |
| 1988 | TYPE is the type of data desired, typically `STRING'. | 1953 | TYPE is the type of data desired, typically `STRING'. |
| 1989 | TIME_STAMP is the time to use in the XConvertSelection call for foreign | 1954 | TIME_STAMP is the time to use in the XConvertSelection call for foreign |
| 1990 | selections. If omitted, defaults to the time for the last event. */) | 1955 | selections. If omitted, defaults to the time for the last event. |
| 1991 | (Lisp_Object selection_symbol, Lisp_Object target_type, Lisp_Object time_stamp) | 1956 | |
| 1957 | TERMINAL should be a terminal object or a frame specifying the X | ||
| 1958 | server to query. If omitted or nil, that stands for the selected | ||
| 1959 | frame's display, or the first available X display. */) | ||
| 1960 | (Lisp_Object selection_symbol, Lisp_Object target_type, | ||
| 1961 | Lisp_Object time_stamp, Lisp_Object terminal) | ||
| 1992 | { | 1962 | { |
| 1993 | Lisp_Object val = Qnil; | 1963 | Lisp_Object val = Qnil; |
| 1994 | struct gcpro gcpro1, gcpro2; | 1964 | struct gcpro gcpro1, gcpro2; |
| 1965 | struct frame *f = frame_for_x_selection (terminal); | ||
| 1995 | GCPRO2 (target_type, val); /* we store newly consed data into these */ | 1966 | GCPRO2 (target_type, val); /* we store newly consed data into these */ |
| 1996 | check_x (); | 1967 | |
| 1997 | CHECK_SYMBOL (selection_symbol); | 1968 | CHECK_SYMBOL (selection_symbol); |
| 1969 | CHECK_SYMBOL (target_type); | ||
| 1970 | if (EQ (target_type, QMULTIPLE)) | ||
| 1971 | error ("Retrieving MULTIPLE selections is currently unimplemented"); | ||
| 1972 | if (!f) | ||
| 1973 | error ("X selection unavailable for this frame"); | ||
| 1974 | |||
| 1975 | val = x_get_local_selection (selection_symbol, target_type, 1, | ||
| 1976 | FRAME_X_DISPLAY_INFO (f)); | ||
| 1998 | 1977 | ||
| 1999 | #if 0 /* #### MULTIPLE doesn't work yet */ | 1978 | if (NILP (val) && FRAME_LIVE_P (f)) |
| 2000 | if (CONSP (target_type) | ||
| 2001 | && XCAR (target_type) == QMULTIPLE) | ||
| 2002 | { | 1979 | { |
| 2003 | CHECK_VECTOR (XCDR (target_type)); | 1980 | Lisp_Object frame; |
| 2004 | /* So we don't destructively modify this... */ | 1981 | XSETFRAME (frame, f); |
| 2005 | target_type = copy_multiple_data (target_type); | 1982 | RETURN_UNGCPRO (x_get_foreign_selection (selection_symbol, target_type, |
| 1983 | time_stamp, frame)); | ||
| 2006 | } | 1984 | } |
| 2007 | else | ||
| 2008 | #endif | ||
| 2009 | CHECK_SYMBOL (target_type); | ||
| 2010 | |||
| 2011 | val = x_get_local_selection (selection_symbol, target_type, 1); | ||
| 2012 | |||
| 2013 | if (NILP (val)) | ||
| 2014 | RETURN_UNGCPRO (x_get_foreign_selection (selection_symbol, | ||
| 2015 | target_type, time_stamp)); | ||
| 2016 | 1985 | ||
| 2017 | if (CONSP (val) && SYMBOLP (XCAR (val))) | 1986 | if (CONSP (val) && SYMBOLP (XCAR (val))) |
| 2018 | { | 1987 | { |
| @@ -2024,10 +1993,14 @@ selections. If omitted, defaults to the time for the last event. */) | |||
| 2024 | } | 1993 | } |
| 2025 | 1994 | ||
| 2026 | DEFUN ("x-disown-selection-internal", Fx_disown_selection_internal, | 1995 | DEFUN ("x-disown-selection-internal", Fx_disown_selection_internal, |
| 2027 | Sx_disown_selection_internal, 1, 2, 0, | 1996 | Sx_disown_selection_internal, 1, 3, 0, |
| 2028 | doc: /* If we own the selection SELECTION, disown it. | 1997 | doc: /* If we own the selection SELECTION, disown it. |
| 2029 | Disowning it means there is no such selection. */) | 1998 | Disowning it means there is no such selection. |
| 2030 | (Lisp_Object selection, Lisp_Object time_object) | 1999 | |
| 2000 | TERMINAL should be a terminal object or a frame specifying the X | ||
| 2001 | server to query. If omitted or nil, that stands for the selected | ||
| 2002 | frame's display, or the first available X display. */) | ||
| 2003 | (Lisp_Object selection, Lisp_Object time_object, Lisp_Object terminal) | ||
| 2031 | { | 2004 | { |
| 2032 | Time timestamp; | 2005 | Time timestamp; |
| 2033 | Atom selection_atom; | 2006 | Atom selection_atom; |
| @@ -2035,29 +2008,25 @@ Disowning it means there is no such selection. */) | |||
| 2035 | struct selection_input_event sie; | 2008 | struct selection_input_event sie; |
| 2036 | struct input_event ie; | 2009 | struct input_event ie; |
| 2037 | } event; | 2010 | } event; |
| 2038 | Display *display; | 2011 | struct frame *f = frame_for_x_selection (terminal); |
| 2039 | struct x_display_info *dpyinfo; | 2012 | struct x_display_info *dpyinfo; |
| 2040 | struct frame *sf = SELECTED_FRAME (); | ||
| 2041 | 2013 | ||
| 2042 | check_x (); | 2014 | if (!f) |
| 2043 | if (! FRAME_X_P (sf)) | ||
| 2044 | return Qnil; | 2015 | return Qnil; |
| 2045 | 2016 | ||
| 2046 | display = FRAME_X_DISPLAY (sf); | 2017 | dpyinfo = FRAME_X_DISPLAY_INFO (f); |
| 2047 | dpyinfo = FRAME_X_DISPLAY_INFO (sf); | ||
| 2048 | CHECK_SYMBOL (selection); | 2018 | CHECK_SYMBOL (selection); |
| 2049 | if (NILP (time_object)) | ||
| 2050 | timestamp = last_event_timestamp; | ||
| 2051 | else | ||
| 2052 | timestamp = cons_to_long (time_object); | ||
| 2053 | 2019 | ||
| 2054 | if (NILP (assq_no_quit (selection, Vselection_alist))) | 2020 | /* Don't disown the selection when we're not the owner. */ |
| 2055 | return Qnil; /* Don't disown the selection when we're not the owner. */ | 2021 | if (NILP (LOCAL_SELECTION (selection, dpyinfo))) |
| 2022 | return Qnil; | ||
| 2056 | 2023 | ||
| 2057 | selection_atom = symbol_to_x_atom (dpyinfo, display, selection); | 2024 | selection_atom = symbol_to_x_atom (dpyinfo, selection); |
| 2058 | 2025 | ||
| 2059 | BLOCK_INPUT; | 2026 | BLOCK_INPUT; |
| 2060 | XSetSelectionOwner (display, selection_atom, None, timestamp); | 2027 | timestamp = (NILP (time_object) ? last_event_timestamp |
| 2028 | : cons_to_long (time_object)); | ||
| 2029 | XSetSelectionOwner (dpyinfo->display, selection_atom, None, timestamp); | ||
| 2061 | UNBLOCK_INPUT; | 2030 | UNBLOCK_INPUT; |
| 2062 | 2031 | ||
| 2063 | /* It doesn't seem to be guaranteed that a SelectionClear event will be | 2032 | /* It doesn't seem to be guaranteed that a SelectionClear event will be |
| @@ -2065,7 +2034,7 @@ Disowning it means there is no such selection. */) | |||
| 2065 | the selection owner to None. The NCD server does, the MIT Sun4 server | 2034 | the selection owner to None. The NCD server does, the MIT Sun4 server |
| 2066 | doesn't. So we synthesize one; this means we might get two, but | 2035 | doesn't. So we synthesize one; this means we might get two, but |
| 2067 | that's ok, because the second one won't have any effect. */ | 2036 | that's ok, because the second one won't have any effect. */ |
| 2068 | SELECTION_EVENT_DISPLAY (&event.sie) = display; | 2037 | SELECTION_EVENT_DISPLAY (&event.sie) = dpyinfo->display; |
| 2069 | SELECTION_EVENT_SELECTION (&event.sie) = selection_atom; | 2038 | SELECTION_EVENT_SELECTION (&event.sie) = selection_atom; |
| 2070 | SELECTION_EVENT_TIME (&event.sie) = timestamp; | 2039 | SELECTION_EVENT_TIME (&event.sie) = timestamp; |
| 2071 | x_handle_selection_clear (&event.ie); | 2040 | x_handle_selection_clear (&event.ie); |
| @@ -2074,59 +2043,138 @@ Disowning it means there is no such selection. */) | |||
| 2074 | } | 2043 | } |
| 2075 | 2044 | ||
| 2076 | DEFUN ("x-selection-owner-p", Fx_selection_owner_p, Sx_selection_owner_p, | 2045 | DEFUN ("x-selection-owner-p", Fx_selection_owner_p, Sx_selection_owner_p, |
| 2077 | 0, 1, 0, | 2046 | 0, 2, 0, |
| 2078 | doc: /* Whether the current Emacs process owns the given X Selection. | 2047 | doc: /* Whether the current Emacs process owns the given X Selection. |
| 2079 | The arg should be the name of the selection in question, typically one of | 2048 | The arg should be the name of the selection in question, typically one of |
| 2080 | the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'. | 2049 | the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'. |
| 2081 | \(Those are literal upper-case symbol names, since that's what X expects.) | 2050 | \(Those are literal upper-case symbol names, since that's what X expects.) |
| 2082 | For convenience, the symbol nil is the same as `PRIMARY', | 2051 | For convenience, the symbol nil is the same as `PRIMARY', |
| 2083 | and t is the same as `SECONDARY'. */) | 2052 | and t is the same as `SECONDARY'. |
| 2084 | (Lisp_Object selection) | 2053 | |
| 2054 | TERMINAL should be a terminal object or a frame specifying the X | ||
| 2055 | server to query. If omitted or nil, that stands for the selected | ||
| 2056 | frame's display, or the first available X display. */) | ||
| 2057 | (Lisp_Object selection, Lisp_Object terminal) | ||
| 2085 | { | 2058 | { |
| 2086 | check_x (); | 2059 | struct frame *f = frame_for_x_selection (terminal); |
| 2060 | |||
| 2087 | CHECK_SYMBOL (selection); | 2061 | CHECK_SYMBOL (selection); |
| 2088 | if (EQ (selection, Qnil)) selection = QPRIMARY; | 2062 | if (EQ (selection, Qnil)) selection = QPRIMARY; |
| 2089 | if (EQ (selection, Qt)) selection = QSECONDARY; | 2063 | if (EQ (selection, Qt)) selection = QSECONDARY; |
| 2090 | 2064 | ||
| 2091 | if (NILP (Fassq (selection, Vselection_alist))) | 2065 | if (f && !NILP (LOCAL_SELECTION (selection, FRAME_X_DISPLAY_INFO (f)))) |
| 2066 | return Qt; | ||
| 2067 | else | ||
| 2092 | return Qnil; | 2068 | return Qnil; |
| 2093 | return Qt; | ||
| 2094 | } | 2069 | } |
| 2095 | 2070 | ||
| 2096 | DEFUN ("x-selection-exists-p", Fx_selection_exists_p, Sx_selection_exists_p, | 2071 | DEFUN ("x-selection-exists-p", Fx_selection_exists_p, Sx_selection_exists_p, |
| 2097 | 0, 1, 0, | 2072 | 0, 2, 0, |
| 2098 | doc: /* Whether there is an owner for the given X Selection. | 2073 | doc: /* Whether there is an owner for the given X selection. |
| 2099 | The arg should be the name of the selection in question, typically one of | 2074 | SELECTION should be the name of the selection in question, typically |
| 2100 | the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'. | 2075 | one of the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'. (X expects |
| 2101 | \(Those are literal upper-case symbol names, since that's what X expects.) | 2076 | these literal upper-case names.) The symbol nil is the same as |
| 2102 | For convenience, the symbol nil is the same as `PRIMARY', | 2077 | `PRIMARY', and t is the same as `SECONDARY'. |
| 2103 | and t is the same as `SECONDARY'. */) | 2078 | |
| 2104 | (Lisp_Object selection) | 2079 | TERMINAL should be a terminal object or a frame specifying the X |
| 2080 | server to query. If omitted or nil, that stands for the selected | ||
| 2081 | frame's display, or the first available X display. */) | ||
| 2082 | (Lisp_Object selection, Lisp_Object terminal) | ||
| 2105 | { | 2083 | { |
| 2106 | Window owner; | 2084 | Window owner; |
| 2107 | Atom atom; | 2085 | Atom atom; |
| 2108 | Display *dpy; | 2086 | struct frame *f = frame_for_x_selection (terminal); |
| 2109 | struct frame *sf = SELECTED_FRAME (); | 2087 | struct x_display_info *dpyinfo; |
| 2110 | |||
| 2111 | /* It should be safe to call this before we have an X frame. */ | ||
| 2112 | if (! FRAME_X_P (sf)) | ||
| 2113 | return Qnil; | ||
| 2114 | 2088 | ||
| 2115 | dpy = FRAME_X_DISPLAY (sf); | ||
| 2116 | CHECK_SYMBOL (selection); | 2089 | CHECK_SYMBOL (selection); |
| 2117 | if (!NILP (Fx_selection_owner_p (selection))) | ||
| 2118 | return Qt; | ||
| 2119 | if (EQ (selection, Qnil)) selection = QPRIMARY; | 2090 | if (EQ (selection, Qnil)) selection = QPRIMARY; |
| 2120 | if (EQ (selection, Qt)) selection = QSECONDARY; | 2091 | if (EQ (selection, Qt)) selection = QSECONDARY; |
| 2121 | atom = symbol_to_x_atom (FRAME_X_DISPLAY_INFO (sf), dpy, selection); | 2092 | |
| 2122 | if (atom == 0) | 2093 | if (!f) |
| 2123 | return Qnil; | 2094 | return Qnil; |
| 2095 | |||
| 2096 | dpyinfo = FRAME_X_DISPLAY_INFO (f); | ||
| 2097 | |||
| 2098 | if (!NILP (LOCAL_SELECTION (selection, dpyinfo))) | ||
| 2099 | return Qt; | ||
| 2100 | |||
| 2101 | atom = symbol_to_x_atom (dpyinfo, selection); | ||
| 2102 | if (atom == 0) return Qnil; | ||
| 2124 | BLOCK_INPUT; | 2103 | BLOCK_INPUT; |
| 2125 | owner = XGetSelectionOwner (dpy, atom); | 2104 | owner = XGetSelectionOwner (dpyinfo->display, atom); |
| 2126 | UNBLOCK_INPUT; | 2105 | UNBLOCK_INPUT; |
| 2127 | return (owner ? Qt : Qnil); | 2106 | return (owner ? Qt : Qnil); |
| 2128 | } | 2107 | } |
| 2129 | 2108 | ||
| 2109 | /* Send the clipboard manager a SAVE_TARGETS request with a | ||
| 2110 | UTF8_STRING property, as described by | ||
| 2111 | http://www.freedesktop.org/wiki/ClipboardManager */ | ||
| 2112 | |||
| 2113 | void | ||
| 2114 | x_clipboard_manager_save (struct x_display_info *dpyinfo, | ||
| 2115 | Lisp_Object frame) | ||
| 2116 | { | ||
| 2117 | struct frame *f = XFRAME (frame); | ||
| 2118 | Atom data = dpyinfo->Xatom_UTF8_STRING; | ||
| 2119 | |||
| 2120 | XChangeProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), | ||
| 2121 | dpyinfo->Xatom_EMACS_TMP, | ||
| 2122 | dpyinfo->Xatom_ATOM, 32, PropModeReplace, | ||
| 2123 | (unsigned char *) &data, 1); | ||
| 2124 | x_get_foreign_selection (QCLIPBOARD_MANAGER, QSAVE_TARGETS, | ||
| 2125 | Qnil, frame); | ||
| 2126 | } | ||
| 2127 | |||
| 2128 | DEFUN ("x-clipboard-manager-save", Fx_clipboard_manager_save, | ||
| 2129 | Sx_clipboard_manager_save, 0, 1, 0, | ||
| 2130 | doc: /* Save the clipboard contents to the clipboard manager. | ||
| 2131 | This function is intended to run from `delete-frame-functions' and | ||
| 2132 | `kill-emacs-hook', to transfer clipboard data owned by Emacs to a | ||
| 2133 | clipboard manager prior to deleting a frame or killing Emacs. | ||
| 2134 | |||
| 2135 | FRAME specifies a frame owning a clipboard; do nothing if FRAME does | ||
| 2136 | not own the clipboard, or if no clipboard manager is present. If | ||
| 2137 | FRAME is nil, save all clipboard contents owned by Emacs. */) | ||
| 2138 | (Lisp_Object frame) | ||
| 2139 | { | ||
| 2140 | if (FRAMEP (frame)) | ||
| 2141 | { | ||
| 2142 | struct frame *f = XFRAME (frame); | ||
| 2143 | if (FRAME_LIVE_P (f) && FRAME_X_P (f)) | ||
| 2144 | { | ||
| 2145 | struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f); | ||
| 2146 | Lisp_Object local_selection | ||
| 2147 | = LOCAL_SELECTION (QCLIPBOARD, dpyinfo); | ||
| 2148 | |||
| 2149 | if (!NILP (local_selection) | ||
| 2150 | && EQ (frame, XCAR (XCDR (XCDR (XCDR (local_selection))))) | ||
| 2151 | && XGetSelectionOwner (dpyinfo->display, | ||
| 2152 | dpyinfo->Xatom_CLIPBOARD_MANAGER)) | ||
| 2153 | x_clipboard_manager_save (dpyinfo, frame); | ||
| 2154 | } | ||
| 2155 | } | ||
| 2156 | else if (NILP (frame)) | ||
| 2157 | { | ||
| 2158 | /* Loop through all X displays, saving owned clipboards. */ | ||
| 2159 | struct x_display_info *dpyinfo; | ||
| 2160 | Lisp_Object local_selection, frame; | ||
| 2161 | for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next) | ||
| 2162 | { | ||
| 2163 | local_selection = LOCAL_SELECTION (QCLIPBOARD, dpyinfo); | ||
| 2164 | if (NILP (local_selection) | ||
| 2165 | || !XGetSelectionOwner (dpyinfo->display, | ||
| 2166 | dpyinfo->Xatom_CLIPBOARD_MANAGER)) | ||
| 2167 | continue; | ||
| 2168 | |||
| 2169 | frame = XCAR (XCDR (XCDR (XCDR (local_selection)))); | ||
| 2170 | if (FRAME_LIVE_P (XFRAME (frame))) | ||
| 2171 | x_clipboard_manager_save (dpyinfo, frame); | ||
| 2172 | } | ||
| 2173 | } | ||
| 2174 | |||
| 2175 | return Qnil; | ||
| 2176 | } | ||
| 2177 | |||
| 2130 | 2178 | ||
| 2131 | /*********************************************************************** | 2179 | /*********************************************************************** |
| 2132 | Drag and drop support | 2180 | Drag and drop support |
| @@ -2325,7 +2373,7 @@ FRAME is on. If FRAME is nil, the selected frame is used. */) | |||
| 2325 | 2373 | ||
| 2326 | 2374 | ||
| 2327 | if (SYMBOLP (atom)) | 2375 | if (SYMBOLP (atom)) |
| 2328 | x_atom = symbol_to_x_atom (dpyinfo, FRAME_X_DISPLAY (f), atom); | 2376 | x_atom = symbol_to_x_atom (dpyinfo, atom); |
| 2329 | else if (STRINGP (atom)) | 2377 | else if (STRINGP (atom)) |
| 2330 | { | 2378 | { |
| 2331 | BLOCK_INPUT; | 2379 | BLOCK_INPUT; |
| @@ -2537,6 +2585,7 @@ syms_of_xselect (void) | |||
| 2537 | defsubr (&Sx_disown_selection_internal); | 2585 | defsubr (&Sx_disown_selection_internal); |
| 2538 | defsubr (&Sx_selection_owner_p); | 2586 | defsubr (&Sx_selection_owner_p); |
| 2539 | defsubr (&Sx_selection_exists_p); | 2587 | defsubr (&Sx_selection_exists_p); |
| 2588 | defsubr (&Sx_clipboard_manager_save); | ||
| 2540 | 2589 | ||
| 2541 | defsubr (&Sx_get_atom_name); | 2590 | defsubr (&Sx_get_atom_name); |
| 2542 | defsubr (&Sx_send_client_message); | 2591 | defsubr (&Sx_send_client_message); |
| @@ -2552,9 +2601,6 @@ syms_of_xselect (void) | |||
| 2552 | property_change_reply = Fcons (Qnil, Qnil); | 2601 | property_change_reply = Fcons (Qnil, Qnil); |
| 2553 | staticpro (&property_change_reply); | 2602 | staticpro (&property_change_reply); |
| 2554 | 2603 | ||
| 2555 | Vselection_alist = Qnil; | ||
| 2556 | staticpro (&Vselection_alist); | ||
| 2557 | |||
| 2558 | converted_selections = NULL; | 2604 | converted_selections = NULL; |
| 2559 | conversion_fail_tag = None; | 2605 | conversion_fail_tag = None; |
| 2560 | 2606 | ||
| @@ -2618,6 +2664,8 @@ A value of 0 means wait as long as necessary. This is initialized from the | |||
| 2618 | DEFSYM (QTARGETS, "TARGETS"); | 2664 | DEFSYM (QTARGETS, "TARGETS"); |
| 2619 | DEFSYM (QATOM, "ATOM"); | 2665 | DEFSYM (QATOM, "ATOM"); |
| 2620 | DEFSYM (QATOM_PAIR, "ATOM_PAIR"); | 2666 | DEFSYM (QATOM_PAIR, "ATOM_PAIR"); |
| 2667 | DEFSYM (QCLIPBOARD_MANAGER, "CLIPBOARD_MANAGER"); | ||
| 2668 | DEFSYM (QSAVE_TARGETS, "SAVE_TARGETS"); | ||
| 2621 | DEFSYM (QNULL, "NULL"); | 2669 | DEFSYM (QNULL, "NULL"); |
| 2622 | DEFSYM (Qcompound_text_with_extensions, "compound-text-with-extensions"); | 2670 | DEFSYM (Qcompound_text_with_extensions, "compound-text-with-extensions"); |
| 2623 | DEFSYM (Qforeign_selection, "foreign-selection"); | 2671 | DEFSYM (Qforeign_selection, "foreign-selection"); |
diff --git a/src/xterm.c b/src/xterm.c index 64030a3151d..3b8112d972b 100644 --- a/src/xterm.c +++ b/src/xterm.c | |||
| @@ -10186,7 +10186,9 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) | |||
| 10186 | { "_EMACS_TMP_", &dpyinfo->Xatom_EMACS_TMP }, | 10186 | { "_EMACS_TMP_", &dpyinfo->Xatom_EMACS_TMP }, |
| 10187 | { "TARGETS", &dpyinfo->Xatom_TARGETS }, | 10187 | { "TARGETS", &dpyinfo->Xatom_TARGETS }, |
| 10188 | { "NULL", &dpyinfo->Xatom_NULL }, | 10188 | { "NULL", &dpyinfo->Xatom_NULL }, |
| 10189 | { "ATOM", &dpyinfo->Xatom_ATOM }, | ||
| 10189 | { "ATOM_PAIR", &dpyinfo->Xatom_ATOM_PAIR }, | 10190 | { "ATOM_PAIR", &dpyinfo->Xatom_ATOM_PAIR }, |
| 10191 | { "CLIPBOARD_MANAGER", &dpyinfo->Xatom_CLIPBOARD_MANAGER }, | ||
| 10190 | { "_XEMBED_INFO", &dpyinfo->Xatom_XEMBED_INFO }, | 10192 | { "_XEMBED_INFO", &dpyinfo->Xatom_XEMBED_INFO }, |
| 10191 | /* For properties of font. */ | 10193 | /* For properties of font. */ |
| 10192 | { "PIXEL_SIZE", &dpyinfo->Xatom_PIXEL_SIZE }, | 10194 | { "PIXEL_SIZE", &dpyinfo->Xatom_PIXEL_SIZE }, |
diff --git a/src/xterm.h b/src/xterm.h index 1b90b6d8ff4..c44978d5386 100644 --- a/src/xterm.h +++ b/src/xterm.h | |||
| @@ -254,7 +254,7 @@ struct x_display_info | |||
| 254 | Atom Xatom_CLIPBOARD, Xatom_TIMESTAMP, Xatom_TEXT, Xatom_DELETE, | 254 | Atom Xatom_CLIPBOARD, Xatom_TIMESTAMP, Xatom_TEXT, Xatom_DELETE, |
| 255 | Xatom_COMPOUND_TEXT, Xatom_UTF8_STRING, | 255 | Xatom_COMPOUND_TEXT, Xatom_UTF8_STRING, |
| 256 | Xatom_MULTIPLE, Xatom_INCR, Xatom_EMACS_TMP, Xatom_TARGETS, Xatom_NULL, | 256 | Xatom_MULTIPLE, Xatom_INCR, Xatom_EMACS_TMP, Xatom_TARGETS, Xatom_NULL, |
| 257 | Xatom_ATOM_PAIR; | 257 | Xatom_ATOM, Xatom_ATOM_PAIR, Xatom_CLIPBOARD_MANAGER; |
| 258 | 258 | ||
| 259 | /* More atoms for font properties. The last three are private | 259 | /* More atoms for font properties. The last three are private |
| 260 | properties, see the comments in src/fontset.h. */ | 260 | properties, see the comments in src/fontset.h. */ |
| @@ -1027,7 +1027,7 @@ extern Lisp_Object x_property_data_to_lisp (struct frame *, | |||
| 1027 | 1027 | ||
| 1028 | /* Defined in xfns.c */ | 1028 | /* Defined in xfns.c */ |
| 1029 | 1029 | ||
| 1030 | extern struct x_display_info * check_x_display_info (Lisp_Object frame); | 1030 | extern struct x_display_info * check_x_display_info (Lisp_Object); |
| 1031 | extern Lisp_Object x_get_focus_frame (struct frame *); | 1031 | extern Lisp_Object x_get_focus_frame (struct frame *); |
| 1032 | 1032 | ||
| 1033 | #ifdef USE_GTK | 1033 | #ifdef USE_GTK |