diff options
| author | Po Lu | 2022-06-06 11:08:19 +0800 |
|---|---|---|
| committer | Po Lu | 2022-06-06 11:08:19 +0800 |
| commit | b90d2a6a63f1b7f73d2cb7e976148e8195fc5502 (patch) | |
| tree | 965057d58b783e920711e05138ad56184ceec6c4 | |
| parent | 0a36671f415bd681ddca0bad8612aca031fd407d (diff) | |
| download | emacs-b90d2a6a63f1b7f73d2cb7e976148e8195fc5502.tar.gz emacs-b90d2a6a63f1b7f73d2cb7e976148e8195fc5502.zip | |
Rework X selections to make it safe to run the debugger inside converters
* src/keyboard.c (prev_kbd_event): Delete function.
(readable_events): Return 1 if
x_detect_pending_selection_requests returns true.
(kbd_buffer_unget_event): Also delete function, since nested
selection requests are really handled correctly.
(kbd_buffer_get_event): Handle events from the special X
deferred selection queue as well.
* src/keyboard.h: Update prototypes.
* src/xselect.c (struct selection_event_queue)
(selection_input_event_equal, x_queue_event)
(x_start_queuing_selection_requests)
(x_stop_queuing_selection_requests): Delete structs, since they
are no longer required.
(x_handle_selection_request, x_handle_selection_event): Allow
nested selection events.
* src/xterm.c (struct x_selection_request_event): New struct.
(x_handle_pending_selection_requests_1)
(x_handle_pending_selection_requests): Handle all events in the
new selection event queue.
(x_push_selection_request, x_detect_pending_selection_requests):
New functions.
(x_dnd_begin_drag_and_drop): Drain the selection queue here as
well.
(handle_one_xevent): When inside a nested event loop, just push
selections to that queue.
(XTread_socket): Allow reading X events if x_dnd_unwind_flag is
true, even though DND is in progress.
(x_delete_display): Delete pending selection events for the
display that is going away.
* src/xterm.h: Update prototypes.
| -rw-r--r-- | src/keyboard.c | 64 | ||||
| -rw-r--r-- | src/keyboard.h | 3 | ||||
| -rw-r--r-- | src/xselect.c | 93 | ||||
| -rw-r--r-- | src/xterm.c | 163 | ||||
| -rw-r--r-- | src/xterm.h | 2 |
5 files changed, 163 insertions, 162 deletions
diff --git a/src/keyboard.c b/src/keyboard.c index 274c7b3fa84..55d710ed627 100644 --- a/src/keyboard.c +++ b/src/keyboard.c | |||
| @@ -389,14 +389,6 @@ next_kbd_event (union buffered_input_event *ptr) | |||
| 389 | return ptr == kbd_buffer + KBD_BUFFER_SIZE - 1 ? kbd_buffer : ptr + 1; | 389 | return ptr == kbd_buffer + KBD_BUFFER_SIZE - 1 ? kbd_buffer : ptr + 1; |
| 390 | } | 390 | } |
| 391 | 391 | ||
| 392 | #ifdef HAVE_X11 | ||
| 393 | static union buffered_input_event * | ||
| 394 | prev_kbd_event (union buffered_input_event *ptr) | ||
| 395 | { | ||
| 396 | return ptr == kbd_buffer ? kbd_buffer + KBD_BUFFER_SIZE - 1 : ptr - 1; | ||
| 397 | } | ||
| 398 | #endif | ||
| 399 | |||
| 400 | /* Like EVENT_START, but assume EVENT is an event. | 392 | /* Like EVENT_START, but assume EVENT is an event. |
| 401 | This pacifies gcc -Wnull-dereference, which might otherwise | 393 | This pacifies gcc -Wnull-dereference, which might otherwise |
| 402 | complain about earlier checks that EVENT is indeed an event. */ | 394 | complain about earlier checks that EVENT is indeed an event. */ |
| @@ -3528,6 +3520,11 @@ readable_events (int flags) | |||
| 3528 | return 1; | 3520 | return 1; |
| 3529 | } | 3521 | } |
| 3530 | 3522 | ||
| 3523 | #ifdef HAVE_X_WINDOWS | ||
| 3524 | if (x_detect_pending_selection_requests ()) | ||
| 3525 | return 1; | ||
| 3526 | #endif | ||
| 3527 | |||
| 3531 | if (!(flags & READABLE_EVENTS_IGNORE_SQUEEZABLES) && some_mouse_moved ()) | 3528 | if (!(flags & READABLE_EVENTS_IGNORE_SQUEEZABLES) && some_mouse_moved ()) |
| 3532 | return 1; | 3529 | return 1; |
| 3533 | if (single_kboard) | 3530 | if (single_kboard) |
| @@ -3699,25 +3696,6 @@ kbd_buffer_store_buffered_event (union buffered_input_event *event, | |||
| 3699 | Vquit_flag = Vthrow_on_input; | 3696 | Vquit_flag = Vthrow_on_input; |
| 3700 | } | 3697 | } |
| 3701 | 3698 | ||
| 3702 | |||
| 3703 | #ifdef HAVE_X11 | ||
| 3704 | |||
| 3705 | /* Put a selection input event back in the head of the event queue. */ | ||
| 3706 | |||
| 3707 | void | ||
| 3708 | kbd_buffer_unget_event (struct selection_input_event *event) | ||
| 3709 | { | ||
| 3710 | /* Don't let the very last slot in the buffer become full, */ | ||
| 3711 | union buffered_input_event *kp = prev_kbd_event (kbd_fetch_ptr); | ||
| 3712 | if (kp != kbd_store_ptr) | ||
| 3713 | { | ||
| 3714 | kp->sie = *event; | ||
| 3715 | kbd_fetch_ptr = kp; | ||
| 3716 | } | ||
| 3717 | } | ||
| 3718 | |||
| 3719 | #endif | ||
| 3720 | |||
| 3721 | /* Limit help event positions to this range, to avoid overflow problems. */ | 3699 | /* Limit help event positions to this range, to avoid overflow problems. */ |
| 3722 | #define INPUT_EVENT_POS_MAX \ | 3700 | #define INPUT_EVENT_POS_MAX \ |
| 3723 | ((ptrdiff_t) min (PTRDIFF_MAX, min (TYPE_MAXIMUM (Time) / 2, \ | 3701 | ((ptrdiff_t) min (PTRDIFF_MAX, min (TYPE_MAXIMUM (Time) / 2, \ |
| @@ -3874,6 +3852,11 @@ kbd_buffer_get_event (KBOARD **kbp, | |||
| 3874 | struct timespec *end_time) | 3852 | struct timespec *end_time) |
| 3875 | { | 3853 | { |
| 3876 | Lisp_Object obj, str; | 3854 | Lisp_Object obj, str; |
| 3855 | #ifdef HAVE_X_WINDOWS | ||
| 3856 | bool had_pending_selection_requests; | ||
| 3857 | |||
| 3858 | had_pending_selection_requests = false; | ||
| 3859 | #endif | ||
| 3877 | 3860 | ||
| 3878 | #ifdef subprocesses | 3861 | #ifdef subprocesses |
| 3879 | if (kbd_on_hold_p () && kbd_buffer_nr_stored () < KBD_BUFFER_SIZE / 4) | 3862 | if (kbd_on_hold_p () && kbd_buffer_nr_stored () < KBD_BUFFER_SIZE / 4) |
| @@ -3926,10 +3909,18 @@ kbd_buffer_get_event (KBOARD **kbp, | |||
| 3926 | #if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL) | 3909 | #if defined (USABLE_SIGIO) || defined (USABLE_SIGPOLL) |
| 3927 | gobble_input (); | 3910 | gobble_input (); |
| 3928 | #endif | 3911 | #endif |
| 3912 | |||
| 3929 | if (kbd_fetch_ptr != kbd_store_ptr) | 3913 | if (kbd_fetch_ptr != kbd_store_ptr) |
| 3930 | break; | 3914 | break; |
| 3931 | if (some_mouse_moved ()) | 3915 | if (some_mouse_moved ()) |
| 3932 | break; | 3916 | break; |
| 3917 | #ifdef HAVE_X_WINDOWS | ||
| 3918 | if (x_detect_pending_selection_requests ()) | ||
| 3919 | { | ||
| 3920 | had_pending_selection_requests = true; | ||
| 3921 | break; | ||
| 3922 | } | ||
| 3923 | #endif | ||
| 3933 | if (end_time) | 3924 | if (end_time) |
| 3934 | { | 3925 | { |
| 3935 | struct timespec now = current_timespec (); | 3926 | struct timespec now = current_timespec (); |
| @@ -3966,6 +3957,16 @@ kbd_buffer_get_event (KBOARD **kbp, | |||
| 3966 | gobble_input (); | 3957 | gobble_input (); |
| 3967 | } | 3958 | } |
| 3968 | 3959 | ||
| 3960 | #ifdef HAVE_X_WINDOWS | ||
| 3961 | /* Handle pending selection requests. This can happen if Emacs | ||
| 3962 | enters a recursive edit inside a nested event loop (probably | ||
| 3963 | because the debugger opened) or someone called | ||
| 3964 | `read-char'. */ | ||
| 3965 | |||
| 3966 | if (had_pending_selection_requests) | ||
| 3967 | x_handle_pending_selection_requests (); | ||
| 3968 | #endif | ||
| 3969 | |||
| 3969 | if (CONSP (Vunread_command_events)) | 3970 | if (CONSP (Vunread_command_events)) |
| 3970 | { | 3971 | { |
| 3971 | Lisp_Object first; | 3972 | Lisp_Object first; |
| @@ -4345,6 +4346,10 @@ kbd_buffer_get_event (KBOARD **kbp, | |||
| 4345 | ? movement_frame->last_mouse_device | 4346 | ? movement_frame->last_mouse_device |
| 4346 | : virtual_core_pointer_name); | 4347 | : virtual_core_pointer_name); |
| 4347 | } | 4348 | } |
| 4349 | #ifdef HAVE_X_WINDOWS | ||
| 4350 | else if (had_pending_selection_requests) | ||
| 4351 | obj = Qnil; | ||
| 4352 | #endif | ||
| 4348 | else | 4353 | else |
| 4349 | /* We were promised by the above while loop that there was | 4354 | /* We were promised by the above while loop that there was |
| 4350 | something for us to read! */ | 4355 | something for us to read! */ |
| @@ -7241,7 +7246,10 @@ lucid_event_type_list_p (Lisp_Object object) | |||
| 7241 | If READABLE_EVENTS_FILTER_EVENTS is set in FLAGS, ignore internal | 7246 | If READABLE_EVENTS_FILTER_EVENTS is set in FLAGS, ignore internal |
| 7242 | events (FOCUS_IN_EVENT). | 7247 | events (FOCUS_IN_EVENT). |
| 7243 | If READABLE_EVENTS_IGNORE_SQUEEZABLES is set in FLAGS, ignore mouse | 7248 | If READABLE_EVENTS_IGNORE_SQUEEZABLES is set in FLAGS, ignore mouse |
| 7244 | movements and toolkit scroll bar thumb drags. */ | 7249 | movements and toolkit scroll bar thumb drags. |
| 7250 | |||
| 7251 | On X, this also returns if the selection event chain is full, since | ||
| 7252 | that's also "keyboard input". */ | ||
| 7245 | 7253 | ||
| 7246 | static bool | 7254 | static bool |
| 7247 | get_input_pending (int flags) | 7255 | get_input_pending (int flags) |
diff --git a/src/keyboard.h b/src/keyboard.h index a0b7204fa2b..6ae2dc9c4c6 100644 --- a/src/keyboard.h +++ b/src/keyboard.h | |||
| @@ -481,9 +481,6 @@ kbd_buffer_store_event_hold (struct input_event *event, | |||
| 481 | kbd_buffer_store_buffered_event ((union buffered_input_event *) event, | 481 | kbd_buffer_store_buffered_event ((union buffered_input_event *) event, |
| 482 | hold_quit); | 482 | hold_quit); |
| 483 | } | 483 | } |
| 484 | #ifdef HAVE_X11 | ||
| 485 | extern void kbd_buffer_unget_event (struct selection_input_event *); | ||
| 486 | #endif | ||
| 487 | extern void poll_for_input_1 (void); | 484 | extern void poll_for_input_1 (void); |
| 488 | extern void show_help_echo (Lisp_Object, Lisp_Object, Lisp_Object, | 485 | extern void show_help_echo (Lisp_Object, Lisp_Object, Lisp_Object, |
| 489 | Lisp_Object); | 486 | Lisp_Object); |
diff --git a/src/xselect.c b/src/xselect.c index 5f2a0cf56de..6e693c25884 100644 --- a/src/xselect.c +++ b/src/xselect.c | |||
| @@ -116,92 +116,6 @@ selection_quantum (Display *display) | |||
| 116 | assq_no_quit (selection_symbol, dpyinfo->terminal->Vselection_alist) | 116 | assq_no_quit (selection_symbol, dpyinfo->terminal->Vselection_alist) |
| 117 | 117 | ||
| 118 | 118 | ||
| 119 | /* Define a queue to save up SELECTION_REQUEST_EVENT events for later | ||
| 120 | handling. */ | ||
| 121 | |||
| 122 | struct selection_event_queue | ||
| 123 | { | ||
| 124 | struct selection_input_event event; | ||
| 125 | struct selection_event_queue *next; | ||
| 126 | }; | ||
| 127 | |||
| 128 | static struct selection_event_queue *selection_queue; | ||
| 129 | |||
| 130 | /* Nonzero means queue up SELECTION_REQUEST_EVENT events. */ | ||
| 131 | |||
| 132 | static int x_queue_selection_requests; | ||
| 133 | |||
| 134 | /* True if the input events are duplicates. */ | ||
| 135 | |||
| 136 | static bool | ||
| 137 | selection_input_event_equal (struct selection_input_event *a, | ||
| 138 | struct selection_input_event *b) | ||
| 139 | { | ||
| 140 | return (a->kind == b->kind && a->dpyinfo == b->dpyinfo | ||
| 141 | && a->requestor == b->requestor && a->selection == b->selection | ||
| 142 | && a->target == b->target && a->property == b->property | ||
| 143 | && a->time == b->time); | ||
| 144 | } | ||
| 145 | |||
| 146 | /* Queue up an SELECTION_REQUEST_EVENT *EVENT, to be processed later. */ | ||
| 147 | |||
| 148 | static void | ||
| 149 | x_queue_event (struct selection_input_event *event) | ||
| 150 | { | ||
| 151 | struct selection_event_queue *queue_tmp; | ||
| 152 | |||
| 153 | /* Don't queue repeated requests. | ||
| 154 | This only happens for large requests which uses the incremental protocol. */ | ||
| 155 | for (queue_tmp = selection_queue; queue_tmp; queue_tmp = queue_tmp->next) | ||
| 156 | { | ||
| 157 | if (selection_input_event_equal (event, &queue_tmp->event)) | ||
| 158 | { | ||
| 159 | TRACE1 ("DECLINE DUP SELECTION EVENT %p", queue_tmp); | ||
| 160 | x_decline_selection_request (event); | ||
| 161 | return; | ||
| 162 | } | ||
| 163 | } | ||
| 164 | |||
| 165 | queue_tmp = xmalloc (sizeof *queue_tmp); | ||
| 166 | TRACE1 ("QUEUE SELECTION EVENT %p", queue_tmp); | ||
| 167 | queue_tmp->event = *event; | ||
| 168 | queue_tmp->next = selection_queue; | ||
| 169 | selection_queue = queue_tmp; | ||
| 170 | } | ||
| 171 | |||
| 172 | /* Start queuing SELECTION_REQUEST_EVENT events. */ | ||
| 173 | |||
| 174 | static void | ||
| 175 | x_start_queuing_selection_requests (void) | ||
| 176 | { | ||
| 177 | if (x_queue_selection_requests) | ||
| 178 | emacs_abort (); | ||
| 179 | |||
| 180 | x_queue_selection_requests++; | ||
| 181 | TRACE1 ("x_start_queuing_selection_requests %d", x_queue_selection_requests); | ||
| 182 | } | ||
| 183 | |||
| 184 | /* Stop queuing SELECTION_REQUEST_EVENT events. */ | ||
| 185 | |||
| 186 | static void | ||
| 187 | x_stop_queuing_selection_requests (void) | ||
| 188 | { | ||
| 189 | TRACE1 ("x_stop_queuing_selection_requests %d", x_queue_selection_requests); | ||
| 190 | --x_queue_selection_requests; | ||
| 191 | |||
| 192 | /* Take all the queued events and put them back | ||
| 193 | so that they get processed afresh. */ | ||
| 194 | |||
| 195 | while (selection_queue != NULL) | ||
| 196 | { | ||
| 197 | struct selection_event_queue *queue_tmp = selection_queue; | ||
| 198 | TRACE1 ("RESTORE SELECTION EVENT %p", queue_tmp); | ||
| 199 | kbd_buffer_unget_event (&queue_tmp->event); | ||
| 200 | selection_queue = queue_tmp->next; | ||
| 201 | xfree (queue_tmp); | ||
| 202 | } | ||
| 203 | } | ||
| 204 | |||
| 205 | 119 | ||
| 206 | /* This converts a Lisp symbol to a server Atom, avoiding a server | 120 | /* This converts a Lisp symbol to a server Atom, avoiding a server |
| 207 | roundtrip whenever possible. */ | 121 | roundtrip whenever possible. */ |
| @@ -839,11 +753,6 @@ x_handle_selection_request (struct selection_input_event *event) | |||
| 839 | selection_request_dpyinfo = dpyinfo; | 753 | selection_request_dpyinfo = dpyinfo; |
| 840 | record_unwind_protect_void (x_selection_request_lisp_error); | 754 | record_unwind_protect_void (x_selection_request_lisp_error); |
| 841 | 755 | ||
| 842 | /* We might be able to handle nested x_handle_selection_requests, | ||
| 843 | but this is difficult to test, and seems unimportant. */ | ||
| 844 | x_start_queuing_selection_requests (); | ||
| 845 | record_unwind_protect_void (x_stop_queuing_selection_requests); | ||
| 846 | |||
| 847 | TRACE2 ("x_handle_selection_request: selection=%s, target=%s", | 756 | TRACE2 ("x_handle_selection_request: selection=%s, target=%s", |
| 848 | SDATA (SYMBOL_NAME (selection_symbol)), | 757 | SDATA (SYMBOL_NAME (selection_symbol)), |
| 849 | SDATA (SYMBOL_NAME (target_symbol))); | 758 | SDATA (SYMBOL_NAME (target_symbol))); |
| @@ -1028,8 +937,6 @@ x_handle_selection_event (struct selection_input_event *event) | |||
| 1028 | TRACE0 ("x_handle_selection_event"); | 937 | TRACE0 ("x_handle_selection_event"); |
| 1029 | if (event->kind != SELECTION_REQUEST_EVENT) | 938 | if (event->kind != SELECTION_REQUEST_EVENT) |
| 1030 | x_handle_selection_clear (event); | 939 | x_handle_selection_clear (event); |
| 1031 | else if (x_queue_selection_requests) | ||
| 1032 | x_queue_event (event); | ||
| 1033 | else | 940 | else |
| 1034 | x_handle_selection_request (event); | 941 | x_handle_selection_request (event); |
| 1035 | } | 942 | } |
diff --git a/src/xterm.c b/src/xterm.c index 4d8d7e80eb5..ffbd09d27f0 100644 --- a/src/xterm.c +++ b/src/xterm.c | |||
| @@ -789,6 +789,21 @@ static int current_finish; | |||
| 789 | static struct input_event *current_hold_quit; | 789 | static struct input_event *current_hold_quit; |
| 790 | #endif | 790 | #endif |
| 791 | 791 | ||
| 792 | struct x_selection_request_event | ||
| 793 | { | ||
| 794 | /* The selection request event. */ | ||
| 795 | struct selection_input_event se; | ||
| 796 | |||
| 797 | /* The next unprocessed selection request event. */ | ||
| 798 | struct x_selection_request_event *next; | ||
| 799 | }; | ||
| 800 | |||
| 801 | /* Chain of unprocessed selection request events. Used to handle | ||
| 802 | selection requests inside long-lasting modal event loops, such as | ||
| 803 | the drag-and-drop loop. */ | ||
| 804 | |||
| 805 | struct x_selection_request_event *pending_selection_requests; | ||
| 806 | |||
| 792 | /* Compare two request serials A and B with OP, handling | 807 | /* Compare two request serials A and B with OP, handling |
| 793 | wraparound. */ | 808 | wraparound. */ |
| 794 | #define X_COMPARE_SERIALS(a, op ,b) \ | 809 | #define X_COMPARE_SERIALS(a, op ,b) \ |
| @@ -1169,6 +1184,10 @@ static unsigned int x_dnd_keyboard_state; | |||
| 1169 | terminating DND as part of the display disconnect handler. */ | 1184 | terminating DND as part of the display disconnect handler. */ |
| 1170 | static sigjmp_buf x_dnd_disconnect_handler; | 1185 | static sigjmp_buf x_dnd_disconnect_handler; |
| 1171 | 1186 | ||
| 1187 | /* Whether or not the current invocation of handle_one_xevent | ||
| 1188 | happened inside the drag_and_drop event loop. */ | ||
| 1189 | static bool x_dnd_inside_handle_one_xevent; | ||
| 1190 | |||
| 1172 | /* Structure describing a single window that can be the target of | 1191 | /* Structure describing a single window that can be the target of |
| 1173 | drag-and-drop operations. */ | 1192 | drag-and-drop operations. */ |
| 1174 | struct x_client_list_window | 1193 | struct x_client_list_window |
| @@ -10546,6 +10565,53 @@ x_next_event_from_any_display (XEvent *event) | |||
| 10546 | 10565 | ||
| 10547 | #endif /* USE_X_TOOLKIT || USE_GTK */ | 10566 | #endif /* USE_X_TOOLKIT || USE_GTK */ |
| 10548 | 10567 | ||
| 10568 | static void | ||
| 10569 | x_handle_pending_selection_requests_1 (struct x_selection_request_event *tem) | ||
| 10570 | { | ||
| 10571 | specpdl_ref count; | ||
| 10572 | struct selection_input_event se; | ||
| 10573 | |||
| 10574 | count = SPECPDL_INDEX (); | ||
| 10575 | se = tem->se; | ||
| 10576 | |||
| 10577 | record_unwind_protect_ptr (xfree, tem); | ||
| 10578 | x_handle_selection_event (&se); | ||
| 10579 | unbind_to (count, Qnil); | ||
| 10580 | } | ||
| 10581 | |||
| 10582 | /* Handle all pending selection request events from modal event | ||
| 10583 | loops. */ | ||
| 10584 | void | ||
| 10585 | x_handle_pending_selection_requests (void) | ||
| 10586 | { | ||
| 10587 | struct x_selection_request_event *tem; | ||
| 10588 | |||
| 10589 | while (pending_selection_requests) | ||
| 10590 | { | ||
| 10591 | tem = pending_selection_requests; | ||
| 10592 | pending_selection_requests = tem->next; | ||
| 10593 | |||
| 10594 | x_handle_pending_selection_requests_1 (tem); | ||
| 10595 | } | ||
| 10596 | } | ||
| 10597 | |||
| 10598 | static void | ||
| 10599 | x_push_selection_request (struct selection_input_event *se) | ||
| 10600 | { | ||
| 10601 | struct x_selection_request_event *tem; | ||
| 10602 | |||
| 10603 | tem = xmalloc (sizeof *tem); | ||
| 10604 | tem->next = pending_selection_requests; | ||
| 10605 | tem->se = *se; | ||
| 10606 | pending_selection_requests = tem; | ||
| 10607 | } | ||
| 10608 | |||
| 10609 | bool | ||
| 10610 | x_detect_pending_selection_requests (void) | ||
| 10611 | { | ||
| 10612 | return pending_selection_requests; | ||
| 10613 | } | ||
| 10614 | |||
| 10549 | /* This function is defined far away from the rest of the XDND code so | 10615 | /* This function is defined far away from the rest of the XDND code so |
| 10550 | it can utilize `x_any_window_to_frame'. */ | 10616 | it can utilize `x_any_window_to_frame'. */ |
| 10551 | 10617 | ||
| @@ -10841,6 +10907,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, | |||
| 10841 | while (x_dnd_in_progress || x_dnd_waiting_for_finish) | 10907 | while (x_dnd_in_progress || x_dnd_waiting_for_finish) |
| 10842 | { | 10908 | { |
| 10843 | EVENT_INIT (hold_quit); | 10909 | EVENT_INIT (hold_quit); |
| 10910 | |||
| 10844 | #ifdef USE_GTK | 10911 | #ifdef USE_GTK |
| 10845 | current_finish = X_EVENT_NORMAL; | 10912 | current_finish = X_EVENT_NORMAL; |
| 10846 | current_hold_quit = &hold_quit; | 10913 | current_hold_quit = &hold_quit; |
| @@ -10849,6 +10916,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, | |||
| 10849 | #endif | 10916 | #endif |
| 10850 | 10917 | ||
| 10851 | block_input (); | 10918 | block_input (); |
| 10919 | x_dnd_inside_handle_one_xevent = true; | ||
| 10852 | #ifdef USE_GTK | 10920 | #ifdef USE_GTK |
| 10853 | gtk_main_iteration (); | 10921 | gtk_main_iteration (); |
| 10854 | #elif defined USE_X_TOOLKIT | 10922 | #elif defined USE_X_TOOLKIT |
| @@ -10890,6 +10958,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, | |||
| 10890 | current_count = -1; | 10958 | current_count = -1; |
| 10891 | current_hold_quit = NULL; | 10959 | current_hold_quit = NULL; |
| 10892 | #endif | 10960 | #endif |
| 10961 | x_dnd_inside_handle_one_xevent = false; | ||
| 10893 | 10962 | ||
| 10894 | /* The unblock_input below might try to read input, but | 10963 | /* The unblock_input below might try to read input, but |
| 10895 | XTread_socket does nothing inside a drag-and-drop event | 10964 | XTread_socket does nothing inside a drag-and-drop event |
| @@ -10942,29 +11011,6 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, | |||
| 10942 | 11011 | ||
| 10943 | if (hold_quit.kind != NO_EVENT) | 11012 | if (hold_quit.kind != NO_EVENT) |
| 10944 | { | 11013 | { |
| 10945 | if (hold_quit.kind == SELECTION_REQUEST_EVENT) | ||
| 10946 | { | ||
| 10947 | /* It's not safe to run Lisp inside this function if | ||
| 10948 | x_dnd_in_progress and x_dnd_waiting_for_finish | ||
| 10949 | are unset, so push it back into the event queue. */ | ||
| 10950 | |||
| 10951 | if (!x_dnd_in_progress && !x_dnd_waiting_for_finish) | ||
| 10952 | kbd_buffer_store_event (&hold_quit); | ||
| 10953 | else | ||
| 10954 | { | ||
| 10955 | x_dnd_old_window_attrs = root_window_attrs; | ||
| 10956 | x_dnd_unwind_flag = true; | ||
| 10957 | |||
| 10958 | ref = SPECPDL_INDEX (); | ||
| 10959 | record_unwind_protect_ptr (x_dnd_cleanup_drag_and_drop, f); | ||
| 10960 | x_handle_selection_event ((struct selection_input_event *) &hold_quit); | ||
| 10961 | x_dnd_unwind_flag = false; | ||
| 10962 | unbind_to (ref, Qnil); | ||
| 10963 | } | ||
| 10964 | |||
| 10965 | continue; | ||
| 10966 | } | ||
| 10967 | |||
| 10968 | if (x_dnd_in_progress) | 11014 | if (x_dnd_in_progress) |
| 10969 | { | 11015 | { |
| 10970 | if (x_dnd_last_seen_window != None | 11016 | if (x_dnd_last_seen_window != None |
| @@ -11031,6 +11077,19 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, | |||
| 11031 | quit (); | 11077 | quit (); |
| 11032 | } | 11078 | } |
| 11033 | 11079 | ||
| 11080 | if (pending_selection_requests | ||
| 11081 | && (x_dnd_in_progress || x_dnd_waiting_for_finish)) | ||
| 11082 | { | ||
| 11083 | x_dnd_old_window_attrs = root_window_attrs; | ||
| 11084 | x_dnd_unwind_flag = true; | ||
| 11085 | |||
| 11086 | ref = SPECPDL_INDEX (); | ||
| 11087 | record_unwind_protect_ptr (x_dnd_cleanup_drag_and_drop, f); | ||
| 11088 | x_handle_pending_selection_requests (); | ||
| 11089 | x_dnd_unwind_flag = false; | ||
| 11090 | unbind_to (ref, Qnil); | ||
| 11091 | } | ||
| 11092 | |||
| 11034 | #ifdef USE_GTK | 11093 | #ifdef USE_GTK |
| 11035 | if (xg_pending_quit_event.kind != NO_EVENT) | 11094 | if (xg_pending_quit_event.kind != NO_EVENT) |
| 11036 | { | 11095 | { |
| @@ -15801,6 +15860,15 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 15801 | SELECTION_EVENT_DPYINFO (&inev.sie) = dpyinfo; | 15860 | SELECTION_EVENT_DPYINFO (&inev.sie) = dpyinfo; |
| 15802 | SELECTION_EVENT_SELECTION (&inev.sie) = eventp->selection; | 15861 | SELECTION_EVENT_SELECTION (&inev.sie) = eventp->selection; |
| 15803 | SELECTION_EVENT_TIME (&inev.sie) = eventp->time; | 15862 | SELECTION_EVENT_TIME (&inev.sie) = eventp->time; |
| 15863 | |||
| 15864 | if ((x_dnd_in_progress | ||
| 15865 | && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame)) | ||
| 15866 | || (x_dnd_waiting_for_finish | ||
| 15867 | && dpyinfo->display == x_dnd_finish_display)) | ||
| 15868 | { | ||
| 15869 | x_push_selection_request (&inev.sie); | ||
| 15870 | EVENT_INIT (inev.ie); | ||
| 15871 | } | ||
| 15804 | } | 15872 | } |
| 15805 | break; | 15873 | break; |
| 15806 | 15874 | ||
| @@ -15829,17 +15897,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 15829 | || (x_dnd_waiting_for_finish | 15897 | || (x_dnd_waiting_for_finish |
| 15830 | && dpyinfo->display == x_dnd_finish_display)) | 15898 | && dpyinfo->display == x_dnd_finish_display)) |
| 15831 | { | 15899 | { |
| 15832 | #ifndef USE_GTK | 15900 | x_push_selection_request (&inev.sie); |
| 15833 | eassume (hold_quit); | ||
| 15834 | #else | ||
| 15835 | /* If the debugger runs inside a selection converter, then | ||
| 15836 | xg_select can call handle_one_xevent with no | ||
| 15837 | hold_quit. */ | ||
| 15838 | if (!hold_quit) | ||
| 15839 | goto done; | ||
| 15840 | #endif | ||
| 15841 | |||
| 15842 | *hold_quit = inev.ie; | ||
| 15843 | EVENT_INIT (inev.ie); | 15901 | EVENT_INIT (inev.ie); |
| 15844 | } | 15902 | } |
| 15845 | 15903 | ||
| @@ -21120,12 +21178,16 @@ XTread_socket (struct terminal *terminal, struct input_event *hold_quit) | |||
| 21120 | read X events while the drag-and-drop event loop is in progress, | 21178 | read X events while the drag-and-drop event loop is in progress, |
| 21121 | things can go wrong very quick. | 21179 | things can go wrong very quick. |
| 21122 | 21180 | ||
| 21181 | When x_dnd_unwind_flag is true, the above doesn't apply, since | ||
| 21182 | the surrounding code takes special precautions to keep it safe. | ||
| 21183 | |||
| 21123 | That doesn't matter for events from displays other than the | 21184 | That doesn't matter for events from displays other than the |
| 21124 | display of the drag-and-drop operation, though. */ | 21185 | display of the drag-and-drop operation, though. */ |
| 21125 | if ((x_dnd_in_progress | 21186 | if (!x_dnd_unwind_flag |
| 21126 | && dpyinfo->display == FRAME_X_DISPLAY (x_dnd_frame)) | 21187 | && ((x_dnd_in_progress |
| 21127 | || (x_dnd_waiting_for_finish | 21188 | && dpyinfo->display == FRAME_X_DISPLAY (x_dnd_frame)) |
| 21128 | && dpyinfo->display == x_dnd_finish_display)) | 21189 | || (x_dnd_waiting_for_finish |
| 21190 | && dpyinfo->display == x_dnd_finish_display))) | ||
| 21129 | return 0; | 21191 | return 0; |
| 21130 | 21192 | ||
| 21131 | block_input (); | 21193 | block_input (); |
| @@ -25840,6 +25902,7 @@ x_delete_display (struct x_display_info *dpyinfo) | |||
| 25840 | struct terminal *t; | 25902 | struct terminal *t; |
| 25841 | struct color_name_cache_entry *color_entry, *next_color_entry; | 25903 | struct color_name_cache_entry *color_entry, *next_color_entry; |
| 25842 | int i; | 25904 | int i; |
| 25905 | struct x_selection_request_event *ie, *last, *temp; | ||
| 25843 | 25906 | ||
| 25844 | /* Close all frames and delete the generic struct terminal for this | 25907 | /* Close all frames and delete the generic struct terminal for this |
| 25845 | X display. */ | 25908 | X display. */ |
| @@ -25855,6 +25918,30 @@ x_delete_display (struct x_display_info *dpyinfo) | |||
| 25855 | break; | 25918 | break; |
| 25856 | } | 25919 | } |
| 25857 | 25920 | ||
| 25921 | /* Find any pending selection requests for this display and unchain | ||
| 25922 | them. */ | ||
| 25923 | |||
| 25924 | last = NULL; | ||
| 25925 | |||
| 25926 | for (ie = pending_selection_requests; ie; ie = ie->next) | ||
| 25927 | { | ||
| 25928 | again: | ||
| 25929 | |||
| 25930 | if (SELECTION_EVENT_DPYINFO (&ie->se) == dpyinfo) | ||
| 25931 | { | ||
| 25932 | if (last) | ||
| 25933 | last->next = ie->next; | ||
| 25934 | |||
| 25935 | temp = ie; | ||
| 25936 | ie = ie->next; | ||
| 25937 | xfree (temp); | ||
| 25938 | |||
| 25939 | goto again; | ||
| 25940 | } | ||
| 25941 | |||
| 25942 | last = ie; | ||
| 25943 | } | ||
| 25944 | |||
| 25858 | if (next_noop_dpyinfo == dpyinfo) | 25945 | if (next_noop_dpyinfo == dpyinfo) |
| 25859 | next_noop_dpyinfo = dpyinfo->next; | 25946 | next_noop_dpyinfo = dpyinfo->next; |
| 25860 | 25947 | ||
diff --git a/src/xterm.h b/src/xterm.h index 878cb5fd87b..22c6b551766 100644 --- a/src/xterm.h +++ b/src/xterm.h | |||
| @@ -1455,6 +1455,8 @@ extern void x_xr_reset_ext_clip (struct frame *f); | |||
| 1455 | extern void x_scroll_bar_configure (GdkEvent *); | 1455 | extern void x_scroll_bar_configure (GdkEvent *); |
| 1456 | #endif | 1456 | #endif |
| 1457 | 1457 | ||
| 1458 | extern void x_handle_pending_selection_requests (void); | ||
| 1459 | extern bool x_detect_pending_selection_requests (void); | ||
| 1458 | extern Lisp_Object x_dnd_begin_drag_and_drop (struct frame *, Time, Atom, | 1460 | extern Lisp_Object x_dnd_begin_drag_and_drop (struct frame *, Time, Atom, |
| 1459 | Lisp_Object, Atom *, const char **, | 1461 | Lisp_Object, Atom *, const char **, |
| 1460 | size_t, bool, Atom *, int); | 1462 | size_t, bool, Atom *, int); |