Mercurial > emacs
changeset 57952:a6f82b95d10b
* xselect.c (struct selection_event_queue, selection_queue)
(x_queue_selection_requests, x_queue_event)
(x_start_queuing_selection_requests)
(x_stop_queuing_selection_requests): Add new queue for selection
input events to replace previous XEvent queue in xterm.c.
(queue_selection_requests_unwind): Adapt to new queue.
(x_reply_selection_request): Adapt to new queue. Unexpect
wait_object in case of x errors (memory leak).
(x_handle_selection_request, x_handle_selection_clear): Make static.
(x_handle_selection_event): New function. May queue selection events.
(wait_for_property_change_unwind): Use save_value instead of cons.
Clear property_change_reply_object.
(wait_for_property_change): Abort if already waiting.
Use save_value instead of cons for unwind data.
(x_handle_property_notify): Skip events already arrived, but don't
free them, as "arrived" field is checked by wait_for_property_change,
and it will be freed by unwind or explicit unexpect_property_change.
(x_get_foreign_selection): Add to new queue.
(receive_incremental_selection): Don't unexpect wait_object when done
as it has already been freed by previous wait_for_property_change.
author | Kim F. Storm <storm@cua.dk> |
---|---|
date | Fri, 05 Nov 2004 11:30:31 +0000 |
parents | fbbae2d9a2f4 |
children | 95edcd1fae73 |
files | src/xselect.c |
diffstat | 1 files changed, 131 insertions(+), 33 deletions(-) [+] |
line wrap: on
line diff
--- a/src/xselect.c Fri Nov 05 11:30:12 2004 +0000 +++ b/src/xselect.c Fri Nov 05 11:30:31 2004 +0000 @@ -32,6 +32,7 @@ #include "buffer.h" #include "process.h" #include "termhooks.h" +#include "keyboard.h" #include <X11/Xproto.h> @@ -171,6 +172,86 @@ static Lisp_Object selection_data_to_lisp_data (); static Lisp_Object x_get_window_property_as_lisp_data (); + + +/* Define a queue to save up SelectionRequest events for later handling. */ + +struct selection_event_queue + { + struct input_event event; + struct selection_event_queue *next; + }; + +static struct selection_event_queue *selection_queue; + +/* Nonzero means queue up certain events--don't process them yet. */ + +static int x_queue_selection_requests; + +/* Queue up an X event *EVENT, to be processed later. */ + +static void +x_queue_event (event) + struct input_event *event; +{ + struct selection_event_queue *queue_tmp; + + /* Don't queue repeated requests */ + for (queue_tmp = selection_queue; queue_tmp; queue_tmp = queue_tmp->next) + { + if (!bcmp (&queue_tmp->event, event, sizeof (*event))) + { + TRACE1 ("IGNORE DUP SELECTION EVENT %08x", (unsigned long)queue_tmp); + return; + } + } + + queue_tmp + = (struct selection_event_queue *) xmalloc (sizeof (struct selection_event_queue)); + + if (queue_tmp != NULL) + { + TRACE1 ("QUEUE SELECTION EVENT %08x", (unsigned long)queue_tmp); + queue_tmp->event = *event; + queue_tmp->next = selection_queue; + selection_queue = queue_tmp; + } +} + +/* Start queuing SelectionRequest events. */ + +static void +x_start_queuing_selection_requests () +{ + if (x_queue_selection_requests) + abort (); + + x_queue_selection_requests++; + TRACE1 ("x_start_queuing_selection_requests %d", x_queue_selection_requests); +} + +/* Stop queuing SelectionRequest events. */ + +static void +x_stop_queuing_selection_requests () +{ + TRACE1 ("x_stop_queuing_selection_requests %d", x_queue_selection_requests); + --x_queue_selection_requests; + + /* Take all the queued events and put them back + so that they get processed afresh. */ + + while (selection_queue != NULL) + { + struct selection_event_queue *queue_tmp = selection_queue; + TRACE1 ("RESTORE SELECTION EVENT %08x", (unsigned long)queue_tmp); + kbd_buffer_unget_event (&queue_tmp->event); + selection_queue = queue_tmp->next; + xfree ((char *)queue_tmp); + } +} + + /* This converts a Lisp symbol to a server Atom, avoiding a server roundtrip whenever possible. */ @@ -560,13 +641,10 @@ static struct prop_location *property_change_wait_list; static Lisp_Object -queue_selection_requests_unwind (frame) - Lisp_Object frame; +queue_selection_requests_unwind (tem) + Lisp_Object tem; { - FRAME_PTR f = XFRAME (frame); - - if (! NILP (frame)) - x_stop_queuing_selection_requests (FRAME_X_DISPLAY (f)); + x_stop_queuing_selection_requests (); return Qnil; } @@ -664,10 +742,10 @@ bother trying to queue them. */ if (!NILP (frame)) { - x_start_queuing_selection_requests (display); + x_start_queuing_selection_requests (); record_unwind_protect (queue_selection_requests_unwind, - frame); + Qnil); } if (x_window_to_frame (dpyinfo, window)) /* #### debug */ @@ -701,6 +779,8 @@ XGetAtomName (display, reply.property)); wait_for_property_change (wait_object); } + else + unexpect_property_change (wait_object); TRACE0 ("Got ACK"); while (bytes_remaining) @@ -774,7 +854,7 @@ /* Handle a SelectionRequest event EVENT. This is called from keyboard.c when such an event is found in the queue. */ -void +static void x_handle_selection_request (event) struct input_event *event; { @@ -789,6 +869,8 @@ struct x_display_info *dpyinfo = x_display_info_for_display (SELECTION_EVENT_DISPLAY (event)); + TRACE0 ("x_handle_selection_request"); + local_selection_data = Qnil; target_symbol = Qnil; converted_selection = Qnil; @@ -883,7 +965,7 @@ client cleared out our previously asserted selection. This is called from keyboard.c when such an event is found in the queue. */ -void +static void x_handle_selection_clear (event) struct input_event *event; { @@ -896,6 +978,8 @@ struct x_display_info *dpyinfo = x_display_info_for_display (display); struct x_display_info *t_dpyinfo; + TRACE0 ("x_handle_selection_clear"); + /* If the new selection owner is also Emacs, don't clear the new selection. */ BLOCK_INPUT; @@ -964,6 +1048,24 @@ } } +void +x_handle_selection_event (event) + struct input_event *event; +{ + TRACE0 ("x_handle_selection_event"); + + if (event->kind == SELECTION_REQUEST_EVENT) + { + if (x_queue_selection_requests) + x_queue_event (event); + else + x_handle_selection_request (event); + } + else + x_handle_selection_clear (event); +} + + /* Clear all selections that were made from frame F. We do this when about to delete a frame. */ @@ -1094,12 +1196,14 @@ /* Remove the property change expectation element for IDENTIFIER. */ static Lisp_Object -wait_for_property_change_unwind (identifierval) - Lisp_Object identifierval; +wait_for_property_change_unwind (loc) + Lisp_Object loc; { - unexpect_property_change ((struct prop_location *) - (XFASTINT (XCAR (identifierval)) << 16 - | XFASTINT (XCDR (identifierval)))); + struct prop_location *location = XSAVE_VALUE (loc)->pointer; + + unexpect_property_change (location); + if (location == property_change_reply_object) + property_change_reply_object = 0; return Qnil; } @@ -1112,18 +1216,17 @@ { int secs, usecs; int count = SPECPDL_INDEX (); - Lisp_Object tem; - - tem = Fcons (Qnil, Qnil); - XSETCARFASTINT (tem, (EMACS_UINT)location >> 16); - XSETCDRFASTINT (tem, (EMACS_UINT)location & 0xffff); + + if (property_change_reply_object) + abort (); /* Make sure to do unexpect_property_change if we quit or err. */ - record_unwind_protect (wait_for_property_change_unwind, tem); + record_unwind_protect (wait_for_property_change_unwind, + make_save_value (location, 0)); XSETCAR (property_change_reply, Qnil); - property_change_reply_object = location; + /* If the event we are waiting for arrives beyond here, it will set property_change_reply, because property_change_reply_object says so. */ if (! location->arrived) @@ -1154,7 +1257,8 @@ while (rest) { - if (rest->property == event->atom + if (!rest->arrived + && rest->property == event->atom && rest->window == event->window && rest->display == event->display && rest->desired_state == event->state) @@ -1170,11 +1274,6 @@ if (rest == property_change_reply_object) XSETCAR (property_change_reply, Qt); - if (prev) - prev->next = rest->next; - else - property_change_wait_list = rest->next; - xfree (rest); return; } @@ -1300,10 +1399,10 @@ bother trying to queue them. */ if (!NILP (frame)) { - x_start_queuing_selection_requests (display); + x_start_queuing_selection_requests (); record_unwind_protect (queue_selection_requests_unwind, - frame); + Qnil); } UNBLOCK_INPUT; @@ -1459,10 +1558,10 @@ BLOCK_INPUT; XSelectInput (display, window, STANDARD_EVENT_SET | PropertyChangeMask); TRACE1 (" Delete property %s", - SDATA (XSYMBOL (x_atom_to_symbol (display, property))->xname)); + SDATA (SYMBOL_NAME (x_atom_to_symbol (display, property)))); XDeleteProperty (display, window, property); TRACE1 (" Expect new value of property %s", - SDATA (XSYMBOL (x_atom_to_symbol (display, property))->xname)); + SDATA (SYMBOL_NAME (x_atom_to_symbol (display, property)))); wait_object = expect_property_change (display, window, property, PropertyNewValue); XFlush (display); @@ -1492,7 +1591,6 @@ if (! waiting_for_other_props_on_window (display, window)) XSelectInput (display, window, STANDARD_EVENT_SET); - unexpect_property_change (wait_object); /* Use xfree, not XFree, because x_get_window_property calls xmalloc itself. */ if (tmp_data) xfree (tmp_data);