1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-01-25 22:50:37 -08:00

* 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.
This commit is contained in:
Kim F. Storm 2004-11-05 11:30:31 +00:00
parent 87d78665be
commit dd0fe424b2

View file

@ -32,6 +32,7 @@ Boston, MA 02111-1307, USA. */
#include "buffer.h"
#include "process.h"
#include "termhooks.h"
#include "keyboard.h"
#include <X11/Xproto.h>
@ -171,6 +172,86 @@ static void lisp_data_to_selection_data ();
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_reply_object;
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 @@ x_reply_selection_request (event, format, data, size, type)
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 @@ x_reply_selection_request (event, format, data, size, type)
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 @@ x_reply_selection_request (event, format, data, size, type)
/* 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 @@ x_handle_selection_request (event)
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 @@ x_handle_selection_request (event)
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 @@ x_handle_selection_clear (event)
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 @@ x_handle_selection_clear (event)
}
}
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 @@ unexpect_property_change (location)
/* 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 @@ wait_for_property_change (location)
{
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 @@ x_handle_property_notify (event)
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 @@ x_handle_property_notify (event)
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 @@ x_get_foreign_selection (selection_symbol, target_type, time_stamp)
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 @@ receive_incremental_selection (display, window, property, target_type,
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 @@ receive_incremental_selection (display, window, property, target_type,
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);