changeset 59975:501c2e5945ff

* xselect.c (x_reply_selection_request): Pass long array to XChangeProperty so that 64 bit longs are handeled correctly. (x_get_window_property): If format is 32 and long is bigger than 32 bits convert data from XGetWindowProperty from long array to int array. (lisp_data_to_selection_data): When the input is a vector and the format is 32, allocate a long array even if long is bigger than 32 bits. (x_fill_property_data): Use char, short and long as the man page for XChangeProperty specifies. This way the data returned is OK for both 32 and 64 bit machines. (x_handle_dnd_message): Calculate size correctly even for 64 bit machines. (Fx_send_client_event): Undo change from 2005-02-05, x_fill_property_data now handles that case.
author Jan Djärv <jan.h.d@swipnet.se>
date Mon, 07 Feb 2005 19:59:36 +0000
parents bb6a99f86b5d
children 10ab4fe55163
files src/xselect.c
diffstat 1 files changed, 72 insertions(+), 55 deletions(-) [+]
line wrap: on
line diff
--- a/src/xselect.c	Mon Feb 07 12:50:38 2005 +0000
+++ b/src/xselect.c	Mon Feb 07 19:59:36 2005 +0000
@@ -173,12 +173,6 @@
 /* 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;
-
-/* 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 ();
 
 
 
@@ -769,9 +763,17 @@
 
       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...  */
@@ -796,9 +798,9 @@
       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;
 
@@ -1523,9 +1525,38 @@
 	 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);
@@ -1970,6 +2001,7 @@
       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;
@@ -1982,7 +2014,11 @@
 	("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]
@@ -2469,8 +2505,10 @@
    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 hold all values.
-   FORMAT is 8, 16 or 32 and gives the size in bits for each C value to
-   be stored in RET.  */
+   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)
@@ -2479,10 +2517,10 @@
      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))
@@ -2490,24 +2528,24 @@
       Lisp_Object o = XCAR (iter);
 
       if (INTEGERP (o))
-        val = (CARD32) XFASTINT (o);
+        val = (long) XFASTINT (o);
       else if (FLOATP (o))
-        val = (CARD32) XFLOAT_DATA (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;
     }
@@ -2633,7 +2671,8 @@
 {
   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];
@@ -2712,8 +2751,6 @@
   struct frame *f = check_x_frame (from);
   int count;
   int to_root;
-  int idata[5];
-  void *data;
 
   CHECK_STRING (message_type);
   CHECK_NUMBER (format);
@@ -2774,30 +2811,10 @@
   event.xclient.window = to_root ? FRAME_OUTER_WINDOW (f) : wdest;
 
   
-  if (event.xclient.format == 32 && event.xclient.format < BITS_PER_LONG)
-    {
-      /* x_fill_property_data expects data to hold 32 bit values when
-         format == 32, but on a 64 bit machine long is 64 bits.
-         event.xclient.l is an array of long, so we must compensate. */
-
-      memset (idata, 0, sizeof (idata));
-      data = idata;
-    }
-  else
-    {
-      memset (event.xclient.data.b, 0, sizeof (event.xclient.data.b));
-      data = event.xclient.data.b;
-    }
-
-  x_fill_property_data (dpyinfo->display, values, data, event.xclient.format);
-
-  if (data == idata)
-    {
-      int i;
-      for (i = 0; i < 5; ++i) /* There are only 5 longs in a ClientMessage. */
-        event.xclient.data.l[i] = (long) idata[i];
-    }
-  
+  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);
+
   /* If event mask is 0 the event is sent to the client that created
      the destination window.  But if we are sending to the root window,
      there is no such client.  Then we set the event mask to 0xffff.  The