* termhooks.h (TSET): Remove.
[bpt/emacs.git] / src / xselect.c
index 79ce21b..463bd6e 100644 (file)
@@ -1,6 +1,5 @@
 /* X Selection processing for Emacs.
-   Copyright (C) 1993, 1994, 1995, 1996, 1997, 2000, 2001, 2002, 2003,
-                 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+   Copyright (C) 1993-1997, 2000-2012 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -21,21 +20,22 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 /* Rewritten by jwz */
 
 #include <config.h>
+#include <limits.h>
 #include <stdio.h>      /* termhooks.h needs this */
 #include <setjmp.h>
 
 #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 */
 #include "frame.h"     /* Need this to get the X window of selected_frame */
 #include "blockinput.h"
+#include "character.h"
 #include "buffer.h"
 #include "process.h"
 #include "termhooks.h"
@@ -44,125 +44,106 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <X11/Xproto.h>
 
 struct prop_location;
-
-static Lisp_Object x_atom_to_symbol P_ ((Display *dpy, Atom atom));
-static Atom symbol_to_x_atom P_ ((struct x_display_info *, Display *,
-                                 Lisp_Object));
-static void x_own_selection P_ ((Lisp_Object, Lisp_Object));
-static Lisp_Object x_get_local_selection P_ ((Lisp_Object, Lisp_Object, int));
-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));
-static struct prop_location *expect_property_change P_ ((Display *, Window,
-                                                        Atom, int));
-static void unexpect_property_change P_ ((struct prop_location *));
-static Lisp_Object wait_for_property_change_unwind P_ ((Lisp_Object));
-static void wait_for_property_change P_ ((struct prop_location *));
-static Lisp_Object x_get_foreign_selection P_ ((Lisp_Object,
-                                                Lisp_Object,
-                                                Lisp_Object));
-static void x_get_window_property P_ ((Display *, Window, Atom,
-                                      unsigned char **, int *,
-                                      Atom *, int *, unsigned long *, int));
-static void receive_incremental_selection P_ ((Display *, Window, Atom,
-                                              Lisp_Object, unsigned,
-                                              unsigned char **, int *,
-                                              Atom *, int *, unsigned long *));
-static Lisp_Object x_get_window_property_as_lisp_data P_ ((Display *,
-                                                          Window, Atom,
-                                                          Lisp_Object, Atom));
-static Lisp_Object selection_data_to_lisp_data P_ ((Display *, unsigned char *,
-                                                   int, Atom, int));
-static void lisp_data_to_selection_data P_ ((Display *, Lisp_Object,
-                                            unsigned char **, Atom *,
-                                            unsigned *, int *, int *));
-static Lisp_Object clean_local_selection_data P_ ((Lisp_Object));
-static void initialize_cut_buffers P_ ((Display *, Window));
-
+struct selection_data;
+
+static Lisp_Object x_atom_to_symbol (Display *dpy, Atom atom);
+static Atom symbol_to_x_atom (struct x_display_info *, Lisp_Object);
+static void x_own_selection (Lisp_Object, Lisp_Object, Lisp_Object);
+static Lisp_Object x_get_local_selection (Lisp_Object, Lisp_Object, int,
+                                         struct x_display_info *);
+static void x_decline_selection_request (struct input_event *);
+static Lisp_Object x_selection_request_lisp_error (Lisp_Object);
+static Lisp_Object queue_selection_requests_unwind (Lisp_Object);
+static Lisp_Object x_catch_errors_unwind (Lisp_Object);
+static void x_reply_selection_request (struct input_event *, struct x_display_info *);
+static int x_convert_selection (struct input_event *, Lisp_Object, Lisp_Object,
+                               Atom, int, struct x_display_info *);
+static int waiting_for_other_props_on_window (Display *, Window);
+static struct prop_location *expect_property_change (Display *, Window,
+                                                     Atom, int);
+static void unexpect_property_change (struct prop_location *);
+static Lisp_Object wait_for_property_change_unwind (Lisp_Object);
+static void wait_for_property_change (struct prop_location *);
+static Lisp_Object x_get_foreign_selection (Lisp_Object, Lisp_Object,
+                                           Lisp_Object, Lisp_Object);
+static Lisp_Object x_get_window_property_as_lisp_data (Display *,
+                                                       Window, Atom,
+                                                       Lisp_Object, Atom);
+static Lisp_Object selection_data_to_lisp_data (Display *,
+                                               const unsigned char *,
+                                               ptrdiff_t, Atom, int);
+static void lisp_data_to_selection_data (Display *, Lisp_Object,
+                                         unsigned char **, Atom *,
+                                        ptrdiff_t *, int *, int *);
+static Lisp_Object clean_local_selection_data (Lisp_Object);
 
 /* Printing traces to stderr.  */
 
 #ifdef TRACE_SELECTION
 #define TRACE0(fmt) \
-  fprintf (stderr, "%d: " fmt "\n", getpid ())
+  fprintf (stderr, "%"pMd": " fmt "\n", (printmax_t) getpid ())
 #define TRACE1(fmt, a0) \
-  fprintf (stderr, "%d: " fmt "\n", getpid (), a0)
+  fprintf (stderr, "%"pMd": " fmt "\n", (printmax_t) getpid (), a0)
 #define TRACE2(fmt, a0, a1) \
-  fprintf (stderr, "%d: " fmt "\n", getpid (), a0, a1)
+  fprintf (stderr, "%"pMd": " fmt "\n", (printmax_t) getpid (), a0, a1)
 #define TRACE3(fmt, a0, a1, a2) \
-  fprintf (stderr, "%d: " fmt "\n", getpid (), a0, a1, a2)
+  fprintf (stderr, "%"pMd": " fmt "\n", (printmax_t) getpid (), a0, a1, a2)
 #else
 #define TRACE0(fmt)            (void) 0
 #define TRACE1(fmt, a0)                (void) 0
 #define TRACE2(fmt, a0, a1)    (void) 0
-#define TRACE3(fmt, a0, a1)    (void) 0
 #endif
 
 
-#define CUT_BUFFER_SUPPORT
-
-Lisp_Object QPRIMARY, QSECONDARY, QSTRING, QINTEGER, QCLIPBOARD, QTIMESTAMP,
+static Lisp_Object QSECONDARY, QSTRING, QINTEGER, QCLIPBOARD, QTIMESTAMP,
   QTEXT, QDELETE, QMULTIPLE, QINCR, QEMACS_TMP, QTARGETS, QATOM, QNULL,
-  QATOM_PAIR;
-
-Lisp_Object QCOMPOUND_TEXT;    /* This is a type of selection.  */
-Lisp_Object QUTF8_STRING;      /* This is a type of selection.  */
+  QATOM_PAIR, QCLIPBOARD_MANAGER, QSAVE_TARGETS;
 
-Lisp_Object Qcompound_text_with_extensions;
+static Lisp_Object QCOMPOUND_TEXT;     /* This is a type of selection.  */
+static Lisp_Object QUTF8_STRING;       /* This is a type of selection.  */
 
-#ifdef CUT_BUFFER_SUPPORT
-Lisp_Object QCUT_BUFFER0, QCUT_BUFFER1, QCUT_BUFFER2, QCUT_BUFFER3,
-  QCUT_BUFFER4, QCUT_BUFFER5, QCUT_BUFFER6, QCUT_BUFFER7;
-#endif
+static Lisp_Object Qcompound_text_with_extensions;
 
-static Lisp_Object Vx_lost_selection_functions;
-static Lisp_Object Vx_sent_selection_functions;
 static Lisp_Object Qforeign_selection;
+static Lisp_Object Qx_lost_selection_functions, Qx_sent_selection_functions;
+
+/* Bytes needed to represent 'long' data.  This is as per libX11; it
+   is not necessarily sizeof (long).  */
+#define X_LONG_SIZE 4
+
+/* Extreme 'short' and 'long' values suitable for libX11.  */
+#define X_SHRT_MAX 0x7fff
+#define X_SHRT_MIN (-1 - X_SHRT_MAX)
+#define X_LONG_MAX 0x7fffffff
+#define X_LONG_MIN (-1 - X_LONG_MAX)
+#define X_ULONG_MAX 0xffffffffUL
 
 /* If this is a smaller number than the max-request-size of the display,
    emacs will use INCR selection transfer when the selection is larger
    than this.  The max-request-size is usually around 64k, so if you want
    emacs to use incremental selection transfers when the selection is
    smaller than that, set this.  I added this mostly for debugging the
-   incremental transfer stuff, but it might improve server performance.  */
-#define MAX_SELECTION_QUANTUM 0xFFFFFF
-
-#define SELECTION_QUANTUM(dpy) ((XMaxRequestSize(dpy) << 2) - 100)
-
-/* The timestamp of the last input event Emacs received from the X server.  */
-/* Defined in keyboard.c.  */
-extern unsigned long last_event_timestamp;
-
-/* This is an association list whose elements are of the form
-     ( SELECTION-NAME SELECTION-VALUE SELECTION-TIMESTAMP FRAME)
-   SELECTION-NAME is a lisp symbol, whose name is the name of an X Atom.
-   SELECTION-VALUE is the value that emacs owns for that selection.
-     It may be any kind of Lisp object.
-   SELECTION-TIMESTAMP is the time at which emacs began owning this selection,
-     as a cons of two 16-bit numbers (making a 32 bit time.)
-   FRAME is the frame for which we made the selection.
-   If there is an entry in this alist, then it can be assumed that Emacs owns
-    that selection.
-   The only (eq) parts of this list that are visible from Lisp are the
-    selection-values.  */
-static Lisp_Object Vselection_alist;
-
-/* This is an alist whose CARs are selection-types (whose names are the same
-   as the names of X Atoms) and whose CDRs are the names of Lisp functions to
-   call to convert the given Emacs selection value to a string representing
-   the given selection type.  This is for Lisp-level extension of the emacs
-   selection handling.  */
-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;
+   incremental transfer stuff, but it might improve server performance.
 
+   This value cannot exceed INT_MAX / max (X_LONG_SIZE, sizeof (long))
+   because it is multiplied by X_LONG_SIZE and by sizeof (long) in
+   subscript calculations.  Similarly for PTRDIFF_MAX - 1 or SIZE_MAX
+   - 1 in place of INT_MAX.  */
+#define MAX_SELECTION_QUANTUM                                          \
+  ((int) min (0xFFFFFF, (min (INT_MAX, min (PTRDIFF_MAX, SIZE_MAX) - 1)        \
+                        / max (X_LONG_SIZE, sizeof (long)))))
+
+static int
+selection_quantum (Display *display)
+{
+  long mrs = XMaxRequestSize (display);
+  return (mrs < MAX_SELECTION_QUANTUM / X_LONG_SIZE + 25
+         ? (mrs - 25) * X_LONG_SIZE
+         : MAX_SELECTION_QUANTUM);
+}
+
+#define LOCAL_SELECTION(selection_symbol,dpyinfo)                      \
+  assq_no_quit (selection_symbol, dpyinfo->terminal->Vselection_alist)
 
 \f
 /* Define a queue to save up SELECTION_REQUEST_EVENT events for later
@@ -183,8 +164,7 @@ static int x_queue_selection_requests;
 /* Queue up an SELECTION_REQUEST_EVENT *EVENT, to be processed later.  */
 
 static void
-x_queue_event (event)
-     struct input_event *event;
+x_queue_event (struct input_event *event)
 {
   struct selection_event_queue *queue_tmp;
 
@@ -192,30 +172,25 @@ x_queue_event (event)
      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)))
+      if (!memcmp (&queue_tmp->event, event, sizeof (*event)))
        {
-         TRACE1 ("DECLINE DUP SELECTION EVENT %08lx", (unsigned long)queue_tmp);
+         TRACE1 ("DECLINE DUP SELECTION EVENT %p", queue_tmp);
          x_decline_selection_request (event);
          return;
        }
     }
 
-  queue_tmp
-    = (struct selection_event_queue *) xmalloc (sizeof (struct selection_event_queue));
-
-  if (queue_tmp != NULL)
-    {
-      TRACE1 ("QUEUE SELECTION EVENT %08lx", (unsigned long)queue_tmp);
-      queue_tmp->event = *event;
-      queue_tmp->next = selection_queue;
-      selection_queue = queue_tmp;
-    }
+  queue_tmp = xmalloc (sizeof *queue_tmp);
+  TRACE1 ("QUEUE SELECTION EVENT %p", queue_tmp);
+  queue_tmp->event = *event;
+  queue_tmp->next = selection_queue;
+  selection_queue = queue_tmp;
 }
 
 /* Start queuing SELECTION_REQUEST_EVENT events.  */
 
 static void
-x_start_queuing_selection_requests ()
+x_start_queuing_selection_requests (void)
 {
   if (x_queue_selection_requests)
     abort ();
@@ -227,7 +202,7 @@ x_start_queuing_selection_requests ()
 /* Stop queuing SELECTION_REQUEST_EVENT events.  */
 
 static void
-x_stop_queuing_selection_requests ()
+x_stop_queuing_selection_requests (void)
 {
   TRACE1 ("x_stop_queuing_selection_requests %d", x_queue_selection_requests);
   --x_queue_selection_requests;
@@ -238,10 +213,10 @@ x_stop_queuing_selection_requests ()
   while (selection_queue != NULL)
     {
       struct selection_event_queue *queue_tmp = selection_queue;
-      TRACE1 ("RESTORE SELECTION EVENT %08lx", (unsigned long)queue_tmp);
+      TRACE1 ("RESTORE SELECTION EVENT %p", queue_tmp);
       kbd_buffer_unget_event (&queue_tmp->event);
       selection_queue = queue_tmp->next;
-      xfree ((char *)queue_tmp);
+      xfree (queue_tmp);
     }
 }
 \f
@@ -250,10 +225,7 @@ x_stop_queuing_selection_requests ()
    roundtrip whenever possible.  */
 
 static Atom
-symbol_to_x_atom (dpyinfo, display, sym)
-     struct x_display_info *dpyinfo;
-     Display *display;
-     Lisp_Object sym;
+symbol_to_x_atom (struct x_display_info *dpyinfo, Lisp_Object sym)
 {
   Atom val;
   if (NILP (sym))          return 0;
@@ -273,21 +245,11 @@ symbol_to_x_atom (dpyinfo, display, sym)
   if (EQ (sym, QEMACS_TMP)) return dpyinfo->Xatom_EMACS_TMP;
   if (EQ (sym, QTARGETS))   return dpyinfo->Xatom_TARGETS;
   if (EQ (sym, QNULL))     return dpyinfo->Xatom_NULL;
-#ifdef CUT_BUFFER_SUPPORT
-  if (EQ (sym, QCUT_BUFFER0)) return XA_CUT_BUFFER0;
-  if (EQ (sym, QCUT_BUFFER1)) return XA_CUT_BUFFER1;
-  if (EQ (sym, QCUT_BUFFER2)) return XA_CUT_BUFFER2;
-  if (EQ (sym, QCUT_BUFFER3)) return XA_CUT_BUFFER3;
-  if (EQ (sym, QCUT_BUFFER4)) return XA_CUT_BUFFER4;
-  if (EQ (sym, QCUT_BUFFER5)) return XA_CUT_BUFFER5;
-  if (EQ (sym, QCUT_BUFFER6)) return XA_CUT_BUFFER6;
-  if (EQ (sym, QCUT_BUFFER7)) return XA_CUT_BUFFER7;
-#endif
   if (!SYMBOLP (sym)) abort ();
 
-  TRACE1 (" XInternAtom %s", (char *) SDATA (SYMBOL_NAME (sym)));
+  TRACE1 (" XInternAtom %s", SSDATA (SYMBOL_NAME (sym)));
   BLOCK_INPUT;
-  val = XInternAtom (display, (char *) SDATA (SYMBOL_NAME (sym)), False);
+  val = XInternAtom (dpyinfo->display, SSDATA (SYMBOL_NAME (sym)), False);
   UNBLOCK_INPUT;
   return val;
 }
@@ -297,9 +259,7 @@ symbol_to_x_atom (dpyinfo, display, sym)
    and calls to intern whenever possible.  */
 
 static Lisp_Object
-x_atom_to_symbol (dpy, atom)
-     Display *dpy;
-     Atom atom;
+x_atom_to_symbol (Display *dpy, Atom atom)
 {
   struct x_display_info *dpyinfo;
   char *str;
@@ -320,27 +280,11 @@ x_atom_to_symbol (dpy, atom)
       return QINTEGER;
     case XA_ATOM:
       return QATOM;
-#ifdef CUT_BUFFER_SUPPORT
-    case XA_CUT_BUFFER0:
-      return QCUT_BUFFER0;
-    case XA_CUT_BUFFER1:
-      return QCUT_BUFFER1;
-    case XA_CUT_BUFFER2:
-      return QCUT_BUFFER2;
-    case XA_CUT_BUFFER3:
-      return QCUT_BUFFER3;
-    case XA_CUT_BUFFER4:
-      return QCUT_BUFFER4;
-    case XA_CUT_BUFFER5:
-      return QCUT_BUFFER5;
-    case XA_CUT_BUFFER6:
-      return QCUT_BUFFER6;
-    case XA_CUT_BUFFER7:
-      return QCUT_BUFFER7;
-#endif
     }
 
   dpyinfo = x_display_info_for_display (dpy);
+  if (dpyinfo == NULL)
+    return Qnil;
   if (atom == dpyinfo->Xatom_CLIPBOARD)
     return QCLIPBOARD;
   if (atom == dpyinfo->Xatom_TIMESTAMP)
@@ -378,62 +322,51 @@ x_atom_to_symbol (dpy, atom)
 }
 \f
 /* Do protocol to assert ourself as a selection owner.
+   FRAME shall be the owner; it must be a valid X frame.
    Update the Vselection_alist so that we can reply to later requests for
    our selection.  */
 
 static void
-x_own_selection (selection_name, selection_value)
-     Lisp_Object selection_name, selection_value;
+x_own_selection (Lisp_Object selection_name, Lisp_Object selection_value,
+                Lisp_Object frame)
 {
-  struct frame *sf = SELECTED_FRAME ();
-  Window selecting_window;
-  Display *display;
-  Time time = last_event_timestamp;
-  Atom selection_atom;
-  struct x_display_info *dpyinfo;
-
-  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);
+  struct frame *f = XFRAME (frame);
+  Window selecting_window = FRAME_X_WINDOW (f);
+  struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  Display *display = dpyinfo->display;
+  Time timestamp = last_event_timestamp;
+  Atom selection_atom = symbol_to_x_atom (dpyinfo, selection_name);
 
   BLOCK_INPUT;
   x_catch_errors (display);
-  XSetSelectionOwner (display, selection_atom, selecting_window, time);
+  XSetSelectionOwner (display, selection_atom, selecting_window, timestamp);
   x_check_errors (display, "Can't set selection: %s");
   x_uncatch_errors ();
   UNBLOCK_INPUT;
 
   /* Now update the local cache */
   {
-    Lisp_Object selection_time;
     Lisp_Object selection_data;
     Lisp_Object prev_value;
 
-    selection_time = long_to_cons ((unsigned long) time);
-    selection_data = Fcons (selection_name,
-                           Fcons (selection_value,
-                                  Fcons (selection_time,
-                                         Fcons (selected_frame, Qnil))));
-    prev_value = assq_no_quit (selection_name, Vselection_alist);
+    selection_data = list4 (selection_name, selection_value,
+                           INTEGER_TO_CONS (timestamp), frame);
+    prev_value = LOCAL_SELECTION (selection_name, dpyinfo);
 
-    Vselection_alist = Fcons (selection_data, Vselection_alist);
+    tset_selection_alist
+      (dpyinfo->terminal,
+       Fcons (selection_data, dpyinfo->terminal->Vselection_alist));
 
-    /* If we already owned the selection, remove the old selection data.
-       Perhaps we should destructively modify it instead.
-       Don't use Fdelq as that may QUIT.  */
+    /* If we already owned the selection, remove the old selection
+       data.  Don't use Fdelq as that may QUIT.  */
     if (!NILP (prev_value))
       {
-       Lisp_Object rest;       /* we know it's not the CAR, so it's easy.  */
-       for (rest = Vselection_alist; CONSP (rest); rest = XCDR (rest))
+       /* We know it's not the CAR, so it's easy.  */
+       Lisp_Object rest = dpyinfo->terminal->Vselection_alist;
+       for (; CONSP (rest); rest = XCDR (rest))
          if (EQ (prev_value, Fcar (XCDR (rest))))
            {
-             XSETCDR (rest, Fcdr (XCDR (rest)));
+             XSETCDR (rest, XCDR (XCDR (rest)));
              break;
            }
       }
@@ -442,74 +375,36 @@ x_own_selection (selection_name, selection_value)
 \f
 /* Given a selection-name and desired type, look up our local copy of
    the selection value and convert it to the type.
-   The value is nil or a string.
+   Return nil, a string, a vector, a symbol, an integer, or a cons
+   that CONS_TO_INTEGER could plausibly handle.
    This function is used both for remote requests (LOCAL_REQUEST is zero)
    and for local x-get-selection-internal (LOCAL_REQUEST is nonzero).
 
    This calls random Lisp code, and may signal or gc.  */
 
 static Lisp_Object
-x_get_local_selection (selection_symbol, target_type, local_request)
-     Lisp_Object selection_symbol, target_type;
-     int local_request;
+x_get_local_selection (Lisp_Object selection_symbol, Lisp_Object target_type,
+                      int local_request, struct x_display_info *dpyinfo)
 {
   Lisp_Object local_value;
-  Lisp_Object handler_fn, value, type, check;
-  int count;
+  Lisp_Object handler_fn, value, check;
 
-  local_value = assq_no_quit (selection_symbol, Vselection_alist);
+  local_value = LOCAL_SELECTION (selection_symbol, dpyinfo);
 
   if (NILP (local_value)) return Qnil;
 
-  /* TIMESTAMP and MULTIPLE are special cases 'cause that's easiest.  */
+  /* TIMESTAMP is a special case.  */
   if (EQ (target_type, QTIMESTAMP))
     {
       handler_fn = Qnil;
       value = XCAR (XCDR (XCDR (local_value)));
     }
-#if 0
-  else if (EQ (target_type, QDELETE))
-    {
-      handler_fn = Qnil;
-      Fx_disown_selection_internal
-       (selection_symbol,
-        XCAR (XCDR (XCDR (local_value))));
-      value = QNULL;
-    }
-#endif
-
-#if 0 /* #### MULTIPLE doesn't work yet */
-  else if (CONSP (target_type)
-          && XCAR (target_type) == QMULTIPLE)
-    {
-      Lisp_Object pairs;
-      int size;
-      int i;
-      pairs = XCDR (target_type);
-      size = XVECTOR_SIZE (pairs);
-      /* If the target is MULTIPLE, then target_type looks like
-         (MULTIPLE . [[SELECTION1 TARGET1] [SELECTION2 TARGET2] ... ])
-        We modify the second element of each pair in the vector and
-        return it as [[SELECTION1 <value1>] [SELECTION2 <value2>] ... ]
-       */
-      for (i = 0; i < size; i++)
-       {
-         Lisp_Object pair;
-         pair = XVECTOR (pairs)->contents [i];
-         XVECTOR (pair)->contents [1]
-           = x_get_local_selection (XVECTOR (pair)->contents [0],
-                                    XVECTOR (pair)->contents [1],
-                                    local_request);
-       }
-      return pairs;
-    }
-#endif
   else
     {
       /* Don't allow a quit within the converter.
         When the user types C-g, he would be surprised
         if by luck it came during a converter.  */
-      count = SPECPDL_INDEX ();
+      ptrdiff_t count = SPECPDL_INDEX ();
       specbind (Qinhibit_quit, Qt);
 
       CHECK_SYMBOL (target_type);
@@ -532,7 +427,6 @@ x_get_local_selection (selection_symbol, target_type, local_request)
   check = value;
   if (CONSP (value)
       && SYMBOLP (XCAR (value)))
-    type = XCAR (value),
     check = XCDR (value);
 
   if (STRINGP (check)
@@ -541,7 +435,7 @@ x_get_local_selection (selection_symbol, target_type, local_request)
       || INTEGERP (check)
       || NILP (value))
     return value;
-  /* Check for a value that cons_to_long could handle.  */
+  /* Check for a value that CONS_TO_INTEGER could handle.  */
   else if (CONSP (check)
           && INTEGERP (XCAR (check))
           && (INTEGERP (XCDR (check))
@@ -561,8 +455,7 @@ x_get_local_selection (selection_symbol, target_type, local_request)
    meaning we were unable to do what they wanted.  */
 
 static void
-x_decline_selection_request (event)
-     struct input_event *event;
+x_decline_selection_request (struct input_event *event)
 {
   XEvent reply_base;
   XSelectionEvent *reply = &(reply_base.xselection);
@@ -593,14 +486,48 @@ static struct input_event *x_selection_current_request;
 
 static struct x_display_info *selection_request_dpyinfo;
 
+/* Raw selection data, for sending to a requestor window.  */
+
+struct selection_data
+{
+  unsigned char *data;
+  ptrdiff_t size;
+  int format;
+  Atom type;
+  int nofree;
+  Atom property;
+  /* This can be set to non-NULL during x_reply_selection_request, if
+     the selection is waiting for an INCR transfer to complete.  Don't
+     free these; that's done by unexpect_property_change.  */
+  struct prop_location *wait_object;
+  struct selection_data *next;
+};
+
+/* Linked list of the above (in support of MULTIPLE targets).  */
+
+static struct selection_data *converted_selections;
+
+/* "Data" to send a requestor for a failed MULTIPLE subtarget.  */
+static Atom conversion_fail_tag;
+
 /* Used as an unwind-protect clause so that, if a selection-converter signals
-   an error, we tell the requester that we were unable to do what they wanted
+   an error, we tell the requestor that we were unable to do what they wanted
    before we throw to top-level or go into the debugger or whatever.  */
 
 static Lisp_Object
-x_selection_request_lisp_error (ignore)
-     Lisp_Object ignore;
+x_selection_request_lisp_error (Lisp_Object ignore)
 {
+  struct selection_data *cs, *next;
+
+  for (cs = converted_selections; cs; cs = next)
+    {
+      next = cs->next;
+      if (cs->nofree == 0 && cs->data)
+       xfree (cs->data);
+      xfree (cs);
+    }
+  converted_selections = NULL;
+
   if (x_selection_current_request != 0
       && selection_request_dpyinfo->display)
     x_decline_selection_request (x_selection_current_request);
@@ -608,8 +535,7 @@ x_selection_request_lisp_error (ignore)
 }
 
 static Lisp_Object
-x_catch_errors_unwind (dummy)
-     Lisp_Object dummy;
+x_catch_errors_unwind (Lisp_Object dummy)
 {
   BLOCK_INPUT;
   x_uncatch_errors ();
@@ -635,10 +561,10 @@ struct prop_location
   struct prop_location *next;
 };
 
-static struct prop_location *expect_property_change ();
-static void wait_for_property_change ();
-static void unexpect_property_change ();
-static int waiting_for_other_props_on_window ();
+static struct prop_location *expect_property_change (Display *display, Window window, Atom property, int state);
+static void wait_for_property_change (struct prop_location *location);
+static void unexpect_property_change (struct prop_location *location);
+static int waiting_for_other_props_on_window (Display *display, Window window);
 
 static int prop_location_identifier;
 
@@ -649,60 +575,31 @@ static struct prop_location *property_change_reply_object;
 static struct prop_location *property_change_wait_list;
 
 static Lisp_Object
-queue_selection_requests_unwind (tem)
-     Lisp_Object tem;
+queue_selection_requests_unwind (Lisp_Object tem)
 {
   x_stop_queuing_selection_requests ();
   return Qnil;
 }
 
-/* Return some frame whose display info is DPYINFO.
-   Return nil if there is none.  */
-
-static Lisp_Object
-some_frame_on_display (dpyinfo)
-     struct x_display_info *dpyinfo;
-{
-  Lisp_Object list, frame;
-
-  FOR_EACH_FRAME (list, frame)
-    {
-      if (FRAME_X_P (XFRAME (frame))
-          && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
-       return frame;
-    }
-
-  return Qnil;
-}
 \f
-/* Send the reply to a selection request event EVENT.
-   TYPE is the type of selection data requested.
-   DATA and SIZE describe the data to send, already converted.
-   FORMAT is the unit-size (in bits) of the data to be transmitted.  */
+/* Send the reply to a selection request event EVENT.  */
 
 #ifdef TRACE_SELECTION
 static int x_reply_selection_request_cnt;
 #endif  /* TRACE_SELECTION */
 
 static void
-x_reply_selection_request (event, format, data, size, type)
-     struct input_event *event;
-     int format, size;
-     unsigned char *data;
-     Atom type;
+x_reply_selection_request (struct input_event *event,
+                           struct x_display_info *dpyinfo)
 {
   XEvent reply_base;
   XSelectionEvent *reply = &(reply_base.xselection);
   Display *display = SELECTION_EVENT_DISPLAY (event);
   Window window = SELECTION_EVENT_REQUESTOR (event);
-  int bytes_remaining;
-  int format_bytes = format/8;
-  int max_bytes = SELECTION_QUANTUM (display);
-  struct x_display_info *dpyinfo = x_display_info_for_display (display);
-  int count = SPECPDL_INDEX ();
-
-  if (max_bytes > MAX_SELECTION_QUANTUM)
-    max_bytes = MAX_SELECTION_QUANTUM;
+  ptrdiff_t bytes_remaining;
+  int max_bytes = selection_quantum (display);
+  ptrdiff_t count = SPECPDL_INDEX ();
+  struct selection_data *cs;
 
   reply->type = SelectionNotify;
   reply->display = display;
@@ -721,148 +618,141 @@ x_reply_selection_request (event, format, data, size, type)
   record_unwind_protect (x_catch_errors_unwind, Qnil);
   x_catch_errors (display);
 
+  /* Loop over converted selections, storing them in the requested
+     properties.  If data is large, only store the first N bytes
+     (section 2.7.2 of ICCCM).  Note that we store the data for a
+     MULTIPLE request in the opposite order; the ICCM says only that
+     the conversion itself must be done in the same order. */
+  for (cs = converted_selections; cs; cs = cs->next)
+    {
+      if (cs->property == None)
+       continue;
+
+      bytes_remaining = cs->size;
+      bytes_remaining *= cs->format >> 3;
+      if (bytes_remaining <= max_bytes)
+       {
+         /* Send all the data at once, with minimal handshaking.  */
+         TRACE1 ("Sending all %"pD"d bytes", bytes_remaining);
+         XChangeProperty (display, window, cs->property,
+                          cs->type, cs->format, PropModeReplace,
+                          cs->data, cs->size);
+       }
+      else
+       {
+         /* Send an INCR tag to initiate incremental transfer.  */
+         long value[1];
+
+         TRACE2 ("Start sending %"pD"d bytes incrementally (%s)",
+                 bytes_remaining, XGetAtomName (display, cs->property));
+         cs->wait_object
+           = expect_property_change (display, window, cs->property,
+                                     PropertyDelete);
+
+         /* XChangeProperty expects an array of long even if long is
+            more than 32 bits.  */
+         value[0] = min (bytes_remaining, X_LONG_MAX);
+         XChangeProperty (display, window, cs->property,
+                          dpyinfo->Xatom_INCR, 32, PropModeReplace,
+                          (unsigned char *) value, 1);
+         XSelectInput (display, window, PropertyChangeMask);
+       }
+    }
+
+  /* Now issue the SelectionNotify event.  */
+  XSendEvent (display, window, False, 0L, &reply_base);
+  XFlush (display);
+
 #ifdef TRACE_SELECTION
   {
     char *sel = XGetAtomName (display, reply->selection);
     char *tgt = XGetAtomName (display, reply->target);
-    TRACE3 ("%s, target %s (%d)", sel, tgt, ++x_reply_selection_request_cnt);
+    TRACE3 ("Sent SelectionNotify: %s, target %s (%d)",
+           sel, tgt, ++x_reply_selection_request_cnt);
     if (sel) XFree (sel);
     if (tgt) XFree (tgt);
   }
 #endif /* TRACE_SELECTION */
 
-  /* Store the data on the requested property.
-     If the selection is large, only store the first N bytes of it.
-   */
-  bytes_remaining = size * format_bytes;
-  if (bytes_remaining <= max_bytes)
-    {
-      /* Send all the data at once, with minimal handshaking.  */
-      TRACE1 ("Sending all %d bytes", bytes_remaining);
-      XChangeProperty (display, window, reply->property, type, format,
-                      PropModeReplace, data, size);
-      /* At this point, the selection was successfully stored; ack it.  */
-      XSendEvent (display, window, False, 0L, &reply_base);
-    }
-  else
-    {
-      /* Send an INCR selection.  */
-      struct prop_location *wait_object;
-      int had_errors;
-      Lisp_Object frame;
-
-      frame = some_frame_on_display (dpyinfo);
-
-      /* If the display no longer has frames, we can't expect
-        to get many more selection requests from it, so don't
-        bother trying to queue them.  */
-      if (!NILP (frame))
-       {
-         x_start_queuing_selection_requests ();
-
-         record_unwind_protect (queue_selection_requests_unwind,
-                                Qnil);
-       }
-
-      if (x_window_to_frame (dpyinfo, window)) /* #### debug */
-       error ("Attempt to transfer an INCR to ourself!");
-
-      TRACE2 ("Start sending %d bytes incrementally (%s)",
-             bytes_remaining,  XGetAtomName (display, reply->property));
-      wait_object = expect_property_change (display, window, reply->property,
-                                           PropertyDelete);
-
-      TRACE1 ("Set %s to number of bytes to send",
-             XGetAtomName (display, reply->property));
+  /* Finish sending the rest of each of the INCR values.  This should
+     be improved; there's a chance of deadlock if more than one
+     subtarget in a MULTIPLE selection requires an INCR transfer, and
+     the requestor and Emacs loop waiting on different transfers.  */
+  for (cs = converted_selections; cs; cs = cs->next)
+    if (cs->wait_object)
       {
-        /* 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);
-      }
+       int format_bytes = cs->format / 8;
+       int had_errors = x_had_errors_p (display);
+       UNBLOCK_INPUT;
 
-      XSelectInput (display, window, PropertyChangeMask);
-
-      /* Tell 'em the INCR data is there...  */
-      TRACE0 ("Send SelectionNotify event");
-      XSendEvent (display, window, False, 0L, &reply_base);
-      XFlush (display);
+       bytes_remaining = cs->size;
+       bytes_remaining *= format_bytes;
 
-      had_errors = x_had_errors_p (display);
-      UNBLOCK_INPUT;
-
-      /* First, wait for the requester to ack by deleting the property.
-        This can run random lisp code (process handlers) or signal.  */
-      if (! had_errors)
-       {
-         TRACE1 ("Waiting for ACK (deletion of %s)",
-                 XGetAtomName (display, reply->property));
-         wait_for_property_change (wait_object);
-       }
-      else
-       unexpect_property_change (wait_object);
-
-      TRACE0 ("Got ACK");
-      while (bytes_remaining)
-       {
-          int i = ((bytes_remaining < max_bytes)
-                   ? bytes_remaining
-                   : max_bytes) / format_bytes;
-
-         BLOCK_INPUT;
-
-         wait_object
-           = expect_property_change (display, window, reply->property,
-                                     PropertyDelete);
-
-         TRACE1 ("Sending increment of %d elements", i);
-         TRACE1 ("Set %s to increment data",
-                 XGetAtomName (display, reply->property));
+       /* Wait for the requestor to ack by deleting the property.
+          This can run Lisp code (process handlers) or signal.  */
+       if (! had_errors)
+         {
+           TRACE1 ("Waiting for ACK (deletion of %s)",
+                   XGetAtomName (display, cs->property));
+           wait_for_property_change (cs->wait_object);
+         }
+       else
+         unexpect_property_change (cs->wait_object);
 
-         /* Append the next chunk of data to the property.  */
-         XChangeProperty (display, window, reply->property, type, format,
-                          PropModeAppend, data, i);
-         bytes_remaining -= i * format_bytes;
-         if (format == 32)
-           data += i * sizeof (long);
-         else
-           data += i * format_bytes;
-         XFlush (display);
-         had_errors = x_had_errors_p (display);
-         UNBLOCK_INPUT;
+       while (bytes_remaining)
+         {
+           int i = ((bytes_remaining < max_bytes)
+                    ? bytes_remaining
+                    : max_bytes) / format_bytes;
+           BLOCK_INPUT;
+
+           cs->wait_object
+             = expect_property_change (display, window, cs->property,
+                                       PropertyDelete);
+
+           TRACE1 ("Sending increment of %d elements", i);
+           TRACE1 ("Set %s to increment data",
+                   XGetAtomName (display, cs->property));
+
+           /* Append the next chunk of data to the property.  */
+           XChangeProperty (display, window, cs->property,
+                            cs->type, cs->format, PropModeAppend,
+                            cs->data, i);
+           bytes_remaining -= i * format_bytes;
+           cs->data += i * ((cs->format == 32) ? sizeof (long)
+                            : format_bytes);
+           XFlush (display);
+           had_errors = x_had_errors_p (display);
+           UNBLOCK_INPUT;
 
-         if (had_errors)
-           break;
+           if (had_errors) break;
 
-         /* Now wait for the requester to ack this chunk by deleting the
-            property.  This can run random lisp code or signal.  */
-         TRACE1 ("Waiting for increment ACK (deletion of %s)",
-                 XGetAtomName (display, reply->property));
-         wait_for_property_change (wait_object);
-       }
+           /* Wait for the requestor to ack this chunk by deleting
+              the property.  This can run Lisp code or signal.  */
+           TRACE1 ("Waiting for increment ACK (deletion of %s)",
+                   XGetAtomName (display, cs->property));
+           wait_for_property_change (cs->wait_object);
+         }
 
-      /* Now write a zero-length chunk to the property to tell the
-        requester that we're done.  */
-      BLOCK_INPUT;
-      if (! waiting_for_other_props_on_window (display, window))
-       XSelectInput (display, window, 0L);
-
-      TRACE1 ("Set %s to a 0-length chunk to indicate EOF",
-             XGetAtomName (display, reply->property));
-      XChangeProperty (display, window, reply->property, type, format,
-                      PropModeReplace, data, 0);
-      TRACE0 ("Done sending incrementally");
-    }
+       /* Now write a zero-length chunk to the property to tell the
+          requestor that we're done.  */
+       BLOCK_INPUT;
+       if (! waiting_for_other_props_on_window (display, window))
+         XSelectInput (display, window, 0L);
+
+       TRACE1 ("Set %s to a 0-length chunk to indicate EOF",
+               XGetAtomName (display, cs->property));
+       XChangeProperty (display, window, cs->property,
+                        cs->type, cs->format, PropModeReplace,
+                        cs->data, 0);
+       TRACE0 ("Done sending incrementally");
+      }
 
   /* rms, 2003-01-03: I think I have fixed this bug.  */
   /* The window we're communicating with may have been deleted
      in the meantime (that's a real situation from a bug report).
      In this case, there may be events in the event queue still
-     refering to the deleted window, and we'll get a BadWindow error
+     referring to the deleted window, and we'll get a BadWindow error
      in XTread_socket when processing the events.  I don't have
      an idea how to fix that.  gerd, 2001-01-98.   */
   /* 2004-09-10: XSync and UNBLOCK so that possible protocol errors are
@@ -883,120 +773,172 @@ x_reply_selection_request (event, format, data, size, type)
    This is called from keyboard.c when such an event is found in the queue.  */
 
 static void
-x_handle_selection_request (event)
-     struct input_event *event;
+x_handle_selection_request (struct input_event *event)
 {
-  struct gcpro gcpro1, gcpro2, gcpro3;
-  Lisp_Object local_selection_data;
-  Lisp_Object selection_symbol;
-  Lisp_Object target_symbol;
-  Lisp_Object converted_selection;
+  struct gcpro gcpro1, gcpro2;
   Time local_selection_time;
-  Lisp_Object successful_p;
-  int count;
-  struct x_display_info *dpyinfo
-    = x_display_info_for_display (SELECTION_EVENT_DISPLAY (event));
-
-  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;
-  converted_selection = Qnil;
-  successful_p = Qnil;
-
-  GCPRO3 (local_selection_data, converted_selection, target_symbol);
-
-  selection_symbol = x_atom_to_symbol (SELECTION_EVENT_DISPLAY (event),
-                                      SELECTION_EVENT_SELECTION (event));
+  Display *display = SELECTION_EVENT_DISPLAY (event);
+  struct x_display_info *dpyinfo = x_display_info_for_display (display);
+  Atom selection = SELECTION_EVENT_SELECTION (event);
+  Lisp_Object selection_symbol = x_atom_to_symbol (display, selection);
+  Atom target = SELECTION_EVENT_TARGET (event);
+  Lisp_Object target_symbol = x_atom_to_symbol (display, target);
+  Atom property = SELECTION_EVENT_PROPERTY (event);
+  Lisp_Object local_selection_data;
+  int success = 0;
+  ptrdiff_t count = SPECPDL_INDEX ();
+  GCPRO2 (local_selection_data, target_symbol);
 
-  local_selection_data = assq_no_quit (selection_symbol, Vselection_alist);
+  if (!dpyinfo) goto DONE;
 
-  if (NILP (local_selection_data))
-    {
-      /* Someone asked for the selection, but we don't have it any more.
-       */
-      x_decline_selection_request (event);
-      goto DONE;
-    }
+  local_selection_data = LOCAL_SELECTION (selection_symbol, dpyinfo);
 
-  local_selection_time = (Time)
-    cons_to_long (XCAR (XCDR (XCDR (local_selection_data))));
+  /* Decline if we don't own any selections.  */
+  if (NILP (local_selection_data)) goto DONE;
 
+  /* Decline requests issued prior to our acquiring the selection.  */
+  CONS_TO_INTEGER (XCAR (XCDR (XCDR (local_selection_data))),
+                  Time, local_selection_time);
   if (SELECTION_EVENT_TIME (event) != CurrentTime
       && local_selection_time > SELECTION_EVENT_TIME (event))
-    {
-      /* Someone asked for the selection, and we have one, but not the one
-        they're looking for.
-       */
-      x_decline_selection_request (event);
-      goto DONE;
-    }
+    goto DONE;
 
   x_selection_current_request = event;
-  count = SPECPDL_INDEX ();
   selection_request_dpyinfo = dpyinfo;
   record_unwind_protect (x_selection_request_lisp_error, Qnil);
 
-  target_symbol = x_atom_to_symbol (SELECTION_EVENT_DISPLAY (event),
-                                   SELECTION_EVENT_TARGET (event));
-
-#if 0 /* #### MULTIPLE doesn't work yet */
-  if (EQ (target_symbol, QMULTIPLE))
-    target_symbol = fetch_multiple_target (event);
-#endif
-
-  /* Convert lisp objects back into binary data */
+  /* We might be able to handle nested x_handle_selection_requests,
+     but this is difficult to test, and seems unimportant.  */
+  x_start_queuing_selection_requests ();
+  record_unwind_protect (queue_selection_requests_unwind, Qnil);
 
-  converted_selection
-    = x_get_local_selection (selection_symbol, target_symbol, 0);
+  TRACE2 ("x_handle_selection_request: selection=%s, target=%s",
+         SDATA (SYMBOL_NAME (selection_symbol)),
+         SDATA (SYMBOL_NAME (target_symbol)));
 
-  if (! NILP (converted_selection))
+  if (EQ (target_symbol, QMULTIPLE))
     {
-      unsigned char *data;
-      unsigned int size;
-      int format;
-      Atom type;
-      int nofree;
-
-      if (CONSP (converted_selection) && NILP (XCDR (converted_selection)))
-        {
-          x_decline_selection_request (event);
-          goto DONE2;
-        }
+      /* For MULTIPLE targets, the event property names a list of atom
+        pairs; the first atom names a target and the second names a
+        non-None property.  */
+      Window requestor = SELECTION_EVENT_REQUESTOR (event);
+      Lisp_Object multprop;
+      ptrdiff_t j, nselections;
+
+      if (property == None) goto DONE;
+      multprop
+       = x_get_window_property_as_lisp_data (display, requestor, property,
+                                             QMULTIPLE, selection);
+
+      if (!VECTORP (multprop) || ASIZE (multprop) % 2)
+       goto DONE;
+
+      nselections = ASIZE (multprop) / 2;
+      /* Perform conversions.  This can signal.  */
+      for (j = 0; j < nselections; j++)
+       {
+         Lisp_Object subtarget = AREF (multprop, 2*j);
+         Atom subproperty = symbol_to_x_atom (dpyinfo,
+                                              AREF (multprop, 2*j+1));
 
-      lisp_data_to_selection_data (SELECTION_EVENT_DISPLAY (event),
-                                  converted_selection,
-                                  &data, &type, &size, &format, &nofree);
+         if (subproperty != None)
+           x_convert_selection (event, selection_symbol, subtarget,
+                                subproperty, 1, dpyinfo);
+       }
+      success = 1;
+    }
+  else
+    {
+      if (property == None)
+       property = SELECTION_EVENT_TARGET (event);
+      success = x_convert_selection (event, selection_symbol,
+                                    target_symbol, property,
+                                    0, dpyinfo);
+    }
 
-      x_reply_selection_request (event, format, data, size, type);
-      successful_p = Qt;
+ DONE:
 
-      /* Indicate we have successfully processed this event.  */
-      x_selection_current_request = 0;
+  if (success)
+    x_reply_selection_request (event, dpyinfo);
+  else
+    x_decline_selection_request (event);
+  x_selection_current_request = 0;
 
-      /* Use xfree, not XFree, because lisp_data_to_selection_data
-        calls xmalloc itself.  */
-      if (!nofree)
-       xfree (data);
+  /* Run the `x-sent-selection-functions' abnormal hook.  */
+  if (!NILP (Vx_sent_selection_functions)
+      && !EQ (Vx_sent_selection_functions, Qunbound))
+    {
+      Lisp_Object args[4];
+      args[0] = Qx_sent_selection_functions;
+      args[1] = selection_symbol;
+      args[2] = target_symbol;
+      args[3] = success ? Qt : Qnil;
+      Frun_hook_with_args (4, args);
     }
 
- DONE2:
   unbind_to (count, Qnil);
+  UNGCPRO;
+}
 
- DONE:
+/* Perform the requested selection conversion, and write the data to
+   the converted_selections linked list, where it can be accessed by
+   x_reply_selection_request.  If FOR_MULTIPLE is non-zero, write out
+   the data even if conversion fails, using conversion_fail_tag.
 
-  /* Let random lisp code notice that the selection has been asked for.  */
-  {
-    Lisp_Object rest;
-    rest = Vx_sent_selection_functions;
-    if (!EQ (rest, Qunbound))
-      for (; CONSP (rest); rest = Fcdr (rest))
-       call3 (Fcar (rest), selection_symbol, target_symbol, successful_p);
-  }
+   Return 0 if the selection failed to convert, 1 otherwise.  */
+
+static int
+x_convert_selection (struct input_event *event, Lisp_Object selection_symbol,
+                    Lisp_Object target_symbol, Atom property,
+                    int for_multiple, struct x_display_info *dpyinfo)
+{
+  struct gcpro gcpro1;
+  Lisp_Object lisp_selection;
+  struct selection_data *cs;
+  GCPRO1 (lisp_selection);
+
+  lisp_selection
+    = x_get_local_selection (selection_symbol, target_symbol,
+                            0, dpyinfo);
+
+  /* A nil return value means we can't perform the conversion.  */
+  if (NILP (lisp_selection)
+      || (CONSP (lisp_selection) && NILP (XCDR (lisp_selection))))
+    {
+      if (for_multiple)
+       {
+         cs = xmalloc (sizeof *cs);
+         cs->data = (unsigned char *) &conversion_fail_tag;
+         cs->size = 1;
+         cs->format = 32;
+         cs->type = XA_ATOM;
+         cs->nofree = 1;
+         cs->property = property;
+         cs->wait_object = NULL;
+         cs->next = converted_selections;
+         converted_selections = cs;
+       }
 
+      UNGCPRO;
+      return 0;
+    }
+
+  /* Otherwise, record the converted selection to binary.  */
+  cs = xmalloc (sizeof *cs);
+  cs->data = NULL;
+  cs->nofree = 1;
+  cs->property = property;
+  cs->wait_object = NULL;
+  cs->next = converted_selections;
+  converted_selections = cs;
+  lisp_data_to_selection_data (SELECTION_EVENT_DISPLAY (event),
+                              lisp_selection,
+                              &(cs->data), &(cs->type),
+                              &(cs->size), &(cs->format),
+                              &(cs->nofree));
   UNGCPRO;
+  return 1;
 }
 \f
 /* Handle a SelectionClear event EVENT, which indicates that some
@@ -1004,8 +946,7 @@ x_handle_selection_request (event)
    This is called from keyboard.c when such an event is found in the queue.  */
 
 static void
-x_handle_selection_clear (event)
-     struct input_event *event;
+x_handle_selection_clear (struct input_event *event)
 {
   Display *display = SELECTION_EVENT_DISPLAY (event);
   Atom selection = SELECTION_EVENT_SELECTION (event);
@@ -1014,93 +955,65 @@ x_handle_selection_clear (event)
   Lisp_Object selection_symbol, local_selection_data;
   Time local_selection_time;
   struct x_display_info *dpyinfo = x_display_info_for_display (display);
-  struct x_display_info *t_dpyinfo;
+  Lisp_Object Vselection_alist;
 
   TRACE0 ("x_handle_selection_clear");
 
-  /* If the new selection owner is also Emacs,
-     don't clear the new selection.  */
-  BLOCK_INPUT;
-  /* Check each display on the same terminal,
-     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->terminal->kboard == dpyinfo->terminal->kboard)
-      {
-       Window owner_window
-         = XGetSelectionOwner (t_dpyinfo->display, selection);
-       if (x_window_to_frame (t_dpyinfo, owner_window) != 0)
-         {
-           UNBLOCK_INPUT;
-           return;
-         }
-      }
-  UNBLOCK_INPUT;
-  
-  selection_symbol = x_atom_to_symbol (display, selection);
+  if (!dpyinfo) return;
 
-  local_selection_data = assq_no_quit (selection_symbol, Vselection_alist);
+  selection_symbol = x_atom_to_symbol (display, selection);
+  local_selection_data = LOCAL_SELECTION (selection_symbol, dpyinfo);
 
   /* Well, we already believe that we don't own it, so that's just fine.  */
   if (NILP (local_selection_data)) return;
 
-  local_selection_time = (Time)
-    cons_to_long (XCAR (XCDR (XCDR (local_selection_data))));
-
-  /* This SelectionClear is for a selection that we no longer own, so we can
-     disregard it.  (That is, we have reasserted the selection since this
-     request was generated.)  */
+  CONS_TO_INTEGER (XCAR (XCDR (XCDR (local_selection_data))),
+                  Time, local_selection_time);
 
+  /* We have reasserted the selection since this SelectionClear was
+     generated, so we can disregard it.  */
   if (changed_owner_time != CurrentTime
       && local_selection_time > changed_owner_time)
     return;
 
-  /* Otherwise, we're really honest and truly being told to drop it.
-     Don't use Fdelq as that may QUIT;.  */
-
-  if (EQ (local_selection_data, Fcar (Vselection_alist)))
-    Vselection_alist = Fcdr (Vselection_alist);
+  /* Otherwise, really clear.  Don't use Fdelq as that may QUIT;.  */
+  Vselection_alist = dpyinfo->terminal->Vselection_alist;
+  if (EQ (local_selection_data, CAR (Vselection_alist)))
+    Vselection_alist = XCDR (Vselection_alist);
   else
     {
       Lisp_Object rest;
       for (rest = Vselection_alist; CONSP (rest); rest = XCDR (rest))
-       if (EQ (local_selection_data, Fcar (XCDR (rest))))
+       if (EQ (local_selection_data, CAR (XCDR (rest))))
          {
-           XSETCDR (rest, Fcdr (XCDR (rest)));
+           XSETCDR (rest, XCDR (XCDR (rest)));
            break;
          }
     }
+  tset_selection_alist (dpyinfo->terminal, Vselection_alist);
 
-  /* Let random lisp code notice that the selection has been stolen.  */
-
+  /* Run the `x-lost-selection-functions' abnormal hook.  */
   {
-    Lisp_Object rest;
-    rest = Vx_lost_selection_functions;
-    if (!EQ (rest, Qunbound))
-      {
-       for (; CONSP (rest); rest = Fcdr (rest))
-         call1 (Fcar (rest), selection_symbol);
-       prepare_menu_bars ();
-       redisplay_preserve_echo_area (20);
-      }
+    Lisp_Object args[2];
+    args[0] = Qx_lost_selection_functions;
+    args[1] = selection_symbol;
+    Frun_hook_with_args (2, args);
   }
+
+  prepare_menu_bars ();
+  redisplay_preserve_echo_area (20);
 }
 
 void
-x_handle_selection_event (event)
-     struct input_event *event;
+x_handle_selection_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
+  if (event->kind != SELECTION_REQUEST_EVENT)
     x_handle_selection_clear (event);
+  else if (x_queue_selection_requests)
+    x_queue_event (event);
+  else
+    x_handle_selection_request (event);
 }
 
 
@@ -1108,60 +1021,38 @@ x_handle_selection_event (event)
    We do this when about to delete a frame.  */
 
 void
-x_clear_frame_selections (f)
-     FRAME_PTR f;
+x_clear_frame_selections (FRAME_PTR f)
 {
   Lisp_Object frame;
   Lisp_Object rest;
+  struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  struct terminal *t = dpyinfo->terminal;
 
   XSETFRAME (frame, f);
 
-  /* Otherwise, we're really honest and truly being told to drop it.
-     Don't use Fdelq as that may QUIT;.  */
-
   /* Delete elements from the beginning of Vselection_alist.  */
-  while (!NILP (Vselection_alist)
-        && EQ (frame, Fcar (Fcdr (Fcdr (Fcdr (Fcar (Vselection_alist)))))))
+  while (CONSP (t->Vselection_alist)
+        && EQ (frame, XCAR (XCDR (XCDR (XCDR (XCAR (t->Vselection_alist)))))))
     {
-      /* Let random Lisp code notice that the selection has been stolen.  */
-      Lisp_Object hooks, selection_symbol;
-
-      hooks = Vx_lost_selection_functions;
-      selection_symbol = Fcar (Fcar (Vselection_alist));
-
-      if (!EQ (hooks, Qunbound))
-       {
-         for (; CONSP (hooks); hooks = Fcdr (hooks))
-           call1 (Fcar (hooks), selection_symbol);
-#if 0 /* This can crash when deleting a frame
-        from x_connection_closed.  Anyway, it seems unnecessary;
-        something else should cause a redisplay.  */
-         redisplay_preserve_echo_area (21);
-#endif
-       }
+      /* Run the `x-lost-selection-functions' abnormal hook.  */
+      Lisp_Object args[2];
+      args[0] = Qx_lost_selection_functions;
+      args[1] = Fcar (Fcar (t->Vselection_alist));
+      Frun_hook_with_args (2, args);
 
-      Vselection_alist = Fcdr (Vselection_alist);
+      tset_selection_alist (t, XCDR (t->Vselection_alist));
     }
 
   /* Delete elements after the beginning of Vselection_alist.  */
-  for (rest = Vselection_alist; CONSP (rest); rest = XCDR (rest))
-    if (EQ (frame, Fcar (Fcdr (Fcdr (Fcdr (Fcar (XCDR (rest))))))))
+  for (rest = t->Vselection_alist; CONSP (rest); rest = XCDR (rest))
+    if (CONSP (XCDR (rest))
+       && EQ (frame, XCAR (XCDR (XCDR (XCDR (XCAR (XCDR (rest))))))))
       {
-       /* Let random Lisp code notice that the selection has been stolen.  */
-       Lisp_Object hooks, selection_symbol;
-
-       hooks = Vx_lost_selection_functions;
-       selection_symbol = Fcar (Fcar (XCDR (rest)));
-
-       if (!EQ (hooks, Qunbound))
-         {
-           for (; CONSP (hooks); hooks = Fcdr (hooks))
-             call1 (Fcar (hooks), selection_symbol);
-#if 0 /* See above */
-           redisplay_preserve_echo_area (22);
-#endif
-         }
-       XSETCDR (rest, Fcdr (XCDR (rest)));
+       Lisp_Object args[2];
+       args[0] = Qx_lost_selection_functions;
+       args[1] = XCAR (XCAR (XCDR (rest)));
+       Frun_hook_with_args (2, args);
+       XSETCDR (rest, XCDR (XCDR (rest)));
        break;
       }
 }
@@ -1170,9 +1061,7 @@ x_clear_frame_selections (f)
    are on the list of what we are waiting for.  */
 
 static int
-waiting_for_other_props_on_window (display, window)
-     Display *display;
-     Window window;
+waiting_for_other_props_on_window (Display *display, Window window)
 {
   struct prop_location *rest = property_change_wait_list;
   while (rest)
@@ -1189,13 +1078,10 @@ waiting_for_other_props_on_window (display, window)
    this awaited property change.  */
 
 static struct prop_location *
-expect_property_change (display, window, property, state)
-     Display *display;
-     Window window;
-     Atom property;
-     int state;
+expect_property_change (Display *display, Window window,
+                        Atom property, int state)
 {
-  struct prop_location *pl = (struct prop_location *) xmalloc (sizeof *pl);
+  struct prop_location *pl = xmalloc (sizeof *pl);
   pl->identifier = ++prop_location_identifier;
   pl->display = display;
   pl->window = window;
@@ -1211,8 +1097,7 @@ expect_property_change (display, window, property, state)
    IDENTIFIER is the number that uniquely identifies the entry.  */
 
 static void
-unexpect_property_change (location)
-     struct prop_location *location;
+unexpect_property_change (struct prop_location *location)
 {
   struct prop_location *prev = 0, *rest = property_change_wait_list;
   while (rest)
@@ -1234,8 +1119,7 @@ unexpect_property_change (location)
 /* Remove the property change expectation element for IDENTIFIER.  */
 
 static Lisp_Object
-wait_for_property_change_unwind (loc)
-     Lisp_Object loc;
+wait_for_property_change_unwind (Lisp_Object loc)
 {
   struct prop_location *location = XSAVE_VALUE (loc)->pointer;
 
@@ -1249,11 +1133,9 @@ wait_for_property_change_unwind (loc)
    IDENTIFIER should be the value that expect_property_change returned.  */
 
 static void
-wait_for_property_change (location)
-     struct prop_location *location;
+wait_for_property_change (struct prop_location *location)
 {
-  int secs, usecs;
-  int count = SPECPDL_INDEX ();
+  ptrdiff_t count = SPECPDL_INDEX ();
 
   if (property_change_reply_object)
     abort ();
@@ -1269,10 +1151,11 @@ wait_for_property_change (location)
      property_change_reply, because property_change_reply_object says so.  */
   if (! location->arrived)
     {
-      secs = x_selection_timeout / 1000;
-      usecs = (x_selection_timeout % 1000) * 1000;
-      TRACE2 ("  Waiting %d secs, %d usecs", secs, usecs);
-      wait_reading_process_output (secs, usecs, 0, 0,
+      EMACS_INT timeout = max (0, x_selection_timeout);
+      EMACS_INT secs = timeout / 1000;
+      int nsecs = (timeout % 1000) * 1000000;
+      TRACE2 ("  Waiting %"pI"d secs, %d nsecs", secs, nsecs);
+      wait_reading_process_output (secs, nsecs, 0, 0,
                                   property_change_reply, NULL, 0);
 
       if (NILP (XCAR (property_change_reply)))
@@ -1288,12 +1171,11 @@ wait_for_property_change (location)
 /* Called from XTread_socket in response to a PropertyNotify event.  */
 
 void
-x_handle_property_notify (event)
-     XPropertyEvent *event;
+x_handle_property_notify (XPropertyEvent *event)
 {
-  struct prop_location *prev = 0, *rest = property_change_wait_list;
+  struct prop_location *rest;
 
-  while (rest)
+  for (rest = property_change_wait_list; rest; rest = rest->next)
     {
       if (!rest->arrived
          && rest->property == event->atom
@@ -1314,163 +1196,79 @@ x_handle_property_notify (event)
 
          return;
        }
-
-      prev = rest;
-      rest = rest->next;
     }
 }
 
 
 \f
-#if 0 /* #### MULTIPLE doesn't work yet */
-
-static Lisp_Object
-fetch_multiple_target (event)
-     XSelectionRequestEvent *event;
-{
-  Display *display = event->display;
-  Window window = event->requestor;
-  Atom target = event->target;
-  Atom selection_atom = event->selection;
-  int result;
-
-  return
-    Fcons (QMULTIPLE,
-          x_get_window_property_as_lisp_data (display, window, target,
-                                              QMULTIPLE, selection_atom));
-}
-
-static Lisp_Object
-copy_multiple_data (obj)
-     Lisp_Object obj;
-{
-  Lisp_Object vec;
-  int i;
-  int size;
-  if (CONSP (obj))
-    return Fcons (XCAR (obj), copy_multiple_data (XCDR (obj)));
-
-  CHECK_VECTOR (obj);
-  vec = Fmake_vector (size = XVECTOR_SIZE (obj), Qnil);
-  for (i = 0; i < size; i++)
-    {
-      Lisp_Object vec2 = XVECTOR (obj)->contents [i];
-      CHECK_VECTOR (vec2);
-      if (XVECTOR_SIZE (vec2) != 2)
-       /* ??? Confusing error message */
-       signal_error ("Vectors must be of length 2", vec2);
-      XVECTOR (vec)->contents [i] = Fmake_vector (2, Qnil);
-      XVECTOR (XVECTOR (vec)->contents [i])->contents [0]
-       = XVECTOR (vec2)->contents [0];
-      XVECTOR (XVECTOR (vec)->contents [i])->contents [1]
-       = XVECTOR (vec2)->contents [1];
-    }
-  return vec;
-}
-
-#endif
-
-\f
 /* Variables for communication with x_handle_selection_notify.  */
 static Atom reading_which_selection;
 static Lisp_Object reading_selection_reply;
 static Window reading_selection_window;
 
 /* Do protocol to read selection-data from the server.
-   Converts this to Lisp data and returns it.  */
+   Converts this to Lisp data and returns it.
+   FRAME is the frame whose X window shall request the selection.  */
 
 static Lisp_Object
-x_get_foreign_selection (selection_symbol, target_type, time_stamp)
-     Lisp_Object selection_symbol, target_type, time_stamp;
+x_get_foreign_selection (Lisp_Object selection_symbol, Lisp_Object target_type,
+                        Lisp_Object time_stamp, Lisp_Object frame)
 {
-  struct frame *sf = SELECTED_FRAME ();
-  Window requestor_window;
-  Display *display;
-  struct x_display_info *dpyinfo;
+  struct frame *f = XFRAME (frame);
+  struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  Display *display = dpyinfo->display;
+  Window requestor_window = FRAME_X_WINDOW (f);
   Time requestor_time = last_event_timestamp;
-  Atom target_property;
-  Atom selection_atom;
-  Atom type_atom;
-  int secs, usecs;
-  int count = SPECPDL_INDEX ();
-  Lisp_Object frame;
-
-  if (! FRAME_X_P (sf))
+  Atom target_property = dpyinfo->Xatom_EMACS_TMP;
+  Atom selection_atom = symbol_to_x_atom (dpyinfo, selection_symbol);
+  Atom type_atom = (CONSP (target_type)
+                   ? symbol_to_x_atom (dpyinfo, XCAR (target_type))
+                   : symbol_to_x_atom (dpyinfo, target_type));
+  EMACS_INT timeout, secs;
+  int nsecs;
+
+  if (!FRAME_LIVE_P (f))
     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
-    type_atom = symbol_to_x_atom (dpyinfo, display, target_type);
-
   if (! NILP (time_stamp))
-    {
-      if (CONSP (time_stamp))
-        requestor_time = (Time) cons_to_long (time_stamp);
-      else if (INTEGERP (time_stamp))
-        requestor_time = (Time) XUINT (time_stamp);
-      else if (FLOATP (time_stamp))
-        requestor_time = (Time) XFLOAT_DATA (time_stamp);
-      else
-        error ("TIME_STAMP must be cons or number");
-    }
+    CONS_TO_INTEGER (time_stamp, Time, requestor_time);
 
   BLOCK_INPUT;
-
-  /* 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),
          XGetAtomName (display, target_property));
 
+  x_catch_errors (display);
   XConvertSelection (display, selection_atom, type_atom, target_property,
                     requestor_window, requestor_time);
-  XFlush (display);
+  x_check_errors (display, "Can't convert selection: %s");
+  x_uncatch_errors ();
 
   /* Prepare to block until the reply has been read.  */
   reading_selection_window = requestor_window;
   reading_which_selection = selection_atom;
   XSETCAR (reading_selection_reply, Qnil);
 
-  frame = some_frame_on_display (dpyinfo);
-
-  /* If the display no longer has frames, we can't expect
-     to get many more selection requests from it, so don't
-     bother trying to queue them.  */
-  if (!NILP (frame))
-    {
-      x_start_queuing_selection_requests ();
+  /* It should not be necessary to stop handling selection requests
+     during this time.  In fact, the SAVE_TARGETS mechanism requires
+     us to handle a clipboard manager's requests before it returns
+     SelectionNotify. */
+#if 0
+  x_start_queuing_selection_requests ();
+  record_unwind_protect (queue_selection_requests_unwind, Qnil);
+#endif
 
-      record_unwind_protect (queue_selection_requests_unwind,
-                            Qnil);
-    }
   UNBLOCK_INPUT;
 
   /* This allows quits.  Also, don't wait forever.  */
-  secs = x_selection_timeout / 1000;
-  usecs = (x_selection_timeout % 1000) * 1000;
-  TRACE1 ("  Start waiting %d secs for SelectionNotify", secs);
-  wait_reading_process_output (secs, usecs, 0, 0,
+  timeout = max (0, x_selection_timeout);
+  secs = timeout / 1000;
+  nsecs = (timeout % 1000) * 1000000;
+  TRACE1 ("  Start waiting %"pI"d secs for SelectionNotify", secs);
+  wait_reading_process_output (secs, nsecs, 0, 0,
                               reading_selection_reply, NULL, 0);
   TRACE1 ("  Got event = %d", !NILP (XCAR (reading_selection_reply)));
 
-  BLOCK_INPUT;
-  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)))
     error ("Timed out waiting for reply from selection owner");
   if (EQ (XCAR (reading_selection_reply), Qlambda))
@@ -1488,28 +1286,29 @@ x_get_foreign_selection (selection_symbol, target_type, time_stamp)
 /* Use xfree, not XFree, to free the data obtained with this function.  */
 
 static void
-x_get_window_property (display, window, property, data_ret, bytes_ret,
-                      actual_type_ret, actual_format_ret, actual_size_ret,
-                      delete_p)
-     Display *display;
-     Window window;
-     Atom property;
-     unsigned char **data_ret;
-     int *bytes_ret;
-     Atom *actual_type_ret;
-     int *actual_format_ret;
-     unsigned long *actual_size_ret;
-     int delete_p;
+x_get_window_property (Display *display, Window window, Atom property,
+                      unsigned char **data_ret, ptrdiff_t *bytes_ret,
+                      Atom *actual_type_ret, int *actual_format_ret,
+                      unsigned long *actual_size_ret, int delete_p)
 {
-  int total_size;
+  ptrdiff_t total_size;
   unsigned long bytes_remaining;
-  int offset = 0;
+  ptrdiff_t offset = 0;
+  unsigned char *data = 0;
   unsigned char *tmp_data = 0;
   int result;
-  int buffer_size = SELECTION_QUANTUM (display);
+  int buffer_size = selection_quantum (display);
+
+  /* Wide enough to avoid overflow in expressions using it.  */
+  ptrdiff_t x_long_size = X_LONG_SIZE;
 
-  if (buffer_size > MAX_SELECTION_QUANTUM)
-    buffer_size = MAX_SELECTION_QUANTUM;
+  /* Maximum value for TOTAL_SIZE.  It cannot exceed PTRDIFF_MAX - 1
+     and SIZE_MAX - 1, for an extra byte at the end.  And it cannot
+     exceed LONG_MAX * X_LONG_SIZE, for XGetWindowProperty.  */
+  ptrdiff_t total_size_max =
+    ((min (PTRDIFF_MAX, SIZE_MAX) - 1) / x_long_size < LONG_MAX
+     ? min (PTRDIFF_MAX, SIZE_MAX) - 1
+     : LONG_MAX * x_long_size);
 
   BLOCK_INPUT;
 
@@ -1520,113 +1319,133 @@ x_get_window_property (display, window, property, data_ret, bytes_ret,
                               actual_size_ret,
                               &bytes_remaining, &tmp_data);
   if (result != Success)
-    {
-      UNBLOCK_INPUT;
-      *data_ret = 0;
-      *bytes_ret = 0;
-      return;
-    }
+    goto done;
 
   /* This was allocated by Xlib, so use XFree.  */
-  XFree ((char *) tmp_data);
+  XFree (tmp_data);
 
   if (*actual_type_ret == None || *actual_format_ret == 0)
-    {
-      UNBLOCK_INPUT;
-      return;
-    }
+    goto done;
 
-  total_size = bytes_remaining + 1;
-  *data_ret = (unsigned char *) xmalloc (total_size);
+  if (total_size_max < bytes_remaining)
+    goto size_overflow;
+  total_size = bytes_remaining;
+  data = malloc (total_size + 1);
+  if (! data)
+    goto memory_exhausted;
 
   /* Now read, until we've gotten it all.  */
   while (bytes_remaining)
     {
-#ifdef TRACE_SELECTION
-      int last = bytes_remaining;
-#endif
+      ptrdiff_t bytes_gotten;
+      int bytes_per_item;
       result
        = XGetWindowProperty (display, window, property,
-                             (long)offset/4, (long)buffer_size/4,
+                             offset / X_LONG_SIZE,
+                             buffer_size / X_LONG_SIZE,
                              False,
                              AnyPropertyType,
                              actual_type_ret, actual_format_ret,
                              actual_size_ret, &bytes_remaining, &tmp_data);
 
-      TRACE2 ("Read %ld bytes from property %s",
-             last - bytes_remaining,
-             XGetAtomName (display, property));
-
       /* If this doesn't return Success at this point, it means that
         some clod deleted the selection while we were in the midst of
         reading it.  Deal with that, I guess.... */
       if (result != Success)
        break;
 
+      bytes_per_item = *actual_format_ret >> 3;
+      eassert (*actual_size_ret <= buffer_size / bytes_per_item);
+
       /* 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
+         and passes the long array to us.  Thus, for that case memcpy 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)
+      bytes_gotten = *actual_size_ret;
+      bytes_gotten *= bytes_per_item;
+
+      TRACE2 ("Read %"pD"d bytes from property %s",
+             bytes_gotten, XGetAtomName (display, property));
+
+      if (total_size - offset < bytes_gotten)
+       {
+         unsigned char *data1;
+         ptrdiff_t remaining_lim = total_size_max - offset - bytes_gotten;
+         if (remaining_lim < 0 || remaining_lim < bytes_remaining)
+           goto size_overflow;
+         total_size = offset + bytes_gotten + bytes_remaining;
+         data1 = realloc (data, total_size + 1);
+         if (! data1)
+           goto memory_exhausted;
+         data = data1;
+       }
+
+      if (32 < BITS_PER_LONG && *actual_format_ret == 32)
         {
           unsigned long i;
-          int  *idata = (int *) ((*data_ret) + offset);
+         int  *idata = (int *) (data + offset);
           long *ldata = (long *) tmp_data;
 
           for (i = 0; i < *actual_size_ret; ++i)
-            {
-              idata[i]= (int) ldata[i];
-              offset += 4;
-            }
+           idata[i] = ldata[i];
         }
       else
-        {
-          *actual_size_ret *= *actual_format_ret / 8;
-          bcopy (tmp_data, (*data_ret) + offset, *actual_size_ret);
-          offset += *actual_size_ret;
-        }
+       memcpy (data + offset, tmp_data, bytes_gotten);
+
+      offset += bytes_gotten;
 
       /* This was allocated by Xlib, so use XFree.  */
-      XFree ((char *) tmp_data);
+      XFree (tmp_data);
     }
 
   XFlush (display);
+  data[offset] = '\0';
+
+ done:
   UNBLOCK_INPUT;
+  *data_ret = data;
   *bytes_ret = offset;
+  return;
+
+ size_overflow:
+  free (data);
+  UNBLOCK_INPUT;
+  memory_full (SIZE_MAX);
+
+ memory_exhausted:
+  free (data);
+  UNBLOCK_INPUT;
+  memory_full (total_size + 1);
 }
 \f
 /* Use xfree, not XFree, to free the data obtained with this function.  */
 
 static void
-receive_incremental_selection (display, window, property, target_type,
-                              min_size_bytes, data_ret, size_bytes_ret,
-                              type_ret, format_ret, size_ret)
-     Display *display;
-     Window window;
-     Atom property;
-     Lisp_Object target_type; /* for error messages only */
-     unsigned int min_size_bytes;
-     unsigned char **data_ret;
-     int *size_bytes_ret;
-     Atom *type_ret;
-     unsigned long *size_ret;
-     int *format_ret;
+receive_incremental_selection (Display *display, Window window, Atom property,
+                              Lisp_Object target_type,
+                              unsigned int min_size_bytes,
+                              unsigned char **data_ret,
+                              ptrdiff_t *size_bytes_ret,
+                              Atom *type_ret, int *format_ret,
+                              unsigned long *size_ret)
 {
-  int offset = 0;
+  ptrdiff_t offset = 0;
   struct prop_location *wait_object;
+  if (min (PTRDIFF_MAX, SIZE_MAX) < min_size_bytes)
+    memory_full (SIZE_MAX);
+  *data_ret = xmalloc (min_size_bytes);
   *size_bytes_ret = min_size_bytes;
-  *data_ret = (unsigned char *) xmalloc (*size_bytes_ret);
 
-  TRACE1 ("Read %d bytes incrementally", min_size_bytes);
+  TRACE1 ("Read %u bytes incrementally", min_size_bytes);
 
   /* At this point, we have read an INCR property.
      Delete the property to ack it.
@@ -1651,7 +1470,7 @@ receive_incremental_selection (display, window, property, target_type,
   while (1)
     {
       unsigned char *tmp_data;
-      int tmp_size_bytes;
+      ptrdiff_t tmp_size_bytes;
 
       TRACE0 ("  Wait for property change");
       wait_for_property_change (wait_object);
@@ -1664,7 +1483,7 @@ receive_incremental_selection (display, window, property, target_type,
                             &tmp_data, &tmp_size_bytes,
                             type_ret, format_ret, size_ret, 1);
 
-      TRACE1 ("  Read increment of %d bytes", tmp_size_bytes);
+      TRACE1 ("  Read increment of %"pD"d bytes", tmp_size_bytes);
 
       if (tmp_size_bytes == 0) /* we're done */
        {
@@ -1687,13 +1506,12 @@ receive_incremental_selection (display, window, property, target_type,
       XFlush (display);
       UNBLOCK_INPUT;
 
-      if (*size_bytes_ret < offset + tmp_size_bytes)
-       {
-         *size_bytes_ret = offset + tmp_size_bytes;
-         *data_ret = (unsigned char *) xrealloc (*data_ret, *size_bytes_ret);
-       }
+      if (*size_bytes_ret - offset < tmp_size_bytes)
+       *data_ret = xpalloc (*data_ret, size_bytes_ret,
+                            tmp_size_bytes - (*size_bytes_ret - offset),
+                            -1, 1);
 
-      bcopy (tmp_data, (*data_ret) + offset, tmp_size_bytes);
+      memcpy ((*data_ret) + offset, tmp_data, tmp_size_bytes);
       offset += tmp_size_bytes;
 
       /* Use xfree, not XFree, because x_get_window_property
@@ -1703,24 +1521,21 @@ receive_incremental_selection (display, window, property, target_type,
 }
 
 \f
-/* Once a requested selection is "ready" (we got a SelectionNotify event),
-   fetch value from property PROPERTY of X window WINDOW on display DISPLAY.
-   TARGET_TYPE and SELECTION_ATOM are used in error message if this fails.  */
+/* Fetch a value from property PROPERTY of X window WINDOW on display
+   DISPLAY.  TARGET_TYPE and SELECTION_ATOM are used in error message
+   if this fails.  */
 
 static Lisp_Object
-x_get_window_property_as_lisp_data (display, window, property, target_type,
-                                   selection_atom)
-     Display *display;
-     Window window;
-     Atom property;
-     Lisp_Object target_type;  /* for error messages only */
-     Atom selection_atom;      /* for error messages only */
+x_get_window_property_as_lisp_data (Display *display, Window window,
+                                   Atom property,
+                                   Lisp_Object target_type,
+                                   Atom selection_atom)
 {
   Atom actual_type;
   int actual_format;
   unsigned long actual_size;
   unsigned char *data = 0;
-  int bytes = 0;
+  ptrdiff_t bytes = 0;
   Lisp_Object val;
   struct x_display_info *dpyinfo = x_display_info_for_display (display);
 
@@ -1754,7 +1569,7 @@ x_get_window_property_as_lisp_data (display, window, property, target_type,
       BLOCK_INPUT;
       /* Use xfree, not XFree, because x_get_window_property
         calls xmalloc itself.  */
-      xfree ((char *) data);
+      xfree (data);
       UNBLOCK_INPUT;
       receive_incremental_selection (display, window, property, target_type,
                                     min_size_bytes, &data, &bytes,
@@ -1775,7 +1590,7 @@ x_get_window_property_as_lisp_data (display, window, property, target_type,
 
   /* Use xfree, not XFree, because x_get_window_property
      calls xmalloc itself.  */
-  xfree ((char *) data);
+  xfree (data);
   return val;
 }
 \f
@@ -1811,11 +1626,8 @@ x_get_window_property_as_lisp_data (display, window, property, target_type,
 
 
 static Lisp_Object
-selection_data_to_lisp_data (display, data, size, type, format)
-     Display *display;
-     unsigned char *data;
-     Atom type;
-     int size, format;
+selection_data_to_lisp_data (Display *display, const unsigned char *data,
+                            ptrdiff_t size, Atom type, int format)
 {
   struct x_display_info *dpyinfo = x_display_info_for_display (display);
 
@@ -1843,11 +1655,12 @@ selection_data_to_lisp_data (display, data, size, type, format)
       return str;
     }
   /* Convert a single atom to a Lisp_Symbol.  Convert a set of atoms to
-     a vector of symbols.
-   */
-  else if (type == XA_ATOM)
+     a vector of symbols.  */
+  else if (type == XA_ATOM
+          /* Treat ATOM_PAIR type similar to list of atoms.  */
+          || type == dpyinfo->Xatom_ATOM_PAIR)
     {
-      int i;
+      ptrdiff_t i;
       /* 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
@@ -1872,52 +1685,62 @@ selection_data_to_lisp_data (display, data, size, type, format)
      convert it to a cons of integers, 16 bits in each half.
    */
   else if (format == 32 && size == sizeof (int))
-    return long_to_cons (((unsigned int *) data) [0]);
+    return INTEGER_TO_CONS (((int *) data) [0]);
   else if (format == 16 && size == sizeof (short))
-    return make_number ((int) (((unsigned short *) data) [0]));
+    return make_number (((short *) data) [0]);
 
   /* Convert any other kind of data to a vector of numbers, represented
      as above (as an integer, or a cons of two 16 bit integers.)
    */
   else if (format == 16)
     {
-      int i;
+      ptrdiff_t i;
       Lisp_Object v;
       v = Fmake_vector (make_number (size / 2), make_number (0));
       for (i = 0; i < size / 2; i++)
        {
-         int j = (int) ((unsigned short *) data) [i];
+         short j = ((short *) data) [i];
          Faset (v, make_number (i), make_number (j));
        }
       return v;
     }
   else
     {
-      int i;
-      Lisp_Object v = Fmake_vector (make_number (size / 4), make_number (0));
-      for (i = 0; i < size / 4; i++)
+      ptrdiff_t i;
+      Lisp_Object v = Fmake_vector (make_number (size / X_LONG_SIZE),
+                                   make_number (0));
+      for (i = 0; i < size / X_LONG_SIZE; i++)
        {
-         unsigned int j = ((unsigned int *) data) [i];
-         Faset (v, make_number (i), long_to_cons (j));
+         int j = ((int *) data) [i];
+         Faset (v, make_number (i), INTEGER_TO_CONS (j));
        }
       return v;
     }
 }
 
+/* Convert OBJ to an X long value, and return it as unsigned long.
+   OBJ should be an integer or a cons representing an integer.
+   Treat values in the range X_LONG_MAX + 1 .. X_ULONG_MAX as X
+   unsigned long values: in theory these values are supposed to be
+   signed but in practice unsigned 32-bit data are communicated via X
+   selections and we need to support that.  */
+static unsigned long
+cons_to_x_long (Lisp_Object obj)
+{
+  if (X_ULONG_MAX <= INTMAX_MAX
+      || XINT (INTEGERP (obj) ? obj : XCAR (obj)) < 0)
+    return cons_to_signed (obj, X_LONG_MIN, min (X_ULONG_MAX, INTMAX_MAX));
+  else
+    return cons_to_unsigned (obj, X_ULONG_MAX);
+}
 
 /* Use xfree, not XFree, to free the data obtained with this function.  */
 
 static void
-lisp_data_to_selection_data (display, obj,
-                            data_ret, type_ret, size_ret,
-                            format_ret, nofree_ret)
-     Display *display;
-     Lisp_Object obj;
-     unsigned char **data_ret;
-     Atom *type_ret;
-     unsigned int *size_ret;
-     int *format_ret;
-     int *nofree_ret;
+lisp_data_to_selection_data (Display *display, Lisp_Object obj,
+                            unsigned char **data_ret, Atom *type_ret,
+                            ptrdiff_t *size_ret,
+                            int *format_ret, int *nofree_ret)
 {
   Lisp_Object type = Qnil;
   struct x_display_info *dpyinfo = x_display_info_for_display (display);
@@ -1953,22 +1776,24 @@ lisp_data_to_selection_data (display, obj,
     }
   else if (SYMBOLP (obj))
     {
+      void *data = xmalloc (sizeof (Atom) + 1);
+      Atom *x_atom_ptr = data;
+      *data_ret = data;
       *format_ret = 32;
       *size_ret = 1;
-      *data_ret = (unsigned char *) xmalloc (sizeof (Atom) + 1);
       (*data_ret) [sizeof (Atom)] = 0;
-      (*(Atom **) data_ret) [0] = symbol_to_x_atom (dpyinfo, display, obj);
+      *x_atom_ptr = symbol_to_x_atom (dpyinfo, obj);
       if (NILP (type)) type = QATOM;
     }
-  else if (INTEGERP (obj)
-          && XINT (obj) < 0xFFFF
-          && XINT (obj) > -0xFFFF)
+  else if (RANGED_INTEGERP (X_SHRT_MIN, obj, X_SHRT_MAX))
     {
+      void *data = xmalloc (sizeof (short) + 1);
+      short *short_ptr = data;
+      *data_ret = data;
       *format_ret = 16;
       *size_ret = 1;
-      *data_ret = (unsigned char *) xmalloc (sizeof (short) + 1);
       (*data_ret) [sizeof (short)] = 0;
-      (*(short **) data_ret) [0] = (short) XINT (obj);
+      *short_ptr = XINT (obj);
       if (NILP (type)) type = QINTEGER;
     }
   else if (INTEGERP (obj)
@@ -1977,11 +1802,13 @@ lisp_data_to_selection_data (display, obj,
                   || (CONSP (XCDR (obj))
                       && INTEGERP (XCAR (XCDR (obj)))))))
     {
+      void *data = xmalloc (sizeof (unsigned long) + 1);
+      unsigned long *x_long_ptr = data;
+      *data_ret = data;
       *format_ret = 32;
       *size_ret = 1;
-      *data_ret = (unsigned char *) xmalloc (sizeof (long) + 1);
-      (*data_ret) [sizeof (long)] = 0;
-      (*(unsigned long **) data_ret) [0] = cons_to_long (obj);
+      (*data_ret) [sizeof (unsigned long)] = 0;
+      *x_long_ptr = cons_to_x_long (obj);
       if (NILP (type)) type = QINTEGER;
     }
   else if (VECTORP (obj))
@@ -1990,91 +1817,70 @@ lisp_data_to_selection_data (display, obj,
         a set of 16 or 32 bit INTEGERs;
         or a set of ATOM_PAIRs (represented as [[A1 A2] [A3 A4] ...]
        */
-      int i;
+      ptrdiff_t i;
+      ptrdiff_t size = ASIZE (obj);
 
-      if (SYMBOLP (XVECTOR (obj)->contents [0]))
+      if (SYMBOLP (AREF (obj, 0)))
        /* This vector is an ATOM set */
        {
+         void *data;
+         Atom *x_atoms;
          if (NILP (type)) type = QATOM;
-         *size_ret = XVECTOR_SIZE (obj);
-         *format_ret = 32;
-         *data_ret = (unsigned char *) xmalloc ((*size_ret) * sizeof (Atom));
-         for (i = 0; i < *size_ret; i++)
-           if (SYMBOLP (XVECTOR (obj)->contents [i]))
-             (*(Atom **) data_ret) [i]
-               = symbol_to_x_atom (dpyinfo, display, XVECTOR (obj)->contents [i]);
-           else
+         for (i = 0; i < size; i++)
+           if (!SYMBOLP (AREF (obj, i)))
              signal_error ("All elements of selection vector must have same type", obj);
-       }
-#if 0 /* #### MULTIPLE doesn't work yet */
-      else if (VECTORP (XVECTOR (obj)->contents [0]))
-       /* This vector is an ATOM_PAIR set */
-       {
-         if (NILP (type)) type = QATOM_PAIR;
-         *size_ret = XVECTOR_SIZE (obj);
-         *format_ret = 32;
-         *data_ret = (unsigned char *)
-           xmalloc ((*size_ret) * sizeof (Atom) * 2);
-         for (i = 0; i < *size_ret; i++)
-           if (VECTORP (XVECTOR (obj)->contents [i]))
-             {
-               Lisp_Object pair = XVECTOR (obj)->contents [i];
-               if (XVECTOR_SIZE (pair) != 2)
-                 signal_error (
-       "Elements of the vector must be vectors of exactly two elements",
-                               pair);
-
-               (*(Atom **) data_ret) [i * 2]
-                 = symbol_to_x_atom (dpyinfo, display,
-                                     XVECTOR (pair)->contents [0]);
-               (*(Atom **) data_ret) [(i * 2) + 1]
-                 = symbol_to_x_atom (dpyinfo, display,
-                                     XVECTOR (pair)->contents [1]);
-             }
-           else
-             signal_error ("All elements of the vector must be of the same type",
-                           obj);
 
+         *data_ret = data = xnmalloc (size, sizeof *x_atoms);
+         x_atoms = data;
+         *format_ret = 32;
+         *size_ret = size;
+         for (i = 0; i < size; i++)
+           x_atoms[i] = symbol_to_x_atom (dpyinfo, AREF (obj, i));
        }
-#endif
       else
        /* This vector is an INTEGER set, or something like it */
        {
-          int data_size = 2;
-         *size_ret = XVECTOR_SIZE (obj);
+         int format = 16;
+         int data_size = sizeof (short);
+         void *data;
+         unsigned long *x_atoms;
+         short *shorts;
          if (NILP (type)) type = QINTEGER;
-         *format_ret = 16;
-         for (i = 0; i < *size_ret; i++)
-           if (CONSP (XVECTOR (obj)->contents [i]))
-             *format_ret = 32;
-           else if (!INTEGERP (XVECTOR (obj)->contents [i]))
-             signal_error (/* Qselection_error */
-    "Elements of selection vector must be integers or conses of integers",
-                           obj);
-
-          /* 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]
-               = cons_to_long (XVECTOR (obj)->contents [i]);
-           else
-             (*((unsigned short **) data_ret)) [i]
-               = (unsigned short) cons_to_long (XVECTOR (obj)->contents [i]);
+         for (i = 0; i < size; i++)
+           {
+             if (! RANGED_INTEGERP (X_SHRT_MIN, AREF (obj, i),
+                                    X_SHRT_MAX))
+               {
+                 /* Use sizeof (long) even if it is more than 32 bits.
+                    See comment in x_get_window_property and
+                    x_fill_property_data.  */
+                 data_size = sizeof (long);
+                 format = 32;
+                 break;
+               }
+           }
+         *data_ret = data = xnmalloc (size, data_size);
+         x_atoms = data;
+         shorts = data;
+         *format_ret = format;
+         *size_ret = size;
+         for (i = 0; i < size; i++)
+           {
+             if (format == 32)
+               x_atoms[i] = cons_to_x_long (AREF (obj, i));
+             else
+               shorts[i] = XINT (AREF (obj, i));
+           }
        }
     }
   else
     signal_error (/* Qselection_error */ "Unrecognized selection data", obj);
 
-  *type_ret = symbol_to_x_atom (dpyinfo, display, type);
+  *type_ret = symbol_to_x_atom (dpyinfo, type);
 }
 
 static Lisp_Object
-clean_local_selection_data (obj)
-     Lisp_Object obj;
+clean_local_selection_data (Lisp_Object obj)
 {
   if (CONSP (obj)
       && INTEGERP (XCAR (obj))
@@ -2094,15 +1900,14 @@ clean_local_selection_data (obj)
     }
   if (VECTORP (obj))
     {
-      int i;
-      int size = XVECTOR_SIZE (obj);
+      ptrdiff_t i;
+      ptrdiff_t size = ASIZE (obj);
       Lisp_Object copy;
       if (size == 1)
-       return clean_local_selection_data (XVECTOR (obj)->contents [0]);
+       return clean_local_selection_data (AREF (obj, 0));
       copy = Fmake_vector (make_number (size), Qnil);
       for (i = 0; i < size; i++)
-       XVECTOR (copy)->contents [i]
-         = clean_local_selection_data (XVECTOR (obj)->contents [i]);
+       ASET (copy, i, clean_local_selection_data (AREF (obj, i)));
       return copy;
     }
   return obj;
@@ -2114,8 +1919,7 @@ clean_local_selection_data (obj)
    We store t there if the reply is successful, lambda if not.  */
 
 void
-x_handle_selection_notify (event)
-     XSelectionEvent *event;
+x_handle_selection_notify (XSelectionEvent *event)
 {
   if (event->requestor != reading_selection_window)
     return;
@@ -2128,21 +1932,77 @@ x_handle_selection_notify (event)
 }
 
 \f
+/* From a Lisp_Object, return a suitable frame for selection
+   operations.  OBJECT may be a frame, a terminal object, or nil
+   (which stands for the selected frame--or, if that is not an X
+   frame, the first X display on the list).  If no suitable frame can
+   be found, return NULL.  */
+
+static struct frame *
+frame_for_x_selection (Lisp_Object object)
+{
+  Lisp_Object tail;
+  struct frame *f;
+
+  if (NILP (object))
+    {
+      f = XFRAME (selected_frame);
+      if (FRAME_X_P (f) && FRAME_LIVE_P (f))
+       return f;
+
+      for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
+       {
+         f = XFRAME (XCAR (tail));
+         if (FRAME_X_P (f) && FRAME_LIVE_P (f))
+           return f;
+       }
+    }
+  else if (TERMINALP (object))
+    {
+      struct terminal *t = get_terminal (object, 1);
+      if (t->type == output_x_window)
+       {
+         for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
+           {
+             f = XFRAME (XCAR (tail));
+             if (FRAME_LIVE_P (f) && f->terminal == t)
+               return f;
+           }
+       }
+    }
+  else if (FRAMEP (object))
+    {
+      f = XFRAME (object);
+      if (FRAME_X_P (f) && FRAME_LIVE_P (f))
+       return f;
+    }
+
+  return NULL;
+}
+
+
 DEFUN ("x-own-selection-internal", Fx_own_selection_internal,
-       Sx_own_selection_internal, 2, 2, 0,
-       doc: /* Assert an X selection of the given TYPE with the given VALUE.
-TYPE is a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'.
+       Sx_own_selection_internal, 2, 3, 0,
+       doc: /* Assert an X selection of type SELECTION and value VALUE.
+SELECTION is a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'.
 \(Those are literal upper-case symbol names, since that's what X expects.)
 VALUE is typically a string, or a cons of two markers, but may be
-anything that the functions on `selection-converter-alist' know about.  */)
-     (selection_name, selection_value)
-     Lisp_Object selection_name, selection_value;
+anything that the functions on `selection-converter-alist' know about.
+
+FRAME should be a frame that should own the selection.  If omitted or
+nil, it defaults to the selected frame.
+
+On Nextstep, FRAME is unused.  */)
+  (Lisp_Object selection, Lisp_Object value, Lisp_Object frame)
 {
-  check_x ();
-  CHECK_SYMBOL (selection_name);
-  if (NILP (selection_value)) error ("SELECTION-VALUE may not be nil");
-  x_own_selection (selection_name, selection_value);
-  return selection_value;
+  if (NILP (frame)) frame = selected_frame;
+  if (!FRAME_LIVE_P (XFRAME (frame)) || !FRAME_X_P (XFRAME (frame)))
+    error ("X selection unavailable for this frame");
+
+  CHECK_SYMBOL (selection);
+  if (NILP (value)) error ("VALUE may not be nil");
+  x_own_selection (selection, value, frame);
+  return value;
 }
 
 
@@ -2151,62 +2011,70 @@ anything that the functions on `selection-converter-alist' know about.  */)
    will block until all of the data has arrived.  */
 
 DEFUN ("x-get-selection-internal", Fx_get_selection_internal,
-       Sx_get_selection_internal, 2, 3, 0,
+       Sx_get_selection_internal, 2, 4, 0,
        doc: /* Return text selected from some X window.
-SELECTION is a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'.
+SELECTION-SYMBOL is typically `PRIMARY', `SECONDARY', or `CLIPBOARD'.
 \(Those are literal upper-case symbol names, since that's what X expects.)
-TYPE is the type of data desired, typically `STRING'.
-TIME_STAMP is the time to use in the XConvertSelection call for foreign
-selections.  If omitted, defaults to the time for the last event.  */)
-  (selection_symbol, target_type, time_stamp)
-     Lisp_Object selection_symbol, target_type, time_stamp;
+TARGET-TYPE is the type of data desired, typically `STRING'.
+
+TIME-STAMP is the time to use in the XConvertSelection call for foreign
+selections.  If omitted, defaults to the time for the last event.
+
+TERMINAL should be a terminal object or a frame specifying the X
+server to query.  If omitted or nil, that stands for the selected
+frame's display, or the first available X display.
+
+On Nextstep, TIME-STAMP and TERMINAL are unused.  */)
+  (Lisp_Object selection_symbol, Lisp_Object target_type,
+   Lisp_Object time_stamp, Lisp_Object terminal)
 {
   Lisp_Object val = Qnil;
   struct gcpro gcpro1, gcpro2;
+  struct frame *f = frame_for_x_selection (terminal);
   GCPRO2 (target_type, val); /* we store newly consed data into these */
-  check_x ();
-  CHECK_SYMBOL (selection_symbol);
 
-#if 0 /* #### MULTIPLE doesn't work yet */
-  if (CONSP (target_type)
-      && XCAR (target_type) == QMULTIPLE)
-    {
-      CHECK_VECTOR (XCDR (target_type));
-      /* So we don't destructively modify this...  */
-      target_type = copy_multiple_data (target_type);
-    }
-  else
-#endif
-    CHECK_SYMBOL (target_type);
+  CHECK_SYMBOL (selection_symbol);
+  CHECK_SYMBOL (target_type);
+  if (EQ (target_type, QMULTIPLE))
+    error ("Retrieving MULTIPLE selections is currently unimplemented");
+  if (!f)
+    error ("X selection unavailable for this frame");
 
-  val = x_get_local_selection (selection_symbol, target_type, 1);
+  val = x_get_local_selection (selection_symbol, target_type, 1,
+                              FRAME_X_DISPLAY_INFO (f));
 
-  if (NILP (val))
+  if (NILP (val) && FRAME_LIVE_P (f))
     {
-      val = x_get_foreign_selection (selection_symbol, target_type, time_stamp);
-      goto DONE;
+      Lisp_Object frame;
+      XSETFRAME (frame, f);
+      RETURN_UNGCPRO (x_get_foreign_selection (selection_symbol, target_type,
+                                              time_stamp, frame));
     }
 
-  if (CONSP (val)
-      && SYMBOLP (XCAR (val)))
+  if (CONSP (val) && SYMBOLP (XCAR (val)))
     {
       val = XCDR (val);
       if (CONSP (val) && NILP (XCDR (val)))
        val = XCAR (val);
     }
-  val = clean_local_selection_data (val);
- DONE:
-  UNGCPRO;
-  return val;
+  RETURN_UNGCPRO (clean_local_selection_data (val));
 }
 
 DEFUN ("x-disown-selection-internal", Fx_disown_selection_internal,
-       Sx_disown_selection_internal, 1, 2, 0,
+       Sx_disown_selection_internal, 1, 3, 0,
        doc: /* If we own the selection SELECTION, disown it.
-Disowning it means there is no such selection.  */)
-     (selection, time)
-     Lisp_Object selection;
-     Lisp_Object time;
+Disowning it means there is no such selection.
+
+Sets the last-change time for the selection to TIME-OBJECT (by default
+the time of the last event).
+
+TERMINAL should be a terminal object or a frame specifying the X
+server to query.  If omitted or nil, that stands for the selected
+frame's display, or the first available X display.
+
+On Nextstep, the TIME-OBJECT and TERMINAL arguments are unused.
+On MS-DOS, all this does is return non-nil if we own the selection.  */)
+  (Lisp_Object selection, Lisp_Object time_object, Lisp_Object terminal)
 {
   Time timestamp;
   Atom selection_atom;
@@ -2214,29 +2082,27 @@ Disowning it means there is no such selection.  */)
     struct selection_input_event sie;
     struct input_event ie;
   } event;
-  Display *display;
+  struct frame *f = frame_for_x_selection (terminal);
   struct x_display_info *dpyinfo;
-  struct frame *sf = SELECTED_FRAME ();
 
-  check_x ();
-  if (! FRAME_X_P (sf))
+  if (!f)
     return Qnil;
 
-  display = FRAME_X_DISPLAY (sf);
-  dpyinfo = FRAME_X_DISPLAY_INFO (sf);
+  dpyinfo = FRAME_X_DISPLAY_INFO (f);
   CHECK_SYMBOL (selection);
-  if (NILP (time))
-    timestamp = last_event_timestamp;
-  else
-    timestamp = cons_to_long (time);
 
-  if (NILP (assq_no_quit (selection, Vselection_alist)))
-    return Qnil;  /* Don't disown the selection when we're not the owner.  */
+  /* Don't disown the selection when we're not the owner.  */
+  if (NILP (LOCAL_SELECTION (selection, dpyinfo)))
+    return Qnil;
 
-  selection_atom = symbol_to_x_atom (dpyinfo, display, selection);
+  selection_atom = symbol_to_x_atom (dpyinfo, selection);
 
   BLOCK_INPUT;
-  XSetSelectionOwner (display, selection_atom, None, timestamp);
+  if (NILP (time_object))
+    timestamp = last_event_timestamp;
+  else
+    CONS_TO_INTEGER (time_object, Time, timestamp);
+  XSetSelectionOwner (dpyinfo->display, selection_atom, None, timestamp);
   UNBLOCK_INPUT;
 
   /* It doesn't seem to be guaranteed that a SelectionClear event will be
@@ -2244,7 +2110,7 @@ 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.sie) = display;
+  SELECTION_EVENT_DISPLAY (&event.sie) = dpyinfo->display;
   SELECTION_EVENT_SELECTION (&event.sie) = selection_atom;
   SELECTION_EVENT_TIME (&event.sie) = timestamp;
   x_handle_selection_clear (&event.ie);
@@ -2252,301 +2118,207 @@ Disowning it means there is no such selection.  */)
   return Qt;
 }
 
-/* Get rid of all the selections in buffer BUFFER.
-   This is used when we kill a buffer.  */
-
-void
-x_disown_buffer_selections (buffer)
-     Lisp_Object buffer;
-{
-  Lisp_Object tail;
-  struct buffer *buf = XBUFFER (buffer);
-
-  for (tail = Vselection_alist; CONSP (tail); tail = XCDR (tail))
-    {
-      Lisp_Object elt, value;
-      elt = XCAR (tail);
-      value = XCDR (elt);
-      if (CONSP (value) && MARKERP (XCAR (value))
-         && XMARKER (XCAR (value))->buffer == buf)
-       Fx_disown_selection_internal (XCAR (elt), Qnil);
-    }
-}
-
 DEFUN ("x-selection-owner-p", Fx_selection_owner_p, Sx_selection_owner_p,
-       0, 1, 0,
+       0, 2, 0,
        doc: /* Whether the current Emacs process owns the given X Selection.
 The arg should be the name of the selection in question, typically one of
 the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.
 \(Those are literal upper-case symbol names, since that's what X expects.)
 For convenience, the symbol nil is the same as `PRIMARY',
-and t is the same as `SECONDARY'.  */)
-     (selection)
-     Lisp_Object selection;
+and t is the same as `SECONDARY'.
+
+TERMINAL should be a terminal object or a frame specifying the X
+server to query.  If omitted or nil, that stands for the selected
+frame's display, or the first available X display.
+
+On Nextstep, TERMINAL is unused.  */)
+  (Lisp_Object selection, Lisp_Object terminal)
 {
-  check_x ();
+  struct frame *f = frame_for_x_selection (terminal);
+
   CHECK_SYMBOL (selection);
   if (EQ (selection, Qnil)) selection = QPRIMARY;
   if (EQ (selection, Qt)) selection = QSECONDARY;
 
-  if (NILP (Fassq (selection, Vselection_alist)))
+  if (f && !NILP (LOCAL_SELECTION (selection, FRAME_X_DISPLAY_INFO (f))))
+    return Qt;
+  else
     return Qnil;
-  return Qt;
 }
 
 DEFUN ("x-selection-exists-p", Fx_selection_exists_p, Sx_selection_exists_p,
-       0, 1, 0,
-       doc: /* Whether there is an owner for the given X Selection.
-The arg should be the name of the selection in question, typically one of
-the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.
-\(Those are literal upper-case symbol names, since that's what X expects.)
-For convenience, the symbol nil is the same as `PRIMARY',
-and t is the same as `SECONDARY'.  */)
-     (selection)
-     Lisp_Object selection;
+       0, 2, 0,
+       doc: /* Whether there is an owner for the given X selection.
+SELECTION should be the name of the selection in question, typically
+one of the symbols `PRIMARY', `SECONDARY', `CLIPBOARD', or
+`CLIPBOARD_MANAGER' (X expects these literal upper-case names.)  The
+symbol nil is the same as `PRIMARY', and t is the same as `SECONDARY'.
+
+TERMINAL should be a terminal object or a frame specifying the X
+server to query.  If omitted or nil, that stands for the selected
+frame's display, or the first available X display.
+
+On Nextstep, TERMINAL is unused.  */)
+  (Lisp_Object selection, Lisp_Object terminal)
 {
   Window owner;
   Atom atom;
-  Display *dpy;
-  struct frame *sf = SELECTED_FRAME ();
-
-  /* It should be safe to call this before we have an X frame.  */
-  if (! FRAME_X_P (sf))
-    return Qnil;
+  struct frame *f = frame_for_x_selection (terminal);
+  struct x_display_info *dpyinfo;
 
-  dpy = FRAME_X_DISPLAY (sf);
   CHECK_SYMBOL (selection);
-  if (!NILP (Fx_selection_owner_p (selection)))
-    return Qt;
   if (EQ (selection, Qnil)) selection = QPRIMARY;
   if (EQ (selection, Qt)) selection = QSECONDARY;
-  atom = symbol_to_x_atom (FRAME_X_DISPLAY_INFO (sf), dpy, selection);
-  if (atom == 0)
+
+  if (!f)
     return Qnil;
+
+  dpyinfo = FRAME_X_DISPLAY_INFO (f);
+
+  if (!NILP (LOCAL_SELECTION (selection, dpyinfo)))
+    return Qt;
+
+  atom = symbol_to_x_atom (dpyinfo, selection);
+  if (atom == 0) return Qnil;
   BLOCK_INPUT;
-  owner = XGetSelectionOwner (dpy, atom);
+  owner = XGetSelectionOwner (dpyinfo->display, atom);
   UNBLOCK_INPUT;
   return (owner ? Qt : Qnil);
 }
 
 \f
-#ifdef CUT_BUFFER_SUPPORT
+/* Send clipboard manager a SAVE_TARGETS request with a UTF8_STRING
+   property (http://www.freedesktop.org/wiki/ClipboardManager).  */
 
-/* Ensure that all 8 cut buffers exist.  ICCCM says we gotta...  */
-static void
-initialize_cut_buffers (display, window)
-     Display *display;
-     Window window;
+static Lisp_Object
+x_clipboard_manager_save (Lisp_Object frame)
 {
-  unsigned char *data = (unsigned char *) "";
-  BLOCK_INPUT;
-#define FROB(atom) XChangeProperty (display, window, atom, XA_STRING, 8, \
-                                   PropModeAppend, data, 0)
-  FROB (XA_CUT_BUFFER0);
-  FROB (XA_CUT_BUFFER1);
-  FROB (XA_CUT_BUFFER2);
-  FROB (XA_CUT_BUFFER3);
-  FROB (XA_CUT_BUFFER4);
-  FROB (XA_CUT_BUFFER5);
-  FROB (XA_CUT_BUFFER6);
-  FROB (XA_CUT_BUFFER7);
-#undef FROB
-  UNBLOCK_INPUT;
+  struct frame *f = XFRAME (frame);
+  struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  Atom data = dpyinfo->Xatom_UTF8_STRING;
+
+  XChangeProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                  dpyinfo->Xatom_EMACS_TMP,
+                  dpyinfo->Xatom_ATOM, 32, PropModeReplace,
+                  (unsigned char *) &data, 1);
+  x_get_foreign_selection (QCLIPBOARD_MANAGER, QSAVE_TARGETS,
+                          Qnil, frame);
+  return Qt;
 }
 
+/* Error handler for x_clipboard_manager_save_frame.  */
 
-#define CHECK_CUT_BUFFER(symbol)                                       \
-  do { CHECK_SYMBOL ((symbol));                                        \
-    if (!EQ((symbol), QCUT_BUFFER0) && !EQ((symbol), QCUT_BUFFER1)     \
-       && !EQ((symbol), QCUT_BUFFER2) && !EQ((symbol), QCUT_BUFFER3)   \
-       && !EQ((symbol), QCUT_BUFFER4) && !EQ((symbol), QCUT_BUFFER5)   \
-       && !EQ((symbol), QCUT_BUFFER6) && !EQ((symbol), QCUT_BUFFER7))  \
-      signal_error ("Doesn't name a cut buffer", (symbol));            \
-  } while (0)
-
-DEFUN ("x-get-cut-buffer-internal", Fx_get_cut_buffer_internal,
-       Sx_get_cut_buffer_internal, 1, 1, 0,
-       doc: /* Returns the value of the named cut buffer (typically CUT_BUFFER0).  */)
-     (buffer)
-     Lisp_Object buffer;
+static Lisp_Object
+x_clipboard_manager_error_1 (Lisp_Object err)
 {
-  Window window;
-  Atom buffer_atom;
-  unsigned char *data = NULL;
-  int bytes;
-  Atom type;
-  int format;
-  unsigned long size;
-  Lisp_Object ret;
-  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);
-  window = RootWindow (display, 0); /* Cut buffers are on screen 0 */
-  CHECK_CUT_BUFFER (buffer);
-  buffer_atom = symbol_to_x_atom (dpyinfo, display, buffer);
-
-  x_get_window_property (display, window, buffer_atom, &data, &bytes,
-                        &type, &format, &size, 0);
-
-  if (!data || !format)
-    {
-      xfree (data);
-      return Qnil;
-    }
-
-  if (format != 8 || type != XA_STRING)
-    signal_error ("Cut buffer doesn't contain 8-bit data",
-                 list2 (x_atom_to_symbol (display, type),
-                        make_number (format)));
-
-  ret = (bytes ? make_unibyte_string ((char *) data, bytes) : Qnil);
-  /* Use xfree, not XFree, because x_get_window_property
-     calls xmalloc itself.  */
-  xfree (data);
-  return ret;
+  Lisp_Object args[2];
+  args[0] = build_string ("X clipboard manager error: %s\n\
+If the problem persists, set `x-select-enable-clipboard-manager' to nil.");
+  args[1] = CAR (CDR (err));
+  Fmessage (2, args);
+  return Qnil;
 }
 
+/* Error handler for x_clipboard_manager_save_all.  */
 
-DEFUN ("x-store-cut-buffer-internal", Fx_store_cut_buffer_internal,
-       Sx_store_cut_buffer_internal, 2, 2, 0,
-       doc: /* Sets the value of the named cut buffer (typically CUT_BUFFER0).  */)
-     (buffer, string)
-     Lisp_Object buffer, string;
+static Lisp_Object
+x_clipboard_manager_error_2 (Lisp_Object err)
 {
-  Window window;
-  Atom buffer_atom;
-  unsigned char *data;
-  int bytes;
-  int bytes_remaining;
-  int max_bytes;
-  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 */
-
-  max_bytes = SELECTION_QUANTUM (display);
-  if (max_bytes > MAX_SELECTION_QUANTUM)
-    max_bytes = MAX_SELECTION_QUANTUM;
-
-  CHECK_CUT_BUFFER (buffer);
-  CHECK_STRING (string);
-  buffer_atom = symbol_to_x_atom (FRAME_X_DISPLAY_INFO (sf),
-                                 display, buffer);
-  data = (unsigned char *) SDATA (string);
-  bytes = SBYTES (string);
-  bytes_remaining = bytes;
-
-  if (! FRAME_X_DISPLAY_INFO (sf)->cut_buffers_initialized)
-    {
-      initialize_cut_buffers (display, window);
-      FRAME_X_DISPLAY_INFO (sf)->cut_buffers_initialized = 1;
-    }
+  fprintf (stderr, "Error saving to X clipboard manager.\n\
+If the problem persists, set `x-select-enable-clipboard-manager' \
+to nil.\n");
+  return Qnil;
+}
 
-  BLOCK_INPUT;
+/* Called from delete_frame: save any clipboard owned by FRAME to the
+   clipboard manager.  Do nothing if FRAME does not own the clipboard,
+   or if no clipboard manager is present.  */
 
-  /* Don't mess up with an empty value.  */
-  if (!bytes_remaining)
-    XChangeProperty (display, window, buffer_atom, XA_STRING, 8,
-                    PropModeReplace, data, 0);
+void
+x_clipboard_manager_save_frame (Lisp_Object frame)
+{
+  struct frame *f;
 
-  while (bytes_remaining)
+  if (!NILP (Vx_select_enable_clipboard_manager)
+      && FRAMEP (frame)
+      && (f = XFRAME (frame), FRAME_X_P (f))
+      && FRAME_LIVE_P (f))
     {
-      int chunk = (bytes_remaining < max_bytes
-                  ? bytes_remaining : max_bytes);
-      XChangeProperty (display, window, buffer_atom, XA_STRING, 8,
-                      (bytes_remaining == bytes
-                       ? PropModeReplace
-                       : PropModeAppend),
-                      data, chunk);
-      data += chunk;
-      bytes_remaining -= chunk;
+      struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+      Lisp_Object local_selection
+       = LOCAL_SELECTION (QCLIPBOARD, dpyinfo);
+
+      if (!NILP (local_selection)
+         && EQ (frame, XCAR (XCDR (XCDR (XCDR (local_selection)))))
+         && XGetSelectionOwner (dpyinfo->display,
+                                dpyinfo->Xatom_CLIPBOARD_MANAGER))
+       internal_condition_case_1 (x_clipboard_manager_save, frame, Qt,
+                                  x_clipboard_manager_error_1);
     }
-  UNBLOCK_INPUT;
-  return string;
 }
 
+/* Called from Fkill_emacs: save any clipboard owned by FRAME to the
+   clipboard manager.  Do nothing if FRAME does not own the clipboard,
+   or if no clipboard manager is present.  */
 
-DEFUN ("x-rotate-cut-buffers-internal", Fx_rotate_cut_buffers_internal,
-       Sx_rotate_cut_buffers_internal, 1, 1, 0,
-       doc: /* Rotate the values of the cut buffers by N steps.
-Positive N means shift the values forward, negative means backward.  */)
-     (n)
-     Lisp_Object n;
+void
+x_clipboard_manager_save_all (void)
 {
-  Window window;
-  Atom props[8];
-  Display *display;
-  struct frame *sf = SELECTED_FRAME ();
-  
-  check_x ();
+  /* Loop through all X displays, saving owned clipboards.  */
+  struct x_display_info *dpyinfo;
+  Lisp_Object local_selection, local_frame;
 
-  if (! FRAME_X_P (sf))
-    return Qnil;
+  if (NILP (Vx_select_enable_clipboard_manager))
+    return;
 
-  display = FRAME_X_DISPLAY (sf);
-  window = RootWindow (display, 0); /* Cut buffers are on screen 0 */
-  CHECK_NUMBER (n);
-  if (XINT (n) == 0)
-    return n;
-  if (! FRAME_X_DISPLAY_INFO (sf)->cut_buffers_initialized)
+  for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
     {
-      initialize_cut_buffers (display, window);
-      FRAME_X_DISPLAY_INFO (sf)->cut_buffers_initialized = 1;
-    }
+      local_selection = LOCAL_SELECTION (QCLIPBOARD, dpyinfo);
+      if (NILP (local_selection)
+         || !XGetSelectionOwner (dpyinfo->display,
+                                 dpyinfo->Xatom_CLIPBOARD_MANAGER))
+       continue;
+
+      local_frame = XCAR (XCDR (XCDR (XCDR (local_selection))));
+      if (FRAME_LIVE_P (XFRAME (local_frame)))
+       {
+         Lisp_Object args[1];
+         args[0] = build_string ("Saving clipboard to X clipboard manager...");
+         Fmessage (1, args);
 
-  props[0] = XA_CUT_BUFFER0;
-  props[1] = XA_CUT_BUFFER1;
-  props[2] = XA_CUT_BUFFER2;
-  props[3] = XA_CUT_BUFFER3;
-  props[4] = XA_CUT_BUFFER4;
-  props[5] = XA_CUT_BUFFER5;
-  props[6] = XA_CUT_BUFFER6;
-  props[7] = XA_CUT_BUFFER7;
-  BLOCK_INPUT;
-  XRotateWindowProperties (display, window, props, 8, XINT (n));
-  UNBLOCK_INPUT;
-  return n;
+         internal_condition_case_1 (x_clipboard_manager_save, local_frame,
+                                    Qt, x_clipboard_manager_error_2);
+       }
+    }
 }
 
-#endif
 \f
 /***********************************************************************
                       Drag and drop support
 ***********************************************************************/
 /* Check that lisp values are of correct type for x_fill_property_data.
    That is, number, string or a cons with two numbers (low and high 16
-   bit parts of a 32 bit number).  */
+   bit parts of a 32 bit number).  Return the number of items in DATA,
+   or -1 if there is an error.  */
 
 int
-x_check_property_data (data)
-     Lisp_Object data;
+x_check_property_data (Lisp_Object data)
 {
   Lisp_Object iter;
   int size = 0;
 
-  for (iter = data; CONSP (iter) && size != -1; iter = XCDR (iter), ++size)
+  for (iter = data; CONSP (iter); iter = XCDR (iter))
     {
       Lisp_Object o = XCAR (iter);
 
       if (! NUMBERP (o) && ! STRINGP (o) && ! CONSP (o))
-        size = -1;
+        return -1;
       else if (CONSP (o) &&
                (! NUMBERP (XCAR (o)) || ! NUMBERP (XCDR (o))))
-        size = -1;
+        return -1;
+      if (size == INT_MAX)
+       return -1;
+      size++;
     }
 
   return size;
@@ -2566,11 +2338,7 @@ x_check_property_data (data)
    XClientMessageEvent).  */
 
 void
-x_fill_property_data (dpy, data, ret, format)
-     Display *dpy;
-     Lisp_Object data;
-     void *ret;
-     int format;
+x_fill_property_data (Display *dpy, Lisp_Object data, void *ret, int format)
 {
   long val;
   long  *d32 = (long  *) ret;
@@ -2582,25 +2350,31 @@ x_fill_property_data (dpy, data, ret, format)
     {
       Lisp_Object o = XCAR (iter);
 
-      if (INTEGERP (o))
-        val = (long) XFASTINT (o);
-      else if (FLOATP (o))
-        val = (long) XFLOAT_DATA (o);
-      else if (CONSP (o))
-        val = (long) cons_to_long (o);
+      if (INTEGERP (o) || FLOATP (o) || CONSP (o))
+       val = cons_to_signed (o, LONG_MIN, LONG_MAX);
       else if (STRINGP (o))
         {
           BLOCK_INPUT;
-          val = (long) XInternAtom (dpy, (char *) SDATA (o), False);
+          val = (long) XInternAtom (dpy, SSDATA (o), False);
           UNBLOCK_INPUT;
         }
       else
         error ("Wrong type, must be string, number or cons");
 
       if (format == 8)
-        *d08++ = (char) val;
+       {
+         if (CHAR_MIN <= val && val <= CHAR_MAX)
+           *d08++ = val;
+         else
+           error ("Out of 'char' range");
+       }
       else if (format == 16)
-        *d16++ = (short) val;
+       {
+         if (SHRT_MIN <= val && val <= SHRT_MAX)
+           *d16++ = val;
+         else
+           error ("Out of 'short' range");
+       }
       else
         *d32++ = val;
     }
@@ -2610,7 +2384,7 @@ x_fill_property_data (dpy, data, ret, format)
    F is the frame to be used to look up X atoms if the TYPE is XA_ATOM.
    DATA is a C array of values to be converted.
    TYPE is the type of the data.  Only XA_ATOM is special, it converts
-   each number in DATA to its corresponfing X atom as a symbol.
+   each number in DATA to its corresponding X atom as a symbol.
    FORMAT is 8, 16 or 32 and gives the size in bits for each C value to
    be stored in RET.
    SIZE is the number of elements in DATA.
@@ -2622,24 +2396,20 @@ x_fill_property_data (dpy, data, ret, format)
    Also see comment for selection_data_to_lisp_data above.  */
 
 Lisp_Object
-x_property_data_to_lisp (f, data, type, format, size)
-     struct frame *f;
-     unsigned char *data;
-     Atom type;
-     int format;
-     unsigned long size;
+x_property_data_to_lisp (struct frame *f, const unsigned char *data,
+                        Atom type, int format, long unsigned int size)
 {
+  ptrdiff_t format_bytes = format >> 3;
+  if (PTRDIFF_MAX / format_bytes < size)
+    memory_full (SIZE_MAX);
   return selection_data_to_lisp_data (FRAME_X_DISPLAY (f),
-                                      data, size*format/8, type, format);
+                                     data, size * format_bytes, type, format);
 }
 
 /* Get the mouse position in frame relative coordinates.  */
 
 static void
-mouse_position_for_drop (f, x, y)
-     FRAME_PTR f;
-     int *x;
-     int *y;
+mouse_position_for_drop (FRAME_PTR f, int *x, int *y)
 {
   Window root, dummy_window;
   int dummy;
@@ -2681,33 +2451,26 @@ the cdr is the lower 16 bits of a 32 bit value.
 Use the display for FRAME or the current frame if FRAME is not given or nil.
 
 If the value is 0 or the atom is not known, return the empty string.  */)
-  (value, frame)
-     Lisp_Object value, frame;
+  (Lisp_Object value, Lisp_Object frame)
 {
   struct frame *f = check_x_frame (frame);
   char *name = 0;
+  char empty[] = "";
   Lisp_Object ret = Qnil;
   Display *dpy = FRAME_X_DISPLAY (f);
   Atom atom;
   int had_errors;
 
-  if (INTEGERP (value))
-    atom = (Atom) XUINT (value);
-  else if (FLOATP (value))
-    atom = (Atom) XFLOAT_DATA (value);
-  else if (CONSP (value))
-    atom = (Atom) cons_to_long (value);
-  else
-    error ("Wrong type, value must be number or cons");
+  CONS_TO_INTEGER (value, Atom, atom);
 
   BLOCK_INPUT;
   x_catch_errors (dpy);
-  name = atom ? XGetAtomName (dpy, atom) : "";
+  name = atom ? XGetAtomName (dpy, atom) : empty;
   had_errors = x_had_errors_p (dpy);
   x_uncatch_errors ();
 
   if (!had_errors)
-    ret = make_string (name, strlen (name));
+    ret = build_string (name);
 
   if (atom && name) XFree (name);
   if (NILP (ret)) ret = empty_unibyte_string;
@@ -2722,21 +2485,20 @@ DEFUN ("x-register-dnd-atom", Fx_register_dnd_atom,
        doc: /* Request that dnd events are made for ClientMessages with ATOM.
 ATOM can be a symbol or a string.  The ATOM is interned on the display that
 FRAME is on.  If FRAME is nil, the selected frame is used.  */)
-    (atom, frame)
-    Lisp_Object atom, frame;
+  (Lisp_Object atom, Lisp_Object frame)
 {
   Atom x_atom;
   struct frame *f = check_x_frame (frame);
-  size_t i;
+  ptrdiff_t i;
   struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
 
 
   if (SYMBOLP (atom))
-    x_atom = symbol_to_x_atom (dpyinfo, FRAME_X_DISPLAY (f), atom);
+    x_atom = symbol_to_x_atom (dpyinfo, atom);
   else if (STRINGP (atom))
     {
       BLOCK_INPUT;
-      x_atom = XInternAtom (FRAME_X_DISPLAY (f), (char *) SDATA (atom), False);
+      x_atom = XInternAtom (FRAME_X_DISPLAY (f), SSDATA (atom), False);
       UNBLOCK_INPUT;
     }
   else
@@ -2747,12 +2509,9 @@ FRAME is on.  If FRAME is nil, the selected frame is used.  */)
       return Qnil;
 
   if (dpyinfo->x_dnd_atoms_length == dpyinfo->x_dnd_atoms_size)
-    {
-      dpyinfo->x_dnd_atoms_size *= 2;
-      dpyinfo->x_dnd_atoms = xrealloc (dpyinfo->x_dnd_atoms,
-                                       sizeof (*dpyinfo->x_dnd_atoms)
-                                       * dpyinfo->x_dnd_atoms_size);
-    }
+    dpyinfo->x_dnd_atoms =
+      xpalloc (dpyinfo->x_dnd_atoms, &dpyinfo->x_dnd_atoms_size,
+              1, -1, sizeof *dpyinfo->x_dnd_atoms);
 
   dpyinfo->x_dnd_atoms[dpyinfo->x_dnd_atoms_length++] = x_atom;
   return Qnil;
@@ -2761,11 +2520,8 @@ FRAME is on.  If FRAME is nil, the selected frame is used.  */)
 /* Convert an XClientMessageEvent to a Lisp event of type DRAG_N_DROP_EVENT.  */
 
 int
-x_handle_dnd_message (f, event, dpyinfo, bufp)
-     struct frame *f;
-     XClientMessageEvent *event;
-     struct x_display_info *dpyinfo;
-     struct input_event *bufp;
+x_handle_dnd_message (struct frame *f, XClientMessageEvent *event,
+                      struct x_display_info *dpyinfo, struct input_event *bufp)
 {
   Lisp_Object vec;
   Lisp_Object frame;
@@ -2774,7 +2530,7 @@ x_handle_dnd_message (f, event, dpyinfo, bufp)
   int x, y;
   unsigned char *data = (unsigned char *) event->data.b;
   int idata[5];
-  size_t i;
+  ptrdiff_t i;
 
   for (i = 0; i < dpyinfo->x_dnd_atoms_length; ++i)
     if (dpyinfo->x_dnd_atoms[i] == event->message_type) break;
@@ -2788,11 +2544,10 @@ x_handle_dnd_message (f, event, dpyinfo, bufp)
      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)
+  if (32 < BITS_PER_LONG && event->format == 32)
     {
-      int i;
       for (i = 0; i < 5; ++i) /* There are only 5 longs in a ClientMessage. */
-        idata[i] = (int) event->data.l[i];
+       idata[i] = event->data.l[i];
       data = (unsigned char *) idata;
     }
 
@@ -2844,31 +2599,43 @@ the Atom is sent.  If a value is a cons, it is converted to a 32 bit number
 with the high 16 bits from the car and the lower 16 bit from the cdr.
 If more values than fits into the event is given, the excessive values
 are ignored.  */)
-     (display, dest, from, message_type, format, values)
-     Lisp_Object display, dest, from, message_type, format, values;
+  (Lisp_Object display, Lisp_Object dest, Lisp_Object from,
+   Lisp_Object message_type, Lisp_Object format, Lisp_Object values)
+{
+  struct x_display_info *dpyinfo = check_x_display_info (display);
+
+  CHECK_STRING (message_type);
+  x_send_client_event (display, dest, from,
+                       XInternAtom (dpyinfo->display,
+                                    SSDATA (message_type),
+                                    False),
+                       format, values);
+
+  return Qnil;
+}
+
+void
+x_send_client_event (Lisp_Object display, Lisp_Object dest, Lisp_Object from,
+                     Atom message_type, Lisp_Object format, Lisp_Object values)
 {
   struct x_display_info *dpyinfo = check_x_display_info (display);
   Window wdest;
   XEvent event;
-  Lisp_Object cons;
-  int size;
   struct frame *f = check_x_frame (from);
   int to_root;
 
-  CHECK_STRING (message_type);
   CHECK_NUMBER (format);
   CHECK_CONS (values);
 
   if (x_check_property_data (values) == -1)
     error ("Bad data in VALUES, must be number, cons or string");
 
-  event.xclient.type = ClientMessage;
-  event.xclient.format = XFASTINT (format);
-
-  if (event.xclient.format != 8 && event.xclient.format != 16
-      && event.xclient.format != 32)
+  if (XINT (format) != 8 && XINT (format) != 16 && XINT (format) != 32)
     error ("FORMAT must be one of 8, 16 or 32");
 
+  event.xclient.type = ClientMessage;
+  event.xclient.format = XINT (format);
+
   if (FRAMEP (dest) || NILP (dest))
     {
       struct frame *fdest = check_x_frame (dest);
@@ -2876,37 +2643,24 @@ are ignored.  */)
     }
   else if (STRINGP (dest))
     {
-      if (strcmp (SDATA (dest), "PointerWindow") == 0)
+      if (strcmp (SSDATA (dest), "PointerWindow") == 0)
         wdest = PointerWindow;
-      else if (strcmp (SDATA (dest), "InputFocus") == 0)
+      else if (strcmp (SSDATA (dest), "InputFocus") == 0)
         wdest = InputFocus;
       else
         error ("DEST as a string must be one of PointerWindow or InputFocus");
     }
-  else if (INTEGERP (dest))
-    wdest = (Window) XFASTINT (dest);
-  else if (FLOATP (dest))
-    wdest =  (Window) XFLOAT_DATA (dest);
-  else if (CONSP (dest))
-    {
-      if (! NUMBERP (XCAR (dest)) || ! NUMBERP (XCDR (dest)))
-        error ("Both car and cdr for DEST must be numbers");
-      else
-        wdest = (Window) cons_to_long (dest);
-    }
+  else if (INTEGERP (dest) || FLOATP (dest) || CONSP (dest))
+    CONS_TO_INTEGER (dest, Window, wdest);
   else
     error ("DEST must be a frame, nil, string, number or cons");
 
   if (wdest == 0) wdest = dpyinfo->root_window;
   to_root = wdest == dpyinfo->root_window;
 
-  for (cons = values, size = 0; CONSP (cons); cons = XCDR (cons), ++size)
-    ;
-
   BLOCK_INPUT;
 
-  event.xclient.message_type
-    = XInternAtom (dpyinfo->display, SDATA (message_type), False);
+  event.xclient.message_type = message_type;
   event.xclient.display = dpyinfo->display;
 
   /* Some clients (metacity for example) expects sending window to be here
@@ -2931,13 +2685,11 @@ are ignored.  */)
   }
   x_uncatch_errors ();
   UNBLOCK_INPUT;
-
-  return Qnil;
 }
 
 \f
 void
-syms_of_xselect ()
+syms_of_xselect (void)
 {
   defsubr (&Sx_get_selection_internal);
   defsubr (&Sx_own_selection_internal);
@@ -2945,12 +2697,6 @@ syms_of_xselect ()
   defsubr (&Sx_selection_owner_p);
   defsubr (&Sx_selection_exists_p);
 
-#ifdef CUT_BUFFER_SUPPORT
-  defsubr (&Sx_get_cut_buffer_internal);
-  defsubr (&Sx_store_cut_buffer_internal);
-  defsubr (&Sx_rotate_cut_buffers_internal);
-#endif
-
   defsubr (&Sx_get_atom_name);
   defsubr (&Sx_send_client_message);
   defsubr (&Sx_register_dnd_atom);
@@ -2965,10 +2711,10 @@ syms_of_xselect ()
   property_change_reply = Fcons (Qnil, Qnil);
   staticpro (&property_change_reply);
 
-  Vselection_alist = Qnil;
-  staticpro (&Vselection_alist);
+  converted_selections = NULL;
+  conversion_fail_tag = None;
 
-  DEFVAR_LISP ("selection-converter-alist", &Vselection_converter_alist,
+  DEFVAR_LISP ("selection-converter-alist", Vselection_converter_alist,
               doc: /* An alist associating X Windows selection-types with functions.
 These functions are called to convert the selection, with three args:
 the name of the selection (typically `PRIMARY', `SECONDARY', or `CLIPBOARD');
@@ -2983,7 +2729,7 @@ means that a side-effect was executed,
 and there is no meaningful selection value.  */);
   Vselection_converter_alist = Qnil;
 
-  DEFVAR_LISP ("x-lost-selection-functions", &Vx_lost_selection_functions,
+  DEFVAR_LISP ("x-lost-selection-functions", Vx_lost_selection_functions,
               doc: /* A list of functions to be called when Emacs loses an X selection.
 \(This happens when some other X client makes its own selection
 or when a Lisp program explicitly clears the selection.)
@@ -2991,9 +2737,9 @@ The functions are called with one argument, the selection type
 \(a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD').  */);
   Vx_lost_selection_functions = Qnil;
 
-  DEFVAR_LISP ("x-sent-selection-functions", &Vx_sent_selection_functions,
+  DEFVAR_LISP ("x-sent-selection-functions", Vx_sent_selection_functions,
               doc: /* A list of functions to be called when Emacs answers a selection request.
-The functions are called with four arguments:
+The functions are called with three arguments:
   - the selection name (typically `PRIMARY', `SECONDARY', or `CLIPBOARD');
   - the selection-type which Emacs was asked to convert the
     selection into before sending (for example, `STRING' or `LENGTH');
@@ -3005,47 +2751,42 @@ This hook doesn't let you change the behavior of Emacs's selection replies,
 it merely informs you that they have happened.  */);
   Vx_sent_selection_functions = Qnil;
 
-  DEFVAR_INT ("x-selection-timeout", &x_selection_timeout,
+  DEFVAR_LISP ("x-select-enable-clipboard-manager",
+              Vx_select_enable_clipboard_manager,
+              doc: /* Whether to enable X clipboard manager support.
+If non-nil, then whenever Emacs is killed or an Emacs frame is deleted
+while owning the X clipboard, the clipboard contents are saved to the
+clipboard manager if one is present.  */);
+  Vx_select_enable_clipboard_manager = Qt;
+
+  DEFVAR_INT ("x-selection-timeout", x_selection_timeout,
              doc: /* Number of milliseconds to wait for a selection reply.
 If the selection owner doesn't reply in this time, we give up.
 A value of 0 means wait as long as necessary.  This is initialized from the
 \"*selectionTimeout\" resource.  */);
   x_selection_timeout = 0;
 
-  QPRIMARY   = intern_c_string ("PRIMARY");    staticpro (&QPRIMARY);
-  QSECONDARY = intern_c_string ("SECONDARY");  staticpro (&QSECONDARY);
-  QSTRING    = intern_c_string ("STRING");     staticpro (&QSTRING);
-  QINTEGER   = intern_c_string ("INTEGER");    staticpro (&QINTEGER);
-  QCLIPBOARD = intern_c_string ("CLIPBOARD");  staticpro (&QCLIPBOARD);
-  QTIMESTAMP = intern_c_string ("TIMESTAMP");  staticpro (&QTIMESTAMP);
-  QTEXT      = intern_c_string ("TEXT");       staticpro (&QTEXT);
-  QCOMPOUND_TEXT = intern_c_string ("COMPOUND_TEXT"); staticpro (&QCOMPOUND_TEXT);
-  QUTF8_STRING = intern_c_string ("UTF8_STRING"); staticpro (&QUTF8_STRING);
-  QDELETE    = intern_c_string ("DELETE");     staticpro (&QDELETE);
-  QMULTIPLE  = intern_c_string ("MULTIPLE");   staticpro (&QMULTIPLE);
-  QINCR      = intern_c_string ("INCR");               staticpro (&QINCR);
-  QEMACS_TMP = intern_c_string ("_EMACS_TMP_");        staticpro (&QEMACS_TMP);
-  QTARGETS   = intern_c_string ("TARGETS");    staticpro (&QTARGETS);
-  QATOM             = intern_c_string ("ATOM");                staticpro (&QATOM);
-  QATOM_PAIR = intern_c_string ("ATOM_PAIR");  staticpro (&QATOM_PAIR);
-  QNULL             = intern_c_string ("NULL");                staticpro (&QNULL);
-  Qcompound_text_with_extensions = intern_c_string ("compound-text-with-extensions");
-  staticpro (&Qcompound_text_with_extensions);
-
-#ifdef CUT_BUFFER_SUPPORT
-  QCUT_BUFFER0 = intern_c_string ("CUT_BUFFER0"); staticpro (&QCUT_BUFFER0);
-  QCUT_BUFFER1 = intern_c_string ("CUT_BUFFER1"); staticpro (&QCUT_BUFFER1);
-  QCUT_BUFFER2 = intern_c_string ("CUT_BUFFER2"); staticpro (&QCUT_BUFFER2);
-  QCUT_BUFFER3 = intern_c_string ("CUT_BUFFER3"); staticpro (&QCUT_BUFFER3);
-  QCUT_BUFFER4 = intern_c_string ("CUT_BUFFER4"); staticpro (&QCUT_BUFFER4);
-  QCUT_BUFFER5 = intern_c_string ("CUT_BUFFER5"); staticpro (&QCUT_BUFFER5);
-  QCUT_BUFFER6 = intern_c_string ("CUT_BUFFER6"); staticpro (&QCUT_BUFFER6);
-  QCUT_BUFFER7 = intern_c_string ("CUT_BUFFER7"); staticpro (&QCUT_BUFFER7);
-#endif
-
-  Qforeign_selection = intern_c_string ("foreign-selection");
-  staticpro (&Qforeign_selection);
+  /* QPRIMARY is defined in keyboard.c.  */
+  DEFSYM (QSECONDARY, "SECONDARY");
+  DEFSYM (QSTRING, "STRING");
+  DEFSYM (QINTEGER, "INTEGER");
+  DEFSYM (QCLIPBOARD, "CLIPBOARD");
+  DEFSYM (QTIMESTAMP, "TIMESTAMP");
+  DEFSYM (QTEXT, "TEXT");
+  DEFSYM (QCOMPOUND_TEXT, "COMPOUND_TEXT");
+  DEFSYM (QUTF8_STRING, "UTF8_STRING");
+  DEFSYM (QDELETE, "DELETE");
+  DEFSYM (QMULTIPLE, "MULTIPLE");
+  DEFSYM (QINCR, "INCR");
+  DEFSYM (QEMACS_TMP, "_EMACS_TMP_");
+  DEFSYM (QTARGETS, "TARGETS");
+  DEFSYM (QATOM, "ATOM");
+  DEFSYM (QATOM_PAIR, "ATOM_PAIR");
+  DEFSYM (QCLIPBOARD_MANAGER, "CLIPBOARD_MANAGER");
+  DEFSYM (QSAVE_TARGETS, "SAVE_TARGETS");
+  DEFSYM (QNULL, "NULL");
+  DEFSYM (Qcompound_text_with_extensions, "compound-text-with-extensions");
+  DEFSYM (Qforeign_selection, "foreign-selection");
+  DEFSYM (Qx_lost_selection_functions, "x-lost-selection-functions");
+  DEFSYM (Qx_sent_selection_functions, "x-sent-selection-functions");
 }
-
-/* arch-tag: 7c293b0f-9918-4f69-8ac7-03e142307236
-   (do not change this comment) */