]> code.delx.au - gnu-emacs/blobdiff - src/xselect.c
(archive-l-e): New optional argument `float' means generate a float value.
[gnu-emacs] / src / xselect.c
index daae84b276cbbf05f53ece2e945c25369e5b8276..9c2c221c02190d0e80c8b2e1d50f3075fb10e081 100644 (file)
@@ -1,6 +1,6 @@
 /* X Selection processing for Emacs.
-   Copyright (C) 1993, 1994, 1995, 1996, 1997, 2000, 2001, 2003, 2004
-   Free Software Foundation.
+   Copyright (C) 1993, 1994, 1995, 1996, 1997, 2000, 2001, 2002, 2003,
+                 2004, 2005, 2006 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -16,8 +16,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 
 /* Rewritten by jwz */
@@ -55,6 +55,7 @@ static void x_decline_selection_request P_ ((struct input_event *));
 static Lisp_Object x_selection_request_lisp_error P_ ((Lisp_Object));
 static Lisp_Object queue_selection_requests_unwind P_ ((Lisp_Object));
 static Lisp_Object some_frame_on_display P_ ((struct x_display_info *));
+static Lisp_Object x_catch_errors_unwind P_ ((Lisp_Object));
 static void x_reply_selection_request P_ ((struct input_event *, int,
                                           unsigned char *, int, Atom));
 static int waiting_for_other_props_on_window P_ ((Display *, Window));
@@ -173,12 +174,6 @@ 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
@@ -408,16 +403,15 @@ x_own_selection (selection_name, selection_value)
   Time time = last_event_timestamp;
   Atom selection_atom;
   struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (sf);
-  int count;
 
   CHECK_SYMBOL (selection_name);
   selection_atom = symbol_to_x_atom (dpyinfo, display, selection_name);
 
   BLOCK_INPUT;
-  count = x_catch_errors (display);
+  x_catch_errors (display);
   XSetSelectionOwner (display, selection_atom, selecting_window, time);
   x_check_errors (display, "Can't set selection: %s");
-  x_uncatch_errors (display, count);
+  x_uncatch_errors ();
   UNBLOCK_INPUT;
 
   /* Now update the local cache */
@@ -578,7 +572,6 @@ x_decline_selection_request (event)
      struct input_event *event;
 {
   XSelectionEvent reply;
-  int count;
 
   reply.type = SelectionNotify;
   reply.display = SELECTION_EVENT_DISPLAY (event);
@@ -591,10 +584,10 @@ x_decline_selection_request (event)
   /* The reason for the error may be that the receiver has
      died in the meantime.  Handle that case.  */
   BLOCK_INPUT;
-  count = x_catch_errors (reply.display);
+  x_catch_errors (reply.display);
   XSendEvent (reply.display, reply.requestor, False, 0L, (XEvent *) &reply);
   XFlush (reply.display);
-  x_uncatch_errors (reply.display, count);
+  x_uncatch_errors ();
   UNBLOCK_INPUT;
 }
 
@@ -619,6 +612,16 @@ x_selection_request_lisp_error (ignore)
     x_decline_selection_request (x_selection_current_request);
   return Qnil;
 }
+
+static Lisp_Object
+x_catch_errors_unwind (dummy)
+     Lisp_Object dummy;
+{
+  BLOCK_INPUT;
+  x_uncatch_errors ();
+  UNBLOCK_INPUT;
+  return Qnil;
+}
 \f
 
 /* This stuff is so that INCR selections are reentrant (that is, so we can
@@ -696,7 +699,7 @@ x_reply_selection_request (event, format, data, size, type)
   int format_bytes = format/8;
   int max_bytes = SELECTION_QUANTUM (display);
   struct x_display_info *dpyinfo = x_display_info_for_display (display);
-  int count;
+  int count = SPECPDL_INDEX ();
 
   if (max_bytes > MAX_SELECTION_QUANTUM)
     max_bytes = MAX_SELECTION_QUANTUM;
@@ -711,9 +714,12 @@ x_reply_selection_request (event, format, data, size, type)
   if (reply.property == None)
     reply.property = reply.target;
 
-  /* #### XChangeProperty can generate BadAlloc, and we must handle it! */
   BLOCK_INPUT;
-  count = x_catch_errors (display);
+  /* The protected block contains wait_for_property_change, which can
+     run random lisp code (process handlers) or signal.  Therefore, we
+     put the x_uncatch_errors call in an unwind.  */
+  record_unwind_protect (x_catch_errors_unwind, Qnil);
+  x_catch_errors (display);
 
 #ifdef TRACE_SELECTION
   {
@@ -769,9 +775,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...  */
@@ -796,9 +810,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;
 
@@ -858,7 +872,8 @@ x_reply_selection_request (event, format, data, size, type)
      UNBLOCK to enter the event loop and get possible errors delivered,
      and then BLOCK again because x_uncatch_errors requires it.  */
   BLOCK_INPUT;
-  x_uncatch_errors (display, count);
+  /* This calls x_uncatch_errors.  */
+  unbind_to (count, Qnil);
   UNBLOCK_INPUT;
 }
 \f
@@ -1368,7 +1383,7 @@ x_get_foreign_selection (selection_symbol, target_type, time_stamp)
   Atom selection_atom = symbol_to_x_atom (dpyinfo, display, selection_symbol);
   Atom type_atom;
   int secs, usecs;
-  int count;
+  int count = SPECPDL_INDEX ();
   Lisp_Object frame;
 
   if (CONSP (target_type))
@@ -1390,7 +1405,11 @@ x_get_foreign_selection (selection_symbol, target_type, time_stamp)
 
   BLOCK_INPUT;
 
-  count = x_catch_errors (display);
+  /* The protected block contains wait_reading_process_output, which
+     can run random lisp code (process handlers) or signal.
+     Therefore, we put the x_uncatch_errors call in an unwind.  */
+  record_unwind_protect (x_catch_errors_unwind, Qnil);
+  x_catch_errors (display);
 
   TRACE2 ("Get selection %s, type %s",
          XGetAtomName (display, type_atom),
@@ -1428,8 +1447,10 @@ x_get_foreign_selection (selection_symbol, target_type, time_stamp)
   TRACE1 ("  Got event = %d", !NILP (XCAR (reading_selection_reply)));
 
   BLOCK_INPUT;
-  x_check_errors (display, "Cannot get selection: %s");
-  x_uncatch_errors (display, count);
+  if (x_had_errors_p (display))
+    error ("Cannot get selection");
+  /* This calls x_uncatch_errors.  */
+  unbind_to (count, Qnil);
   UNBLOCK_INPUT;
 
   if (NILP (XCAR (reading_selection_reply)))
@@ -1523,9 +1544,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);
@@ -1738,7 +1788,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).  */
 
 
 
@@ -1780,15 +1834,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;
        }
     }
@@ -1867,7 +1927,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;
@@ -1970,6 +2035,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;
@@ -1982,7 +2048,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]
@@ -1994,7 +2064,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);
@@ -2068,7 +2138,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;
 }
@@ -2138,7 +2208,10 @@ 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 ();
@@ -2166,10 +2239,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;
 }
@@ -2469,8 +2542,10 @@ x_check_property_data (data)
    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 +2554,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))
@@ -2490,24 +2565,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_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;
     }
@@ -2522,6 +2597,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
@@ -2590,9 +2669,9 @@ If the value is 0 or the atom is not known, return the empty string.  */)
   struct frame *f = check_x_frame (frame);
   char *name = 0;
   Lisp_Object ret = Qnil;
-  int count;
   Display *dpy = FRAME_X_DISPLAY (f);
   Atom atom;
+  int had_errors;
 
   if (INTEGERP (value))
     atom = (Atom) XUINT (value);
@@ -2604,15 +2683,14 @@ If the value is 0 or the atom is not known, return the empty string.  */)
     error ("Wrong type, value must be number or cons");
 
   BLOCK_INPUT;
-  count = x_catch_errors (dpy);
-
+  x_catch_errors (dpy);
   name = atom ? XGetAtomName (dpy, atom) : "";
+  had_errors = x_had_errors_p (dpy);
+  x_uncatch_errors ();
 
-  if (! x_had_errors_p (dpy))
+  if (!had_errors)
     ret = make_string (name, strlen (name));
 
-  x_uncatch_errors (dpy, count);
-
   if (atom && name) XFree (name);
   if (NILP (ret)) ret = make_string ("", 0);
 
@@ -2633,7 +2711,8 @@ 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];
@@ -2666,11 +2745,11 @@ x_handle_dnd_message (f, event, dpyinfo, bufp)
 
   mouse_position_for_drop (f, &x, &y);
   bufp->kind = DRAG_N_DROP_EVENT;
-  bufp->frame_or_window = Fcons (frame, vec);
+  bufp->frame_or_window = frame;
   bufp->timestamp = CurrentTime;
   bufp->x = make_number (x);
   bufp->y = make_number (y);
-  bufp->arg = Qnil;
+  bufp->arg = vec;
   bufp->modifiers = 0;
 
   return 1;
@@ -2710,10 +2789,7 @@ are ignored.  */)
   Lisp_Object cons;
   int size;
   struct frame *f = check_x_frame (from);
-  int count;
   int to_root;
-  int idata[5];
-  void *data;
 
   CHECK_STRING (message_type);
   CHECK_NUMBER (format);
@@ -2773,43 +2849,23 @@ are ignored.  */)
      when sending to the root window.  */
   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);
+  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 (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];
-    }
-  
   /* 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
      event then goes to clients selecting for events on the root window.  */
-  count = x_catch_errors (dpyinfo->display);
+  x_catch_errors (dpyinfo->display);
   {
     int propagate = to_root ? False : True;
     unsigned mask = to_root ? 0xffff : 0;
     XSendEvent (dpyinfo->display, wdest, propagate, mask, &event);
     XFlush (dpyinfo->display);
   }
-  x_uncatch_errors (dpyinfo->display, count);
+  x_uncatch_errors ();
   UNBLOCK_INPUT;
 
   return Qnil;
@@ -2915,7 +2971,6 @@ A value of 0 means wait as long as necessary.  This is initialized from the
   QTEXT      = intern ("TEXT");        staticpro (&QTEXT);
   QCOMPOUND_TEXT = intern ("COMPOUND_TEXT"); staticpro (&QCOMPOUND_TEXT);
   QUTF8_STRING = intern ("UTF8_STRING"); staticpro (&QUTF8_STRING);
-  QTIMESTAMP = intern ("TIMESTAMP");   staticpro (&QTIMESTAMP);
   QDELETE    = intern ("DELETE");      staticpro (&QDELETE);
   QMULTIPLE  = intern ("MULTIPLE");    staticpro (&QMULTIPLE);
   QINCR      = intern ("INCR");                staticpro (&QINCR);