diff options
| author | Gerd Moellmann | 2001-07-12 14:38:51 +0000 |
|---|---|---|
| committer | Gerd Moellmann | 2001-07-12 14:38:51 +0000 |
| commit | d9c0d4a31a12b6c2944ebba1ae5552ef249c28d2 (patch) | |
| tree | 990760c462616a72cf08edd26bbc103b68950398 /src | |
| parent | 158f4aea95b259d8f1129ede0c322e065971710e (diff) | |
| download | emacs-d9c0d4a31a12b6c2944ebba1ae5552ef249c28d2.tar.gz emacs-d9c0d4a31a12b6c2944ebba1ae5552ef249c28d2.zip | |
(x_decline_selection_request): Handle errors
caused by receivers that have vanished.
(TRACE0, TRACE1, TRACE2): New macros, defined
depending on TRACE_SELECTION. Replace fprintfs in #if 0 with
TRACE macros to facilitate debugging. Add additional trace
statements.
(toplevel): Add prototypes for file-local functions.
(x_atom_to_symbol): Remove DPYINFO parameter.
Diffstat (limited to 'src')
| -rw-r--r-- | src/xselect.c | 249 |
1 files changed, 169 insertions, 80 deletions
diff --git a/src/xselect.c b/src/xselect.c index eae1b0cdb13..91011589bc4 100644 --- a/src/xselect.c +++ b/src/xselect.c | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | /* X Selection processing for Emacs. | 1 | /* X Selection processing for Emacs. |
| 2 | Copyright (C) 1993, 1994, 1995, 1996, 1997, 2000 Free Software Foundation. | 2 | Copyright (C) 1993, 1994, 1995, 1996, 1997, 2000, 2001 |
| 3 | Free Software Foundation. | ||
| 3 | 4 | ||
| 4 | This file is part of GNU Emacs. | 5 | This file is part of GNU Emacs. |
| 5 | 6 | ||
| @@ -33,6 +34,61 @@ Boston, MA 02111-1307, USA. */ | |||
| 33 | #include "process.h" | 34 | #include "process.h" |
| 34 | #include "composite.h" | 35 | #include "composite.h" |
| 35 | 36 | ||
| 37 | struct prop_location; | ||
| 38 | |||
| 39 | static Lisp_Object x_atom_to_symbol P_ ((Display *dpy, Atom atom)); | ||
| 40 | static Atom symbol_to_x_atom P_ ((struct x_display_info *, Display *, | ||
| 41 | Lisp_Object)); | ||
| 42 | static void x_own_selection P_ ((Lisp_Object, Lisp_Object)); | ||
| 43 | static Lisp_Object x_get_local_selection P_ ((Lisp_Object, Lisp_Object)); | ||
| 44 | static void x_decline_selection_request P_ ((struct input_event *)); | ||
| 45 | static Lisp_Object x_selection_request_lisp_error P_ ((Lisp_Object)); | ||
| 46 | static Lisp_Object queue_selection_requests_unwind P_ ((Lisp_Object)); | ||
| 47 | static Lisp_Object some_frame_on_display P_ ((struct x_display_info *)); | ||
| 48 | static void x_reply_selection_request P_ ((struct input_event *, int, | ||
| 49 | unsigned char *, int, Atom)); | ||
| 50 | static int waiting_for_other_props_on_window P_ ((Display *, Window)); | ||
| 51 | static struct prop_location *expect_property_change P_ ((Display *, Window, | ||
| 52 | Atom, int)); | ||
| 53 | static void unexpect_property_change P_ ((struct prop_location *)); | ||
| 54 | static Lisp_Object wait_for_property_change_unwind P_ ((Lisp_Object)); | ||
| 55 | static void wait_for_property_change P_ ((struct prop_location *)); | ||
| 56 | static Lisp_Object x_get_foreign_selection P_ ((Lisp_Object, Lisp_Object)); | ||
| 57 | static void x_get_window_property P_ ((Display *, Window, Atom, | ||
| 58 | unsigned char **, int *, | ||
| 59 | Atom *, int *, unsigned long *, int)); | ||
| 60 | static void receive_incremental_selection P_ ((Display *, Window, Atom, | ||
| 61 | Lisp_Object, unsigned, | ||
| 62 | unsigned char **, int *, | ||
| 63 | Atom *, int *, unsigned long *)); | ||
| 64 | static Lisp_Object x_get_window_property_as_lisp_data P_ ((Display *, | ||
| 65 | Window, Atom, | ||
| 66 | Lisp_Object, Atom)); | ||
| 67 | static Lisp_Object selection_data_to_lisp_data P_ ((Display *, unsigned char *, | ||
| 68 | int, Atom, int)); | ||
| 69 | static void lisp_data_to_selection_data P_ ((Display *, Lisp_Object, | ||
| 70 | unsigned char **, Atom *, | ||
| 71 | unsigned *, int *, int *)); | ||
| 72 | static Lisp_Object clean_local_selection_data P_ ((Lisp_Object)); | ||
| 73 | static void initialize_cut_buffers P_ ((Display *, Window)); | ||
| 74 | |||
| 75 | |||
| 76 | /* Printing traces to stderr. */ | ||
| 77 | |||
| 78 | #ifdef TRACE_SELECTION | ||
| 79 | #define TRACE0(fmt) \ | ||
| 80 | fprintf (stderr, "%d: " fmt "\n", getpid ()) | ||
| 81 | #define TRACE1(fmt, a0) \ | ||
| 82 | fprintf (stderr, "%d: " fmt "\n", getpid (), a0) | ||
| 83 | #define TRACE2(fmt, a0, a1) \ | ||
| 84 | fprintf (stderr, "%d: " fmt "\n", getpid (), a0, a1) | ||
| 85 | #else | ||
| 86 | #define TRACE0(fmt) (void) 0 | ||
| 87 | #define TRACE1(fmt, a0) (void) 0 | ||
| 88 | #define TRACE2(fmt, a0, a1) (void) 0 | ||
| 89 | #endif | ||
| 90 | |||
| 91 | |||
| 36 | #define CUT_BUFFER_SUPPORT | 92 | #define CUT_BUFFER_SUPPORT |
| 37 | 93 | ||
| 38 | Lisp_Object QPRIMARY, QSECONDARY, QSTRING, QINTEGER, QCLIPBOARD, QTIMESTAMP, | 94 | Lisp_Object QPRIMARY, QSECONDARY, QSTRING, QINTEGER, QCLIPBOARD, QTIMESTAMP, |
| @@ -142,9 +198,7 @@ symbol_to_x_atom (dpyinfo, display, sym) | |||
| 142 | #endif | 198 | #endif |
| 143 | if (!SYMBOLP (sym)) abort (); | 199 | if (!SYMBOLP (sym)) abort (); |
| 144 | 200 | ||
| 145 | #if 0 | 201 | TRACE1 (" XInternAtom %s", (char *) XSYMBOL (sym)->name->data); |
| 146 | fprintf (stderr, " XInternAtom %s\n", (char *) XSYMBOL (sym)->name->data); | ||
| 147 | #endif | ||
| 148 | BLOCK_INPUT; | 202 | BLOCK_INPUT; |
| 149 | val = XInternAtom (display, (char *) XSYMBOL (sym)->name->data, False); | 203 | val = XInternAtom (display, (char *) XSYMBOL (sym)->name->data, False); |
| 150 | UNBLOCK_INPUT; | 204 | UNBLOCK_INPUT; |
| @@ -156,14 +210,17 @@ symbol_to_x_atom (dpyinfo, display, sym) | |||
| 156 | and calls to intern whenever possible. */ | 210 | and calls to intern whenever possible. */ |
| 157 | 211 | ||
| 158 | static Lisp_Object | 212 | static Lisp_Object |
| 159 | x_atom_to_symbol (dpyinfo, display, atom) | 213 | x_atom_to_symbol (dpy, atom) |
| 160 | struct x_display_info *dpyinfo; | 214 | Display *dpy; |
| 161 | Display *display; | ||
| 162 | Atom atom; | 215 | Atom atom; |
| 163 | { | 216 | { |
| 217 | struct x_display_info *dpyinfo; | ||
| 164 | char *str; | 218 | char *str; |
| 165 | Lisp_Object val; | 219 | Lisp_Object val; |
| 166 | if (! atom) return Qnil; | 220 | |
| 221 | if (! atom) | ||
| 222 | return Qnil; | ||
| 223 | |||
| 167 | switch (atom) | 224 | switch (atom) |
| 168 | { | 225 | { |
| 169 | case XA_PRIMARY: | 226 | case XA_PRIMARY: |
| @@ -196,6 +253,7 @@ x_atom_to_symbol (dpyinfo, display, atom) | |||
| 196 | #endif | 253 | #endif |
| 197 | } | 254 | } |
| 198 | 255 | ||
| 256 | dpyinfo = x_display_info_for_display (dpy); | ||
| 199 | if (atom == dpyinfo->Xatom_CLIPBOARD) | 257 | if (atom == dpyinfo->Xatom_CLIPBOARD) |
| 200 | return QCLIPBOARD; | 258 | return QCLIPBOARD; |
| 201 | if (atom == dpyinfo->Xatom_TIMESTAMP) | 259 | if (atom == dpyinfo->Xatom_TIMESTAMP) |
| @@ -218,11 +276,9 @@ x_atom_to_symbol (dpyinfo, display, atom) | |||
| 218 | return QNULL; | 276 | return QNULL; |
| 219 | 277 | ||
| 220 | BLOCK_INPUT; | 278 | BLOCK_INPUT; |
| 221 | str = XGetAtomName (display, atom); | 279 | str = XGetAtomName (dpy, atom); |
| 222 | UNBLOCK_INPUT; | 280 | UNBLOCK_INPUT; |
| 223 | #if 0 | 281 | TRACE1 ("XGetAtomName --> %s", str); |
| 224 | fprintf (stderr, " XGetAtomName --> %s\n", str); | ||
| 225 | #endif | ||
| 226 | if (! str) return Qnil; | 282 | if (! str) return Qnil; |
| 227 | val = intern (str); | 283 | val = intern (str); |
| 228 | BLOCK_INPUT; | 284 | BLOCK_INPUT; |
| @@ -411,6 +467,8 @@ x_decline_selection_request (event) | |||
| 411 | struct input_event *event; | 467 | struct input_event *event; |
| 412 | { | 468 | { |
| 413 | XSelectionEvent reply; | 469 | XSelectionEvent reply; |
| 470 | int count; | ||
| 471 | |||
| 414 | reply.type = SelectionNotify; | 472 | reply.type = SelectionNotify; |
| 415 | reply.display = SELECTION_EVENT_DISPLAY (event); | 473 | reply.display = SELECTION_EVENT_DISPLAY (event); |
| 416 | reply.requestor = SELECTION_EVENT_REQUESTOR (event); | 474 | reply.requestor = SELECTION_EVENT_REQUESTOR (event); |
| @@ -419,10 +477,13 @@ x_decline_selection_request (event) | |||
| 419 | reply.target = SELECTION_EVENT_TARGET (event); | 477 | reply.target = SELECTION_EVENT_TARGET (event); |
| 420 | reply.property = None; | 478 | reply.property = None; |
| 421 | 479 | ||
| 480 | /* The reason for the error may be that the receiver has | ||
| 481 | died in the meantime. Handle that case. */ | ||
| 422 | BLOCK_INPUT; | 482 | BLOCK_INPUT; |
| 423 | XSendEvent (reply.display, reply.requestor, False, 0L, | 483 | count = x_catch_errors (reply.display); |
| 424 | (XEvent *) &reply); | 484 | XSendEvent (reply.display, reply.requestor, False, 0L, (XEvent *) &reply); |
| 425 | XFlush (reply.display); | 485 | XFlush (reply.display); |
| 486 | x_uncatch_errors (reply.display, count); | ||
| 426 | UNBLOCK_INPUT; | 487 | UNBLOCK_INPUT; |
| 427 | } | 488 | } |
| 428 | 489 | ||
| @@ -553,9 +614,7 @@ x_reply_selection_request (event, format, data, size, type) | |||
| 553 | if (bytes_remaining <= max_bytes) | 614 | if (bytes_remaining <= max_bytes) |
| 554 | { | 615 | { |
| 555 | /* Send all the data at once, with minimal handshaking. */ | 616 | /* Send all the data at once, with minimal handshaking. */ |
| 556 | #if 0 | 617 | TRACE1 ("Sending all %d bytes", bytes_remaining); |
| 557 | fprintf (stderr,"\nStoring all %d\n", bytes_remaining); | ||
| 558 | #endif | ||
| 559 | XChangeProperty (display, window, reply.property, type, format, | 618 | XChangeProperty (display, window, reply.property, type, format, |
| 560 | PropModeReplace, data, size); | 619 | PropModeReplace, data, size); |
| 561 | /* At this point, the selection was successfully stored; ack it. */ | 620 | /* At this point, the selection was successfully stored; ack it. */ |
| @@ -583,17 +642,21 @@ x_reply_selection_request (event, format, data, size, type) | |||
| 583 | 642 | ||
| 584 | if (x_window_to_frame (dpyinfo, window)) /* #### debug */ | 643 | if (x_window_to_frame (dpyinfo, window)) /* #### debug */ |
| 585 | error ("Attempt to transfer an INCR to ourself!"); | 644 | error ("Attempt to transfer an INCR to ourself!"); |
| 586 | #if 0 | 645 | |
| 587 | fprintf (stderr, "\nINCR %d\n", bytes_remaining); | 646 | TRACE2 ("Start sending %d bytes incrementally (%s)", |
| 588 | #endif | 647 | bytes_remaining, XGetAtomName (display, reply.property)); |
| 589 | wait_object = expect_property_change (display, window, reply.property, | 648 | wait_object = expect_property_change (display, window, reply.property, |
| 590 | PropertyDelete); | 649 | PropertyDelete); |
| 591 | 650 | ||
| 651 | TRACE1 ("Set %s to number of bytes to send", | ||
| 652 | XGetAtomName (display, reply.property)); | ||
| 592 | XChangeProperty (display, window, reply.property, dpyinfo->Xatom_INCR, | 653 | XChangeProperty (display, window, reply.property, dpyinfo->Xatom_INCR, |
| 593 | 32, PropModeReplace, | 654 | 32, PropModeReplace, |
| 594 | (unsigned char *) &bytes_remaining, 1); | 655 | (unsigned char *) &bytes_remaining, 1); |
| 595 | XSelectInput (display, window, PropertyChangeMask); | 656 | XSelectInput (display, window, PropertyChangeMask); |
| 657 | |||
| 596 | /* Tell 'em the INCR data is there... */ | 658 | /* Tell 'em the INCR data is there... */ |
| 659 | TRACE0 ("Send SelectionNotify event"); | ||
| 597 | XSendEvent (display, window, False, 0L, (XEvent *) &reply); | 660 | XSendEvent (display, window, False, 0L, (XEvent *) &reply); |
| 598 | XFlush (display); | 661 | XFlush (display); |
| 599 | 662 | ||
| @@ -603,8 +666,13 @@ x_reply_selection_request (event, format, data, size, type) | |||
| 603 | /* First, wait for the requester to ack by deleting the property. | 666 | /* First, wait for the requester to ack by deleting the property. |
| 604 | This can run random lisp code (process handlers) or signal. */ | 667 | This can run random lisp code (process handlers) or signal. */ |
| 605 | if (! had_errors) | 668 | if (! had_errors) |
| 606 | wait_for_property_change (wait_object); | 669 | { |
| 670 | TRACE1 ("Waiting for ACK (deletion of %s)", | ||
| 671 | XGetAtomName (display, reply.property)); | ||
| 672 | wait_for_property_change (wait_object); | ||
| 673 | } | ||
| 607 | 674 | ||
| 675 | TRACE0 ("Got ACK"); | ||
| 608 | while (bytes_remaining) | 676 | while (bytes_remaining) |
| 609 | { | 677 | { |
| 610 | int i = ((bytes_remaining < max_bytes) | 678 | int i = ((bytes_remaining < max_bytes) |
| @@ -616,9 +684,11 @@ x_reply_selection_request (event, format, data, size, type) | |||
| 616 | wait_object | 684 | wait_object |
| 617 | = expect_property_change (display, window, reply.property, | 685 | = expect_property_change (display, window, reply.property, |
| 618 | PropertyDelete); | 686 | PropertyDelete); |
| 619 | #if 0 | 687 | |
| 620 | fprintf (stderr," INCR adding %d\n", i); | 688 | TRACE1 ("Sending increment of %d bytes", i); |
| 621 | #endif | 689 | TRACE1 ("Set %s to increment data", |
| 690 | XGetAtomName (display, reply.property)); | ||
| 691 | |||
| 622 | /* Append the next chunk of data to the property. */ | 692 | /* Append the next chunk of data to the property. */ |
| 623 | XChangeProperty (display, window, reply.property, type, format, | 693 | XChangeProperty (display, window, reply.property, type, format, |
| 624 | PropModeAppend, data, i / format_bytes); | 694 | PropModeAppend, data, i / format_bytes); |
| @@ -632,21 +702,23 @@ x_reply_selection_request (event, format, data, size, type) | |||
| 632 | break; | 702 | break; |
| 633 | 703 | ||
| 634 | /* Now wait for the requester to ack this chunk by deleting the | 704 | /* Now wait for the requester to ack this chunk by deleting the |
| 635 | property. This can run random lisp code or signal. | 705 | property. This can run random lisp code or signal. */ |
| 636 | */ | 706 | TRACE1 ("Waiting for increment ACK (deletion of %s)", |
| 707 | XGetAtomName (display, reply.property)); | ||
| 637 | wait_for_property_change (wait_object); | 708 | wait_for_property_change (wait_object); |
| 638 | } | 709 | } |
| 639 | /* Now write a zero-length chunk to the property to tell the requester | 710 | |
| 640 | that we're done. */ | 711 | /* Now write a zero-length chunk to the property to tell the |
| 641 | #if 0 | 712 | requester that we're done. */ |
| 642 | fprintf (stderr," INCR done\n"); | ||
| 643 | #endif | ||
| 644 | BLOCK_INPUT; | 713 | BLOCK_INPUT; |
| 645 | if (! waiting_for_other_props_on_window (display, window)) | 714 | if (! waiting_for_other_props_on_window (display, window)) |
| 646 | XSelectInput (display, window, 0L); | 715 | XSelectInput (display, window, 0L); |
| 647 | 716 | ||
| 717 | TRACE1 ("Set %s to a 0-length chunk to indicate EOF", | ||
| 718 | XGetAtomName (display, reply.property)); | ||
| 648 | XChangeProperty (display, window, reply.property, type, format, | 719 | XChangeProperty (display, window, reply.property, type, format, |
| 649 | PropModeReplace, data, 0); | 720 | PropModeReplace, data, 0); |
| 721 | TRACE0 ("Done sending incrementally"); | ||
| 650 | } | 722 | } |
| 651 | 723 | ||
| 652 | /* The window we're communicating with may have been deleted | 724 | /* The window we're communicating with may have been deleted |
| @@ -685,8 +757,7 @@ x_handle_selection_request (event) | |||
| 685 | 757 | ||
| 686 | GCPRO3 (local_selection_data, converted_selection, target_symbol); | 758 | GCPRO3 (local_selection_data, converted_selection, target_symbol); |
| 687 | 759 | ||
| 688 | selection_symbol = x_atom_to_symbol (dpyinfo, | 760 | selection_symbol = x_atom_to_symbol (SELECTION_EVENT_DISPLAY (event), |
| 689 | SELECTION_EVENT_DISPLAY (event), | ||
| 690 | SELECTION_EVENT_SELECTION (event)); | 761 | SELECTION_EVENT_SELECTION (event)); |
| 691 | 762 | ||
| 692 | local_selection_data = assq_no_quit (selection_symbol, Vselection_alist); | 763 | local_selection_data = assq_no_quit (selection_symbol, Vselection_alist); |
| @@ -717,7 +788,7 @@ x_handle_selection_request (event) | |||
| 717 | selection_request_dpyinfo = dpyinfo; | 788 | selection_request_dpyinfo = dpyinfo; |
| 718 | record_unwind_protect (x_selection_request_lisp_error, Qnil); | 789 | record_unwind_protect (x_selection_request_lisp_error, Qnil); |
| 719 | 790 | ||
| 720 | target_symbol = x_atom_to_symbol (dpyinfo, SELECTION_EVENT_DISPLAY (event), | 791 | target_symbol = x_atom_to_symbol (SELECTION_EVENT_DISPLAY (event), |
| 721 | SELECTION_EVENT_TARGET (event)); | 792 | SELECTION_EVENT_TARGET (event)); |
| 722 | 793 | ||
| 723 | #if 0 /* #### MULTIPLE doesn't work yet */ | 794 | #if 0 /* #### MULTIPLE doesn't work yet */ |
| @@ -805,7 +876,7 @@ x_handle_selection_clear (event) | |||
| 805 | } | 876 | } |
| 806 | UNBLOCK_INPUT; | 877 | UNBLOCK_INPUT; |
| 807 | 878 | ||
| 808 | selection_symbol = x_atom_to_symbol (dpyinfo, display, selection); | 879 | selection_symbol = x_atom_to_symbol (display, selection); |
| 809 | 880 | ||
| 810 | local_selection_data = assq_no_quit (selection_symbol, Vselection_alist); | 881 | local_selection_data = assq_no_quit (selection_symbol, Vselection_alist); |
| 811 | 882 | ||
| @@ -945,8 +1016,7 @@ expect_property_change (display, window, property, state) | |||
| 945 | Atom property; | 1016 | Atom property; |
| 946 | int state; | 1017 | int state; |
| 947 | { | 1018 | { |
| 948 | struct prop_location *pl | 1019 | struct prop_location *pl = (struct prop_location *) xmalloc (sizeof *pl); |
| 949 | = (struct prop_location *) xmalloc (sizeof (struct prop_location)); | ||
| 950 | pl->identifier = ++prop_location_identifier; | 1020 | pl->identifier = ++prop_location_identifier; |
| 951 | pl->display = display; | 1021 | pl->display = display; |
| 952 | pl->window = window; | 1022 | pl->window = window; |
| @@ -1021,10 +1091,14 @@ wait_for_property_change (location) | |||
| 1021 | { | 1091 | { |
| 1022 | secs = x_selection_timeout / 1000; | 1092 | secs = x_selection_timeout / 1000; |
| 1023 | usecs = (x_selection_timeout % 1000) * 1000; | 1093 | usecs = (x_selection_timeout % 1000) * 1000; |
| 1094 | TRACE2 (" Waiting %d secs, %d usecs", secs, usecs); | ||
| 1024 | wait_reading_process_input (secs, usecs, property_change_reply, 0); | 1095 | wait_reading_process_input (secs, usecs, property_change_reply, 0); |
| 1025 | 1096 | ||
| 1026 | if (NILP (XCAR (property_change_reply))) | 1097 | if (NILP (XCAR (property_change_reply))) |
| 1027 | error ("Timed out waiting for property-notify event"); | 1098 | { |
| 1099 | TRACE0 (" Timed out"); | ||
| 1100 | error ("Timed out waiting for property-notify event"); | ||
| 1101 | } | ||
| 1028 | } | 1102 | } |
| 1029 | 1103 | ||
| 1030 | unbind_to (count, Qnil); | 1104 | unbind_to (count, Qnil); |
| @@ -1037,6 +1111,7 @@ x_handle_property_notify (event) | |||
| 1037 | XPropertyEvent *event; | 1111 | XPropertyEvent *event; |
| 1038 | { | 1112 | { |
| 1039 | struct prop_location *prev = 0, *rest = property_change_wait_list; | 1113 | struct prop_location *prev = 0, *rest = property_change_wait_list; |
| 1114 | |||
| 1040 | while (rest) | 1115 | while (rest) |
| 1041 | { | 1116 | { |
| 1042 | if (rest->property == event->atom | 1117 | if (rest->property == event->atom |
| @@ -1044,13 +1119,9 @@ x_handle_property_notify (event) | |||
| 1044 | && rest->display == event->display | 1119 | && rest->display == event->display |
| 1045 | && rest->desired_state == event->state) | 1120 | && rest->desired_state == event->state) |
| 1046 | { | 1121 | { |
| 1047 | #if 0 | 1122 | TRACE2 ("Expected %s of property %s", |
| 1048 | fprintf (stderr, "Saw expected prop-%s on %s\n", | 1123 | (event->state == PropertyDelete ? "deletion" : "change"), |
| 1049 | (event->state == PropertyDelete ? "delete" : "change"), | 1124 | XGetAtomName (event->display, event->atom)); |
| 1050 | (char *) XSYMBOL (x_atom_to_symbol (dpyinfo, event->display, | ||
| 1051 | event->atom)) | ||
| 1052 | ->name->data); | ||
| 1053 | #endif | ||
| 1054 | 1125 | ||
| 1055 | rest->arrived = 1; | 1126 | rest->arrived = 1; |
| 1056 | 1127 | ||
| @@ -1066,16 +1137,10 @@ x_handle_property_notify (event) | |||
| 1066 | xfree (rest); | 1137 | xfree (rest); |
| 1067 | return; | 1138 | return; |
| 1068 | } | 1139 | } |
| 1140 | |||
| 1069 | prev = rest; | 1141 | prev = rest; |
| 1070 | rest = rest->next; | 1142 | rest = rest->next; |
| 1071 | } | 1143 | } |
| 1072 | #if 0 | ||
| 1073 | fprintf (stderr, "Saw UNexpected prop-%s on %s\n", | ||
| 1074 | (event->state == PropertyDelete ? "delete" : "change"), | ||
| 1075 | (char *) XSYMBOL (x_atom_to_symbol (dpyinfo, | ||
| 1076 | event->display, event->atom)) | ||
| 1077 | ->name->data); | ||
| 1078 | #endif | ||
| 1079 | } | 1144 | } |
| 1080 | 1145 | ||
| 1081 | 1146 | ||
| @@ -1160,7 +1225,13 @@ x_get_foreign_selection (selection_symbol, target_type) | |||
| 1160 | type_atom = symbol_to_x_atom (dpyinfo, display, target_type); | 1225 | type_atom = symbol_to_x_atom (dpyinfo, display, target_type); |
| 1161 | 1226 | ||
| 1162 | BLOCK_INPUT; | 1227 | BLOCK_INPUT; |
| 1228 | |||
| 1163 | count = x_catch_errors (display); | 1229 | count = x_catch_errors (display); |
| 1230 | |||
| 1231 | TRACE2 ("Get selection %s, type %s", | ||
| 1232 | XGetAtomName (display, type_atom), | ||
| 1233 | XGetAtomName (display, target_property)); | ||
| 1234 | |||
| 1164 | XConvertSelection (display, selection_atom, type_atom, target_property, | 1235 | XConvertSelection (display, selection_atom, type_atom, target_property, |
| 1165 | requestor_window, requestor_time); | 1236 | requestor_window, requestor_time); |
| 1166 | XFlush (display); | 1237 | XFlush (display); |
| @@ -1187,7 +1258,9 @@ x_get_foreign_selection (selection_symbol, target_type) | |||
| 1187 | /* This allows quits. Also, don't wait forever. */ | 1258 | /* This allows quits. Also, don't wait forever. */ |
| 1188 | secs = x_selection_timeout / 1000; | 1259 | secs = x_selection_timeout / 1000; |
| 1189 | usecs = (x_selection_timeout % 1000) * 1000; | 1260 | usecs = (x_selection_timeout % 1000) * 1000; |
| 1261 | TRACE1 (" Start waiting %d secs for SelectionNotify", secs); | ||
| 1190 | wait_reading_process_input (secs, usecs, reading_selection_reply, 0); | 1262 | wait_reading_process_input (secs, usecs, reading_selection_reply, 0); |
| 1263 | TRACE1 (" Got event = %d", !NILP (XCAR (reading_selection_reply))); | ||
| 1191 | 1264 | ||
| 1192 | BLOCK_INPUT; | 1265 | BLOCK_INPUT; |
| 1193 | x_check_errors (display, "Cannot get selection: %s"); | 1266 | x_check_errors (display, "Cannot get selection: %s"); |
| @@ -1230,9 +1303,12 @@ x_get_window_property (display, window, property, data_ret, bytes_ret, | |||
| 1230 | unsigned char *tmp_data = 0; | 1303 | unsigned char *tmp_data = 0; |
| 1231 | int result; | 1304 | int result; |
| 1232 | int buffer_size = SELECTION_QUANTUM (display); | 1305 | int buffer_size = SELECTION_QUANTUM (display); |
| 1233 | if (buffer_size > MAX_SELECTION_QUANTUM) buffer_size = MAX_SELECTION_QUANTUM; | 1306 | |
| 1307 | if (buffer_size > MAX_SELECTION_QUANTUM) | ||
| 1308 | buffer_size = MAX_SELECTION_QUANTUM; | ||
| 1234 | 1309 | ||
| 1235 | BLOCK_INPUT; | 1310 | BLOCK_INPUT; |
| 1311 | |||
| 1236 | /* First probe the thing to find out how big it is. */ | 1312 | /* First probe the thing to find out how big it is. */ |
| 1237 | result = XGetWindowProperty (display, window, property, | 1313 | result = XGetWindowProperty (display, window, property, |
| 1238 | 0L, 0L, False, AnyPropertyType, | 1314 | 0L, 0L, False, AnyPropertyType, |
| @@ -1246,6 +1322,7 @@ x_get_window_property (display, window, property, data_ret, bytes_ret, | |||
| 1246 | *bytes_ret = 0; | 1322 | *bytes_ret = 0; |
| 1247 | return; | 1323 | return; |
| 1248 | } | 1324 | } |
| 1325 | |||
| 1249 | /* This was allocated by Xlib, so use XFree. */ | 1326 | /* This was allocated by Xlib, so use XFree. */ |
| 1250 | XFree ((char *) tmp_data); | 1327 | XFree ((char *) tmp_data); |
| 1251 | 1328 | ||
| @@ -1261,7 +1338,7 @@ x_get_window_property (display, window, property, data_ret, bytes_ret, | |||
| 1261 | /* Now read, until we've gotten it all. */ | 1338 | /* Now read, until we've gotten it all. */ |
| 1262 | while (bytes_remaining) | 1339 | while (bytes_remaining) |
| 1263 | { | 1340 | { |
| 1264 | #if 0 | 1341 | #ifdef TRACE_SELECTION |
| 1265 | int last = bytes_remaining; | 1342 | int last = bytes_remaining; |
| 1266 | #endif | 1343 | #endif |
| 1267 | result | 1344 | result |
| @@ -1271,17 +1348,20 @@ x_get_window_property (display, window, property, data_ret, bytes_ret, | |||
| 1271 | AnyPropertyType, | 1348 | AnyPropertyType, |
| 1272 | actual_type_ret, actual_format_ret, | 1349 | actual_type_ret, actual_format_ret, |
| 1273 | actual_size_ret, &bytes_remaining, &tmp_data); | 1350 | actual_size_ret, &bytes_remaining, &tmp_data); |
| 1274 | #if 0 | 1351 | |
| 1275 | fprintf (stderr, "<< read %d\n", last-bytes_remaining); | 1352 | TRACE2 ("Read %ld bytes from property %s", |
| 1276 | #endif | 1353 | last - bytes_remaining, |
| 1354 | XGetAtomName (display, property)); | ||
| 1355 | |||
| 1277 | /* If this doesn't return Success at this point, it means that | 1356 | /* If this doesn't return Success at this point, it means that |
| 1278 | some clod deleted the selection while we were in the midst of | 1357 | some clod deleted the selection while we were in the midst of |
| 1279 | reading it. Deal with that, I guess.... | 1358 | reading it. Deal with that, I guess.... */ |
| 1280 | */ | 1359 | if (result != Success) |
| 1281 | if (result != Success) break; | 1360 | break; |
| 1282 | *actual_size_ret *= *actual_format_ret / 8; | 1361 | *actual_size_ret *= *actual_format_ret / 8; |
| 1283 | bcopy (tmp_data, (*data_ret) + offset, *actual_size_ret); | 1362 | bcopy (tmp_data, (*data_ret) + offset, *actual_size_ret); |
| 1284 | offset += *actual_size_ret; | 1363 | offset += *actual_size_ret; |
| 1364 | |||
| 1285 | /* This was allocated by Xlib, so use XFree. */ | 1365 | /* This was allocated by Xlib, so use XFree. */ |
| 1286 | XFree ((char *) tmp_data); | 1366 | XFree ((char *) tmp_data); |
| 1287 | } | 1367 | } |
| @@ -1312,9 +1392,8 @@ receive_incremental_selection (display, window, property, target_type, | |||
| 1312 | struct prop_location *wait_object; | 1392 | struct prop_location *wait_object; |
| 1313 | *size_bytes_ret = min_size_bytes; | 1393 | *size_bytes_ret = min_size_bytes; |
| 1314 | *data_ret = (unsigned char *) xmalloc (*size_bytes_ret); | 1394 | *data_ret = (unsigned char *) xmalloc (*size_bytes_ret); |
| 1315 | #if 0 | 1395 | |
| 1316 | fprintf (stderr, "\nread INCR %d\n", min_size_bytes); | 1396 | TRACE1 ("Read %d bytes incrementally", min_size_bytes); |
| 1317 | #endif | ||
| 1318 | 1397 | ||
| 1319 | /* At this point, we have read an INCR property. | 1398 | /* At this point, we have read an INCR property. |
| 1320 | Delete the property to ack it. | 1399 | Delete the property to ack it. |
| @@ -1326,7 +1405,11 @@ receive_incremental_selection (display, window, property, target_type, | |||
| 1326 | */ | 1405 | */ |
| 1327 | BLOCK_INPUT; | 1406 | BLOCK_INPUT; |
| 1328 | XSelectInput (display, window, STANDARD_EVENT_SET | PropertyChangeMask); | 1407 | XSelectInput (display, window, STANDARD_EVENT_SET | PropertyChangeMask); |
| 1408 | TRACE1 (" Delete property %s", | ||
| 1409 | XSYMBOL (x_atom_to_symbol (display, property))->name->data); | ||
| 1329 | XDeleteProperty (display, window, property); | 1410 | XDeleteProperty (display, window, property); |
| 1411 | TRACE1 (" Expect new value of property %s", | ||
| 1412 | XSYMBOL (x_atom_to_symbol (display, property))->name->data); | ||
| 1330 | wait_object = expect_property_change (display, window, property, | 1413 | wait_object = expect_property_change (display, window, property, |
| 1331 | PropertyNewValue); | 1414 | PropertyNewValue); |
| 1332 | XFlush (display); | 1415 | XFlush (display); |
| @@ -1336,20 +1419,24 @@ receive_incremental_selection (display, window, property, target_type, | |||
| 1336 | { | 1419 | { |
| 1337 | unsigned char *tmp_data; | 1420 | unsigned char *tmp_data; |
| 1338 | int tmp_size_bytes; | 1421 | int tmp_size_bytes; |
| 1422 | |||
| 1423 | TRACE0 (" Wait for property change"); | ||
| 1339 | wait_for_property_change (wait_object); | 1424 | wait_for_property_change (wait_object); |
| 1425 | |||
| 1340 | /* expect it again immediately, because x_get_window_property may | 1426 | /* expect it again immediately, because x_get_window_property may |
| 1341 | .. no it won't, I don't get it. | 1427 | .. no it won't, I don't get it. |
| 1342 | .. Ok, I get it now, the Xt code that implements INCR is broken. | 1428 | .. Ok, I get it now, the Xt code that implements INCR is broken. */ |
| 1343 | */ | 1429 | TRACE0 (" Get property value"); |
| 1344 | x_get_window_property (display, window, property, | 1430 | x_get_window_property (display, window, property, |
| 1345 | &tmp_data, &tmp_size_bytes, | 1431 | &tmp_data, &tmp_size_bytes, |
| 1346 | type_ret, format_ret, size_ret, 1); | 1432 | type_ret, format_ret, size_ret, 1); |
| 1347 | 1433 | ||
| 1434 | TRACE1 (" Read increment of %d bytes", tmp_size_bytes); | ||
| 1435 | |||
| 1348 | if (tmp_size_bytes == 0) /* we're done */ | 1436 | if (tmp_size_bytes == 0) /* we're done */ |
| 1349 | { | 1437 | { |
| 1350 | #if 0 | 1438 | TRACE0 ("Done reading incrementally"); |
| 1351 | fprintf (stderr, " read INCR done\n"); | 1439 | |
| 1352 | #endif | ||
| 1353 | if (! waiting_for_other_props_on_window (display, window)) | 1440 | if (! waiting_for_other_props_on_window (display, window)) |
| 1354 | XSelectInput (display, window, STANDARD_EVENT_SET); | 1441 | XSelectInput (display, window, STANDARD_EVENT_SET); |
| 1355 | unexpect_property_change (wait_object); | 1442 | unexpect_property_change (wait_object); |
| @@ -1360,31 +1447,29 @@ receive_incremental_selection (display, window, property, target_type, | |||
| 1360 | } | 1447 | } |
| 1361 | 1448 | ||
| 1362 | BLOCK_INPUT; | 1449 | BLOCK_INPUT; |
| 1450 | TRACE1 (" ACK by deleting property %s", | ||
| 1451 | XGetAtomName (display, property)); | ||
| 1363 | XDeleteProperty (display, window, property); | 1452 | XDeleteProperty (display, window, property); |
| 1364 | wait_object = expect_property_change (display, window, property, | 1453 | wait_object = expect_property_change (display, window, property, |
| 1365 | PropertyNewValue); | 1454 | PropertyNewValue); |
| 1366 | XFlush (display); | 1455 | XFlush (display); |
| 1367 | UNBLOCK_INPUT; | 1456 | UNBLOCK_INPUT; |
| 1368 | 1457 | ||
| 1369 | #if 0 | ||
| 1370 | fprintf (stderr, " read INCR %d\n", tmp_size_bytes); | ||
| 1371 | #endif | ||
| 1372 | if (*size_bytes_ret < offset + tmp_size_bytes) | 1458 | if (*size_bytes_ret < offset + tmp_size_bytes) |
| 1373 | { | 1459 | { |
| 1374 | #if 0 | ||
| 1375 | fprintf (stderr, " read INCR realloc %d -> %d\n", | ||
| 1376 | *size_bytes_ret, offset + tmp_size_bytes); | ||
| 1377 | #endif | ||
| 1378 | *size_bytes_ret = offset + tmp_size_bytes; | 1460 | *size_bytes_ret = offset + tmp_size_bytes; |
| 1379 | *data_ret = (unsigned char *) xrealloc (*data_ret, *size_bytes_ret); | 1461 | *data_ret = (unsigned char *) xrealloc (*data_ret, *size_bytes_ret); |
| 1380 | } | 1462 | } |
| 1463 | |||
| 1381 | bcopy (tmp_data, (*data_ret) + offset, tmp_size_bytes); | 1464 | bcopy (tmp_data, (*data_ret) + offset, tmp_size_bytes); |
| 1382 | offset += tmp_size_bytes; | 1465 | offset += tmp_size_bytes; |
| 1466 | |||
| 1383 | /* Use xfree, not XFree, because x_get_window_property | 1467 | /* Use xfree, not XFree, because x_get_window_property |
| 1384 | calls xmalloc itself. */ | 1468 | calls xmalloc itself. */ |
| 1385 | xfree (tmp_data); | 1469 | xfree (tmp_data); |
| 1386 | } | 1470 | } |
| 1387 | } | 1471 | } |
| 1472 | |||
| 1388 | 1473 | ||
| 1389 | /* Once a requested selection is "ready" (we got a SelectionNotify event), | 1474 | /* Once a requested selection is "ready" (we got a SelectionNotify event), |
| 1390 | fetch value from property PROPERTY of X window WINDOW on display DISPLAY. | 1475 | fetch value from property PROPERTY of X window WINDOW on display DISPLAY. |
| @@ -1407,6 +1492,8 @@ x_get_window_property_as_lisp_data (display, window, property, target_type, | |||
| 1407 | Lisp_Object val; | 1492 | Lisp_Object val; |
| 1408 | struct x_display_info *dpyinfo = x_display_info_for_display (display); | 1493 | struct x_display_info *dpyinfo = x_display_info_for_display (display); |
| 1409 | 1494 | ||
| 1495 | TRACE0 ("Reading selection data"); | ||
| 1496 | |||
| 1410 | x_get_window_property (display, window, property, &data, &bytes, | 1497 | x_get_window_property (display, window, property, &data, &bytes, |
| 1411 | &actual_type, &actual_format, &actual_size, 1); | 1498 | &actual_type, &actual_format, &actual_size, 1); |
| 1412 | if (! data) | 1499 | if (! data) |
| @@ -1421,12 +1508,12 @@ x_get_window_property_as_lisp_data (display, window, property, target_type, | |||
| 1421 | ? Fcons (build_string ("selection owner couldn't convert"), | 1508 | ? Fcons (build_string ("selection owner couldn't convert"), |
| 1422 | actual_type | 1509 | actual_type |
| 1423 | ? Fcons (target_type, | 1510 | ? Fcons (target_type, |
| 1424 | Fcons (x_atom_to_symbol (dpyinfo, display, | 1511 | Fcons (x_atom_to_symbol (display, |
| 1425 | actual_type), | 1512 | actual_type), |
| 1426 | Qnil)) | 1513 | Qnil)) |
| 1427 | : Fcons (target_type, Qnil)) | 1514 | : Fcons (target_type, Qnil)) |
| 1428 | : Fcons (build_string ("no selection"), | 1515 | : Fcons (build_string ("no selection"), |
| 1429 | Fcons (x_atom_to_symbol (dpyinfo, display, | 1516 | Fcons (x_atom_to_symbol (display, |
| 1430 | selection_atom), | 1517 | selection_atom), |
| 1431 | Qnil))); | 1518 | Qnil))); |
| 1432 | } | 1519 | } |
| @@ -1448,6 +1535,7 @@ x_get_window_property_as_lisp_data (display, window, property, target_type, | |||
| 1448 | } | 1535 | } |
| 1449 | 1536 | ||
| 1450 | BLOCK_INPUT; | 1537 | BLOCK_INPUT; |
| 1538 | TRACE1 (" Delete property %s", XGetAtomName (display, property)); | ||
| 1451 | XDeleteProperty (display, window, property); | 1539 | XDeleteProperty (display, window, property); |
| 1452 | XFlush (display); | 1540 | XFlush (display); |
| 1453 | UNBLOCK_INPUT; | 1541 | UNBLOCK_INPUT; |
| @@ -1574,14 +1662,14 @@ selection_data_to_lisp_data (display, data, size, type, format) | |||
| 1574 | { | 1662 | { |
| 1575 | int i; | 1663 | int i; |
| 1576 | if (size == sizeof (Atom)) | 1664 | if (size == sizeof (Atom)) |
| 1577 | return x_atom_to_symbol (dpyinfo, display, *((Atom *) data)); | 1665 | return x_atom_to_symbol (display, *((Atom *) data)); |
| 1578 | else | 1666 | else |
| 1579 | { | 1667 | { |
| 1580 | Lisp_Object v = Fmake_vector (make_number (size / sizeof (Atom)), | 1668 | Lisp_Object v = Fmake_vector (make_number (size / sizeof (Atom)), |
| 1581 | make_number (0)); | 1669 | make_number (0)); |
| 1582 | for (i = 0; i < size / sizeof (Atom); i++) | 1670 | for (i = 0; i < size / sizeof (Atom); i++) |
| 1583 | Faset (v, make_number (i), | 1671 | Faset (v, make_number (i), |
| 1584 | x_atom_to_symbol (dpyinfo, display, ((Atom *) data) [i])); | 1672 | x_atom_to_symbol (display, ((Atom *) data) [i])); |
| 1585 | return v; | 1673 | return v; |
| 1586 | } | 1674 | } |
| 1587 | } | 1675 | } |
| @@ -1853,6 +1941,7 @@ x_handle_selection_notify (event) | |||
| 1853 | if (event->selection != reading_which_selection) | 1941 | if (event->selection != reading_which_selection) |
| 1854 | return; | 1942 | return; |
| 1855 | 1943 | ||
| 1944 | TRACE0 ("Received SelectionNotify"); | ||
| 1856 | XCAR (reading_selection_reply) | 1945 | XCAR (reading_selection_reply) |
| 1857 | = (event->property != 0 ? Qt : Qlambda); | 1946 | = (event->property != 0 ? Qt : Qlambda); |
| 1858 | } | 1947 | } |
| @@ -2121,7 +2210,7 @@ DEFUN ("x-get-cut-buffer-internal", Fx_get_cut_buffer_internal, | |||
| 2121 | if (format != 8 || type != XA_STRING) | 2210 | if (format != 8 || type != XA_STRING) |
| 2122 | Fsignal (Qerror, | 2211 | Fsignal (Qerror, |
| 2123 | Fcons (build_string ("cut buffer doesn't contain 8-bit data"), | 2212 | Fcons (build_string ("cut buffer doesn't contain 8-bit data"), |
| 2124 | Fcons (x_atom_to_symbol (dpyinfo, display, type), | 2213 | Fcons (x_atom_to_symbol (display, type), |
| 2125 | Fcons (make_number (format), Qnil)))); | 2214 | Fcons (make_number (format), Qnil)))); |
| 2126 | 2215 | ||
| 2127 | ret = (bytes ? make_string ((char *) data, bytes) : Qnil); | 2216 | ret = (bytes ? make_string ((char *) data, bytes) : Qnil); |