]> code.delx.au - gnu-emacs/blobdiff - src/xselect.c
Merged from miles@gnu.org--gnu-2005 (patch 83-87, 449-468)
[gnu-emacs] / src / xselect.c
index e3698bae9a60686b7ed05eacca59eb671a8c5914..c60c12c3b673ae946b3611f24a4695f246f23a98 100644 (file)
@@ -24,6 +24,14 @@ Boston, MA 02111-1307, USA.  */
 
 #include <config.h>
 #include <stdio.h>      /* termhooks.h needs this */
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
 #include "lisp.h"
 #include "xterm.h"     /* for all of the X includes */
 #include "dispextern.h"        /* frame.h seems to want this */
@@ -165,16 +173,11 @@ static Lisp_Object Vselection_converter_alist;
 /* If the selection owner takes too long to reply to a selection request,
    we give up on it.  This is in milliseconds (0 = no timeout.)  */
 static EMACS_INT x_selection_timeout;
-\f
-/* Utility functions */
-
-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 ();
 
 
 \f
-/* Define a queue to save up SelectionRequest events for later handling.  */
+/* Define a queue to save up SELECTION_REQUEST_EVENT events for later
+   handling.  */
 
 struct selection_event_queue
   {
@@ -184,11 +187,11 @@ struct selection_event_queue
 
 static struct selection_event_queue *selection_queue;
 
-/* Nonzero means queue up certain events--don't process them yet.  */
+/* Nonzero means queue up SELECTION_REQUEST_EVENT events.  */
 
 static int x_queue_selection_requests;
 
-/* Queue up an X event *EVENT, to be processed later.  */
+/* Queue up an SELECTION_REQUEST_EVENT *EVENT, to be processed later.  */
 
 static void
 x_queue_event (event)
@@ -196,12 +199,14 @@ x_queue_event (event)
 {
   struct selection_event_queue *queue_tmp;
 
-  /* Don't queue repeated requests */
+  /* Don't queue repeated requests.
+     This only happens for large requests which uses the incremental protocol.  */
   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);
+         TRACE1 ("DECLINE DUP SELECTION EVENT %08lx", (unsigned long)queue_tmp);
+         x_decline_selection_request (event);
          return;
        }
     }
@@ -211,14 +216,14 @@ x_queue_event (event)
 
   if (queue_tmp != NULL)
     {
-      TRACE1 ("QUEUE SELECTION EVENT %08x", (unsigned long)queue_tmp);
+      TRACE1 ("QUEUE SELECTION EVENT %08lx", (unsigned long)queue_tmp);
       queue_tmp->event = *event;
       queue_tmp->next = selection_queue;
       selection_queue = queue_tmp;
     }
 }
 
-/* Start queuing SelectionRequest events.  */
+/* Start queuing SELECTION_REQUEST_EVENT events.  */
 
 static void
 x_start_queuing_selection_requests ()
@@ -230,7 +235,7 @@ x_start_queuing_selection_requests ()
   TRACE1 ("x_start_queuing_selection_requests %d", x_queue_selection_requests);
 }
 
-/* Stop queuing SelectionRequest events.  */
+/* Stop queuing SELECTION_REQUEST_EVENT events.  */
 
 static void
 x_stop_queuing_selection_requests ()
@@ -244,7 +249,7 @@ x_stop_queuing_selection_requests ()
   while (selection_queue != NULL)
     {
       struct selection_event_queue *queue_tmp = selection_queue;
-      TRACE1 ("RESTORE SELECTION EVENT %08x", (unsigned long)queue_tmp);
+      TRACE1 ("RESTORE SELECTION EVENT %08lx", (unsigned long)queue_tmp);
       kbd_buffer_unget_event (&queue_tmp->event);
       selection_queue = queue_tmp->next;
       xfree ((char *)queue_tmp);
@@ -392,13 +397,20 @@ x_own_selection (selection_name, selection_value)
      Lisp_Object selection_name, selection_value;
 {
   struct frame *sf = SELECTED_FRAME ();
-  Window selecting_window = FRAME_X_WINDOW (sf);
-  Display *display = FRAME_X_DISPLAY (sf);
+  Window selecting_window;
+  Display *display;
   Time time = last_event_timestamp;
   Atom selection_atom;
-  struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (sf);
+  struct x_display_info *dpyinfo;
   int count;
 
+  if (! FRAME_X_P (sf))
+    return;
+
+  selecting_window = FRAME_X_WINDOW (sf);
+  display = FRAME_X_DISPLAY (sf);
+  dpyinfo = FRAME_X_DISPLAY_INFO (sf);
+  
   CHECK_SYMBOL (selection_name);
   selection_atom = symbol_to_x_atom (dpyinfo, display, selection_name);
 
@@ -659,7 +671,8 @@ some_frame_on_display (dpyinfo)
 
   FOR_EACH_FRAME (list, frame)
     {
-      if (FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
+      if (FRAME_X_P (XFRAME (frame))
+          && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
        return frame;
     }
 
@@ -758,9 +771,17 @@ x_reply_selection_request (event, format, data, size, type)
 
       TRACE1 ("Set %s to number of bytes to send",
              XGetAtomName (display, reply.property));
-      XChangeProperty (display, window, reply.property, dpyinfo->Xatom_INCR,
-                      32, PropModeReplace,
-                      (unsigned char *) &bytes_remaining, 1);
+      {
+        /* XChangeProperty expects an array of long even if long is more than
+           32 bits.  */
+        long value[1];
+
+        value[0] = bytes_remaining;
+        XChangeProperty (display, window, reply.property, dpyinfo->Xatom_INCR,
+                         32, PropModeReplace,
+                         (unsigned char *) value, 1);
+      }
+
       XSelectInput (display, window, PropertyChangeMask);
 
       /* Tell 'em the INCR data is there...  */
@@ -785,9 +806,9 @@ x_reply_selection_request (event, format, data, size, type)
       TRACE0 ("Got ACK");
       while (bytes_remaining)
        {
-         int i = ((bytes_remaining < max_bytes)
-                  ? bytes_remaining
-                  : max_bytes);
+          int i = ((bytes_remaining < max_bytes)
+                   ? bytes_remaining
+                   : max_bytes);
 
          BLOCK_INPUT;
 
@@ -869,7 +890,9 @@ x_handle_selection_request (event)
   struct x_display_info *dpyinfo
     = x_display_info_for_display (SELECTION_EVENT_DISPLAY (event));
 
-  TRACE0 ("x_handle_selection_request");
+  TRACE2 ("x_handle_selection_request, from=0x%08lx time=%lu",
+         (unsigned long) SELECTION_EVENT_REQUESTOR (event),
+         (unsigned long) SELECTION_EVENT_TIME (event));
 
   local_selection_data = Qnil;
   target_symbol = Qnil;
@@ -987,7 +1010,7 @@ x_handle_selection_clear (event)
      to see if this Emacs job now owns the selection
      through that display.  */
   for (t_dpyinfo = x_display_list; t_dpyinfo; t_dpyinfo = t_dpyinfo->next)
-    if (t_dpyinfo->kboard == dpyinfo->kboard)
+    if (t_dpyinfo->frame_display->kboard == dpyinfo->frame_display->kboard)
       {
        Window owner_window
          = XGetSelectionOwner (t_dpyinfo->display, selection);
@@ -1347,17 +1370,26 @@ x_get_foreign_selection (selection_symbol, target_type, time_stamp)
      Lisp_Object selection_symbol, target_type, time_stamp;
 {
   struct frame *sf = SELECTED_FRAME ();
-  Window requestor_window = FRAME_X_WINDOW (sf);
-  Display *display = FRAME_X_DISPLAY (sf);
-  struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (sf);
+  Window requestor_window;
+  Display *display;
+  struct x_display_info *dpyinfo;
   Time requestor_time = last_event_timestamp;
-  Atom target_property = dpyinfo->Xatom_EMACS_TMP;
-  Atom selection_atom = symbol_to_x_atom (dpyinfo, display, selection_symbol);
+  Atom target_property;
+  Atom selection_atom;
   Atom type_atom;
   int secs, usecs;
   int count;
   Lisp_Object frame;
 
+  if (! FRAME_X_P (sf))
+    return Qnil;
+
+  requestor_window = FRAME_X_WINDOW (sf);
+  display = FRAME_X_DISPLAY (sf);
+  dpyinfo = FRAME_X_DISPLAY_INFO (sf);
+  target_property = dpyinfo->Xatom_EMACS_TMP;
+  selection_atom = symbol_to_x_atom (dpyinfo, display, selection_symbol);
+
   if (CONSP (target_type))
     type_atom = symbol_to_x_atom (dpyinfo, display, XCAR (target_type));
   else
@@ -1370,7 +1402,7 @@ x_get_foreign_selection (selection_symbol, target_type, time_stamp)
       else if (INTEGERP (time_stamp))
         requestor_time = (Time) XUINT (time_stamp);
       else if (FLOATP (time_stamp))
-        requestor_time = (Time) XFLOAT (time_stamp);
+        requestor_time = (Time) XFLOAT_DATA (time_stamp);
       else
         error ("TIME_STAMP must be cons or number");
     }
@@ -1510,9 +1542,38 @@ x_get_window_property (display, window, property, data_ret, bytes_ret,
         reading it.  Deal with that, I guess.... */
       if (result != Success)
        break;
-      *actual_size_ret *= *actual_format_ret / 8;
-      bcopy (tmp_data, (*data_ret) + offset, *actual_size_ret);
-      offset += *actual_size_ret;
+
+      /* The man page for XGetWindowProperty says:
+         "If the returned format is 32, the returned data is represented
+          as a long array and should be cast to that type to obtain the
+          elements."
+         This applies even if long is more than 32 bits, the X library
+         converts from 32 bit elements received from the X server to long
+         and passes the long array to us.  Thus, for that case bcopy can not
+         be used.  We convert to a 32 bit type here, because so much code
+         assume on that.
+
+         The bytes and offsets passed to XGetWindowProperty refers to the
+         property and those are indeed in 32 bit quantities if format is 32.  */
+
+      if (*actual_format_ret == 32 && *actual_format_ret < BITS_PER_LONG)
+        {
+          unsigned long i;
+          int  *idata = (int *) ((*data_ret) + offset);
+          long *ldata = (long *) tmp_data;
+
+          for (i = 0; i < *actual_size_ret; ++i)
+            {
+              idata[i]= (int) ldata[i];
+              offset += 4;
+            }
+        }
+      else
+        {
+          *actual_size_ret *= *actual_format_ret / 8;
+          bcopy (tmp_data, (*data_ret) + offset, *actual_size_ret);
+          offset += *actual_size_ret;
+        }
 
       /* This was allocated by Xlib, so use XFree.  */
       XFree ((char *) tmp_data);
@@ -1725,7 +1786,11 @@ x_get_window_property_as_lisp_data (display, window, property, target_type,
 
    When converting an object to C, it may be of the form (SYMBOL . <data>)
    where SYMBOL is what we should claim that the type is.  Format and
-   representation are as above.  */
+   representation are as above.
+
+   Important: When format is 32, data should contain an array of int,
+   not an array of long as the X library returns.  This makes a difference
+   when sizeof(long) != sizeof(int).  */
 
 
 
@@ -1767,15 +1832,21 @@ selection_data_to_lisp_data (display, data, size, type, format)
   else if (type == XA_ATOM)
     {
       int i;
-      if (size == sizeof (Atom))
-       return x_atom_to_symbol (display, *((Atom *) data));
+      /* On a 64 bit machine sizeof(Atom) == sizeof(long) == 8.
+         But the callers of these function has made sure the data for
+         format == 32 is an array of int.  Thus, use int instead
+         of Atom.  */
+      int *idata = (int *) data;
+
+      if (size == sizeof (int))
+       return x_atom_to_symbol (display, (Atom) idata[0]);
       else
        {
-         Lisp_Object v = Fmake_vector (make_number (size / sizeof (Atom)),
+         Lisp_Object v = Fmake_vector (make_number (size / sizeof (int)),
                                        make_number (0));
-         for (i = 0; i < size / sizeof (Atom); i++)
+         for (i = 0; i < size / sizeof (int); i++)
            Faset (v, make_number (i),
-                  x_atom_to_symbol (display, ((Atom *) data) [i]));
+                   x_atom_to_symbol (display, (Atom) idata[i]));
          return v;
        }
     }
@@ -1854,7 +1925,12 @@ lisp_data_to_selection_data (display, obj,
     }
   else if (STRINGP (obj))
     {
-      xassert (! STRING_MULTIBYTE (obj));
+      if (SCHARS (obj) < SBYTES (obj))
+       /* OBJ is a multibyte string containing a non-ASCII char.  */
+       Fsignal (Qerror, /* Qselection_error */
+                Fcons (build_string
+                       ("Non-ASCII string must be encoded in advance"),
+                       Fcons (obj, Qnil)));
       if (NILP (type))
        type = QSTRING;
       *format_ret = 8;
@@ -1957,6 +2033,7 @@ lisp_data_to_selection_data (display, obj,
       else
        /* This vector is an INTEGER set, or something like it */
        {
+          int data_size = 2;
          *size_ret = XVECTOR (obj)->size;
          if (NILP (type)) type = QINTEGER;
          *format_ret = 16;
@@ -1969,7 +2046,11 @@ lisp_data_to_selection_data (display, obj,
        ("elements of selection vector must be integers or conses of integers"),
                              Fcons (obj, Qnil)));
 
-         *data_ret = (unsigned char *) xmalloc (*size_ret * (*format_ret/8));
+          /* Use sizeof(long) even if it is more than 32 bits.  See comment
+             in x_get_window_property and x_fill_property_data.  */
+
+          if (*format_ret == 32) data_size = sizeof(long);
+         *data_ret = (unsigned char *) xmalloc (*size_ret * data_size);
          for (i = 0; i < *size_ret; i++)
            if (*format_ret == 32)
              (*((unsigned long **) data_ret)) [i]
@@ -1981,7 +2062,7 @@ lisp_data_to_selection_data (display, obj,
     }
   else
     Fsignal (Qerror, /* Qselection_error */
-            Fcons (build_string ("unrecognised selection data"),
+            Fcons (build_string ("unrecognized selection data"),
                    Fcons (obj, Qnil)));
 
   *type_ret = symbol_to_x_atom (dpyinfo, display, type);
@@ -2055,7 +2136,7 @@ anything that the functions on `selection-converter-alist' know about.  */)
 {
   check_x ();
   CHECK_SYMBOL (selection_name);
-  if (NILP (selection_value)) error ("selection-value may not be nil");
+  if (NILP (selection_value)) error ("SELECTION-VALUE may not be nil");
   x_own_selection (selection_name, selection_value);
   return selection_value;
 }
@@ -2125,12 +2206,18 @@ Disowning it means there is no such selection.  */)
 {
   Time timestamp;
   Atom selection_atom;
-  struct selection_input_event event;
+  union {
+    struct selection_input_event sie;
+    struct input_event ie;
+  } event;
   Display *display;
   struct x_display_info *dpyinfo;
   struct frame *sf = SELECTED_FRAME ();
 
   check_x ();
+  if (! FRAME_X_P (sf))
+    return Qnil;
+
   display = FRAME_X_DISPLAY (sf);
   dpyinfo = FRAME_X_DISPLAY_INFO (sf);
   CHECK_SYMBOL (selection);
@@ -2153,10 +2240,10 @@ Disowning it means there is no such selection.  */)
      the selection owner to None.  The NCD server does, the MIT Sun4 server
      doesn't.  So we synthesize one; this means we might get two, but
      that's ok, because the second one won't have any effect.  */
-  SELECTION_EVENT_DISPLAY (&event) = display;
-  SELECTION_EVENT_SELECTION (&event) = selection_atom;
-  SELECTION_EVENT_TIME (&event) = timestamp;
-  x_handle_selection_clear ((struct input_event *) &event);
+  SELECTION_EVENT_DISPLAY (&event.sie) = display;
+  SELECTION_EVENT_SELECTION (&event.sie) = selection_atom;
+  SELECTION_EVENT_TIME (&event.sie) = timestamp;
+  x_handle_selection_clear (&event.ie);
 
   return Qt;
 }
@@ -2294,6 +2381,10 @@ DEFUN ("x-get-cut-buffer-internal", Fx_get_cut_buffer_internal,
   struct frame *sf = SELECTED_FRAME ();
 
   check_x ();
+
+  if (! FRAME_X_P (sf))
+    return Qnil;
+
   display = FRAME_X_DISPLAY (sf);
   dpyinfo = FRAME_X_DISPLAY_INFO (sf);
   window = RootWindow (display, 0); /* Cut buffers are on screen 0 */
@@ -2311,7 +2402,7 @@ DEFUN ("x-get-cut-buffer-internal", Fx_get_cut_buffer_internal,
                    Fcons (x_atom_to_symbol (display, type),
                           Fcons (make_number (format), Qnil))));
 
-  ret = (bytes ? make_string ((char *) data, bytes) : Qnil);
+  ret = (bytes ? make_unibyte_string ((char *) data, bytes) : Qnil);
   /* Use xfree, not XFree, because x_get_window_property
      calls xmalloc itself.  */
   xfree (data);
@@ -2335,6 +2426,10 @@ DEFUN ("x-store-cut-buffer-internal", Fx_store_cut_buffer_internal,
   struct frame *sf = SELECTED_FRAME ();
 
   check_x ();
+
+  if (! FRAME_X_P (sf))
+    return Qnil;
+
   display = FRAME_X_DISPLAY (sf);
   window = RootWindow (display, 0); /* Cut buffers are on screen 0 */
 
@@ -2391,8 +2486,12 @@ Positive means shift the values forward, negative means backward.  */)
   Atom props[8];
   Display *display;
   struct frame *sf = SELECTED_FRAME ();
-
+  
   check_x ();
+
+  if (! FRAME_X_P (sf))
+    return Qnil;
+
   display = FRAME_X_DISPLAY (sf);
   window = RootWindow (display, 0); /* Cut buffers are on screen 0 */
   CHECK_NUMBER (n);
@@ -2455,9 +2554,11 @@ x_check_property_data (data)
    DPY is the display use to look up X atoms.
    DATA is a Lisp list of values to be converted.
    RET is the C array that contains the converted values.  It is assumed
-   it is big enough to hol all values.
-   FORMAT is 8, 16 or 32 and gives the size in bits for each C value to
-   be stored in RET.  */
+   it is big enough to hold all values.
+   FORMAT is 8, 16 or 32 and denotes char/short/long for each C value to
+   be stored in RET.  Note that long is used for 32 even if long is more
+   than 32 bits (see man pages for XChangeProperty, XGetWindowProperty and
+   XClientMessageEvent).  */
 
 void
 x_fill_property_data (dpy, data, ret, format)
@@ -2466,10 +2567,10 @@ x_fill_property_data (dpy, data, ret, format)
      void *ret;
      int format;
 {
-  CARD32 val;
-  CARD32 *d32 = (CARD32 *) ret;
-  CARD16 *d16 = (CARD16 *) ret;
-  CARD8  *d08 = (CARD8  *) ret;
+  long val;
+  long  *d32 = (long  *) ret;
+  short *d16 = (short *) ret;
+  char  *d08 = (char  *) ret;
   Lisp_Object iter;
 
   for (iter = data; CONSP (iter); iter = XCDR (iter))
@@ -2477,24 +2578,24 @@ x_fill_property_data (dpy, data, ret, format)
       Lisp_Object o = XCAR (iter);
 
       if (INTEGERP (o))
-        val = (CARD32) XFASTINT (o);
+        val = (long) XFASTINT (o);
       else if (FLOATP (o))
-        val = (CARD32) XFLOAT (o);
+        val = (long) XFLOAT_DATA (o);
       else if (CONSP (o))
-        val = (CARD32) cons_to_long (o);
+        val = (long) cons_to_long (o);
       else if (STRINGP (o))
         {
           BLOCK_INPUT;
-          val = XInternAtom (dpy, (char *) SDATA (o), False);
+          val = (long) XInternAtom (dpy, (char *) SDATA (o), False);
           UNBLOCK_INPUT;
         }
       else
         error ("Wrong type, must be string, number or cons");
 
       if (format == 8)
-        *d08++ = (CARD8) val;
+        *d08++ = (char) val;
       else if (format == 16)
-        *d16++ = (CARD16) val;
+        *d16++ = (short) val;
       else
         *d32++ = val;
     }
@@ -2509,6 +2610,10 @@ x_fill_property_data (dpy, data, ret, format)
    be stored in RET.
    SIZE is the number of elements in DATA.
 
+   Important: When format is 32, data should contain an array of int,
+   not an array of long as the X library returns.  This makes a difference
+   when sizeof(long) != sizeof(int).
+
    Also see comment for selection_data_to_lisp_data above.  */
 
 Lisp_Object
@@ -2523,7 +2628,7 @@ x_property_data_to_lisp (f, data, type, format, size)
                                       data, size*format/8, type, format);
 }
 
-/* Get the mouse position frame relative coordinates.  */
+/* Get the mouse position in frame relative coordinates.  */
 
 static void
 mouse_position_for_drop (f, x, y)
@@ -2584,7 +2689,7 @@ If the value is 0 or the atom is not known, return the empty string.  */)
   if (INTEGERP (value))
     atom = (Atom) XUINT (value);
   else if (FLOATP (value))
-    atom = (Atom) XFLOAT (value);
+    atom = (Atom) XFLOAT_DATA (value);
   else if (CONSP (value))
     atom = (Atom) cons_to_long (value);
   else
@@ -2620,18 +2725,34 @@ x_handle_dnd_message (f, event, dpyinfo, bufp)
 {
   Lisp_Object vec;
   Lisp_Object frame;
-  unsigned long size = (8*sizeof (event->data))/event->format;
+  /* format 32 => size 5, format 16 => size 10, format 8 => size 20 */
+  unsigned long size = 160/event->format;
   int x, y;
+  unsigned char *data = (unsigned char *) event->data.b;
+  int idata[5];
 
   XSETFRAME (frame, f);
 
+  /* On a 64 bit machine, the event->data.l array members are 64 bits (long),
+     but the x_property_data_to_lisp (or rather selection_data_to_lisp_data)
+     function expects them to be of size int (i.e. 32).  So to be able to
+     use that function, put the data in the form it expects if format is 32. */
+
+  if (event->format == 32 && event->format < BITS_PER_LONG)
+    {
+      int i;
+      for (i = 0; i < 5; ++i) /* There are only 5 longs in a ClientMessage. */
+        idata[i] = (int) event->data.l[i];
+      data = (unsigned char *) idata;
+    }
+
   vec = Fmake_vector (make_number (4), Qnil);
   AREF (vec, 0) = SYMBOL_NAME (x_atom_to_symbol (FRAME_X_DISPLAY (f),
                                                  event->message_type));
   AREF (vec, 1) = frame;
   AREF (vec, 2) = make_number (event->format);
   AREF (vec, 3) = x_property_data_to_lisp (f,
-                                           event->data.b,
+                                           data,
                                            event->message_type,
                                            event->format,
                                            size);
@@ -2716,7 +2837,7 @@ are ignored.  */)
   else if (INTEGERP (dest))
     wdest = (Window) XFASTINT (dest);
   else if (FLOATP (dest))
-    wdest =  (Window) XFLOAT (dest);
+    wdest =  (Window) XFLOAT_DATA (dest);
   else if (CONSP (dest))
     {
       if (! NUMBERP (XCAR (dest)) || ! NUMBERP (XCDR (dest)))
@@ -2743,6 +2864,7 @@ are ignored.  */)
      when sending to the root window.  */
   event.xclient.window = to_root ? FRAME_OUTER_WINDOW (f) : wdest;
 
+
   memset (event.xclient.data.b, 0, sizeof (event.xclient.data.b));
   x_fill_property_data (dpyinfo->display, values, event.xclient.data.b,
                         event.xclient.format);