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);