]> code.delx.au - gnu-emacs/blobdiff - src/xselect.c
Remove buggy non-native image scrolling
[gnu-emacs] / src / xselect.c
index d90d056e960db8888758a4d8f9a8c01043f642d2..123e46374a28762a11796735070db22851748514 100644 (file)
@@ -1,12 +1,12 @@
 /* X Selection processing for Emacs.
-   Copyright (C) 1993-1997, 2000-2014 Free Software Foundation, Inc.
+   Copyright (C) 1993-1997, 2000-2016 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
 GNU Emacs is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -31,12 +31,8 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #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"
 #include "keyboard.h"
 
@@ -45,10 +41,10 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 struct prop_location;
 struct selection_data;
 
-static void x_decline_selection_request (struct input_event *);
-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 void x_decline_selection_request (struct selection_input_event *);
+static bool x_convert_selection (Lisp_Object, Lisp_Object, Atom, bool,
+                                struct x_display_info *);
+static bool 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 *);
@@ -79,30 +75,10 @@ static void lisp_data_to_selection_data (struct x_display_info *, Lisp_Object,
 #define TRACE2(fmt, a0, a1)    (void) 0
 #endif
 
-
-static Lisp_Object QSECONDARY, QSTRING, QINTEGER, QCLIPBOARD, QTIMESTAMP,
-  QTEXT, QDELETE, QMULTIPLE, QINCR, QEMACS_TMP, QTARGETS, QATOM, QNULL,
-  QATOM_PAIR, QCLIPBOARD_MANAGER, QSAVE_TARGETS;
-
-static Lisp_Object QCOMPOUND_TEXT;     /* This is a type of selection.  */
-static Lisp_Object QUTF8_STRING;       /* This is a type of selection.  */
-
-static Lisp_Object Qcompound_text_with_extensions;
-
-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
@@ -136,7 +112,7 @@ selection_quantum (Display *display)
 
 struct selection_event_queue
   {
-    struct input_event event;
+    struct selection_input_event event;
     struct selection_event_queue *next;
   };
 
@@ -146,10 +122,22 @@ static struct selection_event_queue *selection_queue;
 
 static int x_queue_selection_requests;
 
+/* True if the input events are duplicates.  */
+
+static bool
+selection_input_event_equal (struct selection_input_event *a,
+                            struct selection_input_event *b)
+{
+  return (a->kind == b->kind && a->dpyinfo == b->dpyinfo
+         && a->requestor == b->requestor && a->selection == b->selection
+         && a->target == b->target && a->property == b->property
+         && a->time == b->time);
+}
+
 /* Queue up an SELECTION_REQUEST_EVENT *EVENT, to be processed later.  */
 
 static void
-x_queue_event (struct input_event *event)
+x_queue_event (struct selection_input_event *event)
 {
   struct selection_event_queue *queue_tmp;
 
@@ -157,7 +145,7 @@ x_queue_event (struct input_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 (!memcmp (&queue_tmp->event, event, sizeof (*event)))
+      if (selection_input_event_equal (event, &queue_tmp->event))
        {
          TRACE1 ("DECLINE DUP SELECTION EVENT %p", queue_tmp);
          x_decline_selection_request (event);
@@ -324,7 +312,7 @@ x_own_selection (Lisp_Object selection_name, Lisp_Object selection_value,
   x_catch_errors (display);
   XSetSelectionOwner (display, selection_atom, selecting_window, timestamp);
   x_check_errors (display, "Can't set selection: %s");
-  x_uncatch_errors ();
+  x_uncatch_errors_after_check ();
   unblock_input ();
 
   /* Now update the local cache */
@@ -367,7 +355,7 @@ x_own_selection (Lisp_Object selection_name, Lisp_Object selection_value,
 
 static Lisp_Object
 x_get_local_selection (Lisp_Object selection_symbol, Lisp_Object target_type,
-                      int local_request, struct x_display_info *dpyinfo)
+                      bool local_request, struct x_display_info *dpyinfo)
 {
   Lisp_Object local_value;
   Lisp_Object handler_fn, value, check;
@@ -392,8 +380,6 @@ x_get_local_selection (Lisp_Object selection_symbol, Lisp_Object target_type,
 
       CHECK_SYMBOL (target_type);
       handler_fn = Fcdr (Fassq (target_type, Vselection_converter_alist));
-      /* gcpro is not needed here since nothing but HANDLER_FN
-        is live, and that ought to be a symbol.  */
 
       if (!NILP (handler_fn))
        value = call3 (handler_fn,
@@ -438,7 +424,7 @@ x_get_local_selection (Lisp_Object selection_symbol, Lisp_Object target_type,
    meaning we were unable to do what they wanted.  */
 
 static void
-x_decline_selection_request (struct input_event *event)
+x_decline_selection_request (struct selection_input_event *event)
 {
   XEvent reply_base;
   XSelectionEvent *reply = &(reply_base.xselection);
@@ -463,7 +449,7 @@ x_decline_selection_request (struct input_event *event)
 
 /* This is the selection request currently being processed.
    It is set to zero when the request is fully processed.  */
-static struct input_event *x_selection_current_request;
+static struct selection_input_event *x_selection_current_request;
 
 /* Display info in x_selection_request.  */
 
@@ -477,7 +463,7 @@ struct selection_data
   ptrdiff_t size;
   int format;
   Atom type;
-  int nofree;
+  bool 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
@@ -505,7 +491,7 @@ x_selection_request_lisp_error (void)
   for (cs = converted_selections; cs; cs = next)
     {
       next = cs->next;
-      if (cs->nofree == 0 && cs->data)
+      if (! cs->nofree && cs->data)
        xfree (cs->data);
       xfree (cs);
     }
@@ -538,7 +524,7 @@ struct prop_location
   Window window;
   Atom property;
   int desired_state;
-  int arrived;
+  bool arrived;
   struct prop_location *next;
 };
 
@@ -550,6 +536,16 @@ static struct prop_location *property_change_reply_object;
 
 static struct prop_location *property_change_wait_list;
 
+static void
+set_property_change_object (struct prop_location *location)
+{
+  /* Input must be blocked so we don't get the event before we set these.  */
+  if (! input_blocked_p ())
+    emacs_abort ();
+  XSETCAR (property_change_reply, Qnil);
+  property_change_reply_object = location;
+}
+
 \f
 /* Send the reply to a selection request event EVENT.  */
 
@@ -558,7 +554,7 @@ static int x_reply_selection_request_cnt;
 #endif  /* TRACE_SELECTION */
 
 static void
-x_reply_selection_request (struct input_event *event,
+x_reply_selection_request (struct selection_input_event *event,
                            struct x_display_info *dpyinfo)
 {
   XEvent reply_base;
@@ -652,6 +648,11 @@ x_reply_selection_request (struct input_event *event,
       {
        int format_bytes = cs->format / 8;
        bool had_errors_p = x_had_errors_p (display);
+
+        /* Must set this inside block_input ().  unblock_input may read
+           events and setting property_change_reply in
+           wait_for_property_change is then too late.  */
+        set_property_change_object (cs->wait_object);
        unblock_input ();
 
        bytes_remaining = cs->size;
@@ -692,6 +693,8 @@ x_reply_selection_request (struct input_event *event,
                             : format_bytes);
            XFlush (display);
            had_errors_p = x_had_errors_p (display);
+            // See comment above about property_change_reply.
+            set_property_change_object (cs->wait_object);
            unblock_input ();
 
            if (had_errors_p) break;
@@ -742,9 +745,8 @@ x_reply_selection_request (struct input_event *event,
    This is called from keyboard.c when such an event is found in the queue.  */
 
 static void
-x_handle_selection_request (struct input_event *event)
+x_handle_selection_request (struct selection_input_event *event)
 {
-  struct gcpro gcpro1, gcpro2;
   Time local_selection_time;
 
   struct x_display_info *dpyinfo = SELECTION_EVENT_DPYINFO (event);
@@ -754,9 +756,8 @@ x_handle_selection_request (struct input_event *event)
   Lisp_Object target_symbol = x_atom_to_symbol (dpyinfo, target);
   Atom property = SELECTION_EVENT_PROPERTY (event);
   Lisp_Object local_selection_data;
-  int success = 0;
+  bool success = false;
   ptrdiff_t count = SPECPDL_INDEX ();
-  GCPRO2 (local_selection_data, target_symbol);
 
   if (!dpyinfo) goto DONE;
 
@@ -811,18 +812,18 @@ x_handle_selection_request (struct input_event *event)
                                               AREF (multprop, 2*j+1));
 
          if (subproperty != None)
-           x_convert_selection (event, selection_symbol, subtarget,
-                                subproperty, 1, dpyinfo);
+           x_convert_selection (selection_symbol, subtarget,
+                                subproperty, true, dpyinfo);
        }
-      success = 1;
+      success = true;
     }
   else
     {
       if (property == None)
        property = SELECTION_EVENT_TARGET (event);
-      success = x_convert_selection (event, selection_symbol,
+      success = x_convert_selection (selection_symbol,
                                     target_symbol, property,
-                                    0, dpyinfo);
+                                    false, dpyinfo);
     }
 
  DONE:
@@ -836,39 +837,30 @@ x_handle_selection_request (struct input_event *event)
   /* 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);
-    }
+    CALLN (Frun_hook_with_args, Qx_sent_selection_functions,
+          selection_symbol, target_symbol, success ? Qt : Qnil);
 
   unbind_to (count, Qnil);
-  UNGCPRO;
 }
 
 /* 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
+   x_reply_selection_request.  If FOR_MULTIPLE, write out
    the data even if conversion fails, using conversion_fail_tag.
 
-   Return 0 if the selection failed to convert, 1 otherwise.  */
+   Return true iff successful.  */
 
-static int
-x_convert_selection (struct input_event *event, Lisp_Object selection_symbol,
+static bool
+x_convert_selection (Lisp_Object selection_symbol,
                     Lisp_Object target_symbol, Atom property,
-                    int for_multiple, struct x_display_info *dpyinfo)
+                    bool 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);
+                            false, dpyinfo);
 
   /* A nil return value means we can't perform the conversion.  */
   if (NILP (lisp_selection)
@@ -881,28 +873,26 @@ x_convert_selection (struct input_event *event, Lisp_Object selection_symbol,
          cs->size = 1;
          cs->format = 32;
          cs->type = XA_ATOM;
-         cs->nofree = 1;
+         cs->nofree = true;
          cs->property = property;
          cs->wait_object = NULL;
          cs->next = converted_selections;
          converted_selections = cs;
        }
 
-      UNGCPRO;
-      return 0;
+      return false;
     }
 
   /* Otherwise, record the converted selection to binary.  */
   cs = xmalloc (sizeof *cs);
   cs->data = NULL;
-  cs->nofree = 1;
+  cs->nofree = true;
   cs->property = property;
   cs->wait_object = NULL;
   cs->next = converted_selections;
   converted_selections = cs;
   lisp_data_to_selection_data (dpyinfo, lisp_selection, cs);
-  UNGCPRO;
-  return 1;
+  return true;
 }
 \f
 /* Handle a SelectionClear event EVENT, which indicates that some
@@ -910,7 +900,7 @@ x_convert_selection (struct input_event *event, Lisp_Object selection_symbol,
    This is called from keyboard.c when such an event is found in the queue.  */
 
 static void
-x_handle_selection_clear (struct input_event *event)
+x_handle_selection_clear (struct selection_input_event *event)
 {
   Atom selection = SELECTION_EVENT_SELECTION (event);
   Time changed_owner_time = SELECTION_EVENT_TIME (event);
@@ -956,18 +946,13 @@ x_handle_selection_clear (struct input_event *event)
   tset_selection_alist (dpyinfo->terminal, Vselection_alist);
 
   /* Run the `x-lost-selection-functions' abnormal hook.  */
-  {
-    Lisp_Object args[2];
-    args[0] = Qx_lost_selection_functions;
-    args[1] = selection_symbol;
-    Frun_hook_with_args (2, args);
-  }
+  CALLN (Frun_hook_with_args, Qx_lost_selection_functions, selection_symbol);
 
   redisplay_preserve_echo_area (20);
 }
 
 void
-x_handle_selection_event (struct input_event *event)
+x_handle_selection_event (struct selection_input_event *event)
 {
   TRACE0 ("x_handle_selection_event");
   if (event->kind != SELECTION_REQUEST_EVENT)
@@ -997,10 +982,8 @@ x_clear_frame_selections (struct frame *f)
         && EQ (frame, XCAR (XCDR (XCDR (XCDR (XCAR (t->Vselection_alist)))))))
     {
       /* 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);
+      CALLN (Frun_hook_with_args, Qx_lost_selection_functions,
+            Fcar (Fcar (t->Vselection_alist)));
 
       tset_selection_alist (t, XCDR (t->Vselection_alist));
     }
@@ -1010,28 +993,23 @@ x_clear_frame_selections (struct frame *f)
     if (CONSP (XCDR (rest))
        && EQ (frame, XCAR (XCDR (XCDR (XCDR (XCAR (XCDR (rest))))))))
       {
-       Lisp_Object args[2];
-       args[0] = Qx_lost_selection_functions;
-       args[1] = XCAR (XCAR (XCDR (rest)));
-       Frun_hook_with_args (2, args);
+       CALLN (Frun_hook_with_args, Qx_lost_selection_functions,
+              XCAR (XCAR (XCDR (rest))));
        XSETCDR (rest, XCDR (XCDR (rest)));
        break;
       }
 }
 \f
-/* Nonzero if any properties for DISPLAY and WINDOW
+/* True if any properties for DISPLAY and WINDOW
    are on the list of what we are waiting for.  */
 
-static int
+static bool
 waiting_for_other_props_on_window (Display *display, Window window)
 {
-  struct prop_location *rest = property_change_wait_list;
-  while (rest)
-    if (rest->display == display && rest->window == window)
-      return 1;
-    else
-      rest = rest->next;
-  return 0;
+  for (struct prop_location *p = property_change_wait_list; p; p = p->next)
+    if (p->display == display && p->window == window)
+      return true;
+  return false;
 }
 
 /* Add an entry to the list of property changes we are waiting for.
@@ -1050,7 +1028,7 @@ expect_property_change (Display *display, Window window,
   pl->property = property;
   pl->desired_state = state;
   pl->next = property_change_wait_list;
-  pl->arrived = 0;
+  pl->arrived = false;
   property_change_wait_list = pl;
   return pl;
 }
@@ -1096,14 +1074,11 @@ wait_for_property_change (struct prop_location *location)
 {
   ptrdiff_t count = SPECPDL_INDEX ();
 
-  if (property_change_reply_object)
-    emacs_abort ();
-
   /* Make sure to do unexpect_property_change if we quit or err.  */
   record_unwind_protect_ptr (wait_for_property_change_unwind, location);
 
-  XSETCAR (property_change_reply, Qnil);
-  property_change_reply_object = location;
+  /* See comment in x_reply_selection_request about setting
+     property_change_reply.  Do not do it here.  */
 
   /* If the event we are waiting for arrives beyond here, it will set
      property_change_reply, because property_change_reply_object says so.  */
@@ -1113,7 +1088,7 @@ wait_for_property_change (struct prop_location *location)
       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,
+      wait_reading_process_output (secs, nsecs, 0, false,
                                   property_change_reply, NULL, 0);
 
       if (NILP (XCAR (property_change_reply)))
@@ -1145,7 +1120,7 @@ x_handle_property_notify (const XPropertyEvent *event)
                  (event->state == PropertyDelete ? "deletion" : "change"),
                  XGetAtomName (event->display, event->atom));
 
-         rest->arrived = 1;
+         rest->arrived = true;
 
          /* If this is the one wait_for_property_change is waiting for,
             tell it to wake up.  */
@@ -1200,7 +1175,7 @@ x_get_foreign_selection (Lisp_Object selection_symbol, Lisp_Object target_type,
   XConvertSelection (display, selection_atom, type_atom, target_property,
                     requestor_window, requestor_time);
   x_check_errors (display, "Can't convert selection: %s");
-  x_uncatch_errors ();
+  x_uncatch_errors_after_check ();
 
   /* Prepare to block until the reply has been read.  */
   reading_selection_window = requestor_window;
@@ -1211,7 +1186,7 @@ x_get_foreign_selection (Lisp_Object selection_symbol, Lisp_Object target_type,
      during this time.  In fact, the SAVE_TARGETS mechanism requires
      us to handle a clipboard manager's requests before it returns
      SelectionNotify. */
-#if 0
+#if false
   x_start_queuing_selection_requests ();
   record_unwind_protect_void (x_stop_queuing_selection_requests);
 #endif
@@ -1223,7 +1198,7 @@ x_get_foreign_selection (Lisp_Object selection_symbol, Lisp_Object target_type,
   secs = timeout / 1000;
   nsecs = (timeout % 1000) * 1000000;
   TRACE1 ("  Start waiting %"pI"d secs for SelectionNotify", secs);
-  wait_reading_process_output (secs, nsecs, 0, 0,
+  wait_reading_process_output (secs, nsecs, 0, false,
                               reading_selection_reply, NULL, 0);
   TRACE1 ("  Got event = %d", !NILP (XCAR (reading_selection_reply)));
 
@@ -1247,7 +1222,7 @@ static void
 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)
+                      unsigned long *actual_size_ret)
 {
   ptrdiff_t total_size;
   unsigned long bytes_remaining;
@@ -1418,9 +1393,11 @@ receive_incremental_selection (struct x_display_info *dpyinfo,
   wait_object = expect_property_change (display, window, property,
                                        PropertyNewValue);
   XFlush (display);
+  // See comment in x_reply_selection_request about property_change_reply.
+  set_property_change_object (wait_object);
   unblock_input ();
 
-  while (1)
+  while (true)
     {
       unsigned char *tmp_data;
       ptrdiff_t tmp_size_bytes;
@@ -1434,7 +1411,7 @@ receive_incremental_selection (struct x_display_info *dpyinfo,
       TRACE0 ("  Get property value");
       x_get_window_property (display, window, property,
                             &tmp_data, &tmp_size_bytes,
-                            type_ret, format_ret, size_ret, 1);
+                            type_ret, format_ret, size_ret);
 
       TRACE1 ("  Read increment of %"pD"d bytes", tmp_size_bytes);
 
@@ -1456,6 +1433,8 @@ receive_incremental_selection (struct x_display_info *dpyinfo,
       XDeleteProperty (display, window, property);
       wait_object = expect_property_change (display, window, property,
                                            PropertyNewValue);
+      // See comment in x_reply_selection_request about property_change_reply.
+      set_property_change_object (wait_object);
       XFlush (display);
       unblock_input ();
 
@@ -1495,13 +1474,12 @@ x_get_window_property_as_lisp_data (struct x_display_info *dpyinfo,
   TRACE0 ("Reading selection data");
 
   x_get_window_property (display, window, property, &data, &bytes,
-                        &actual_type, &actual_format, &actual_size, 1);
+                        &actual_type, &actual_format, &actual_size);
   if (! data)
     {
-      int there_is_a_selection_owner;
       block_input ();
-      there_is_a_selection_owner
-       = XGetSelectionOwner (display, selection_atom);
+      bool there_is_a_selection_owner
+       = XGetSelectionOwner (display, selection_atom) != 0;
       unblock_input ();
       if (there_is_a_selection_owner)
        signal_error ("Selection owner couldn't convert",
@@ -1694,7 +1672,7 @@ lisp_data_to_selection_data (struct x_display_info *dpyinfo,
   Lisp_Object type = Qnil;
 
   eassert (cs != NULL);
-  cs->nofree = 0;
+  cs->nofree = false;
 
   if (CONSP (obj) && SYMBOLP (XCAR (obj)))
     {
@@ -1721,7 +1699,7 @@ lisp_data_to_selection_data (struct x_display_info *dpyinfo,
       cs->format = 8;
       cs->size = SBYTES (obj);
       cs->data = SDATA (obj);
-      cs->nofree = 1;
+      cs->nofree = true;
     }
   else if (SYMBOLP (obj))
     {
@@ -1908,7 +1886,7 @@ frame_for_x_selection (Lisp_Object object)
     }
   else if (TERMINALP (object))
     {
-      struct terminal *t = get_terminal (object, 1);
+      struct terminal *t = decode_live_terminal (object);
 
       if (t->type == output_x_window)
        FOR_EACH_FRAME (tail, frame)
@@ -1977,9 +1955,7 @@ On Nextstep, TIME-STAMP and TERMINAL are unused.  */)
    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_SYMBOL (selection_symbol);
   CHECK_SYMBOL (target_type);
@@ -1988,15 +1964,15 @@ On Nextstep, TIME-STAMP and TERMINAL are unused.  */)
   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, true,
                               FRAME_DISPLAY_INFO (f));
 
   if (NILP (val) && FRAME_LIVE_P (f))
     {
       Lisp_Object frame;
       XSETFRAME (frame, f);
-      RETURN_UNGCPRO (x_get_foreign_selection (selection_symbol, target_type,
-                                              time_stamp, frame));
+      return x_get_foreign_selection (selection_symbol, target_type,
+                                     time_stamp, frame);
     }
 
   if (CONSP (val) && SYMBOLP (XCAR (val)))
@@ -2005,7 +1981,7 @@ On Nextstep, TIME-STAMP and TERMINAL are unused.  */)
       if (CONSP (val) && NILP (XCDR (val)))
        val = XCAR (val);
     }
-  RETURN_UNGCPRO (clean_local_selection_data (val));
+  return clean_local_selection_data (val);
 }
 
 DEFUN ("x-disown-selection-internal", Fx_disown_selection_internal,
@@ -2026,10 +2002,7 @@ On MS-DOS, all this does is return non-nil if we own the selection.  */)
 {
   Time timestamp;
   Atom selection_atom;
-  union {
-    struct selection_input_event sie;
-    struct input_event ie;
-  } event;
+  struct selection_input_event event;
   struct frame *f = frame_for_x_selection (terminal);
   struct x_display_info *dpyinfo;
 
@@ -2058,10 +2031,10 @@ On MS-DOS, all this does is return non-nil if we own the 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_DPYINFO (&event.sie) = dpyinfo;
-  SELECTION_EVENT_SELECTION (&event.sie) = selection_atom;
-  SELECTION_EVENT_TIME (&event.sie) = timestamp;
-  x_handle_selection_clear (&event.ie);
+  SELECTION_EVENT_DPYINFO (&event) = dpyinfo;
+  SELECTION_EVENT_SELECTION (&event) = selection_atom;
+  SELECTION_EVENT_TIME (&event) = timestamp;
+  x_handle_selection_clear (&event);
 
   return Qt;
 }
@@ -2159,10 +2132,10 @@ x_clipboard_manager_save (Lisp_Object frame)
 static Lisp_Object
 x_clipboard_manager_error_1 (Lisp_Object err)
 {
-  Fmessage (2, ((Lisp_Object [])
-    { SCOPED_STRING ("X clipboard manager error: %s\n\
-If the problem persists, set `x-select-enable-clipboard-manager' to nil."),
-      CAR (CDR (err)) }));
+  AUTO_STRING (format, "X clipboard manager error: %s\n\
+If the problem persists, set `%s' to nil.");
+  AUTO_STRING (varname, "x-select-enable-clipboard-manager");
+  CALLN (Fmessage, format, CAR (CDR (err)), varname);
   return Qnil;
 }
 
@@ -2172,8 +2145,8 @@ static Lisp_Object
 x_clipboard_manager_error_2 (Lisp_Object err)
 {
   fprintf (stderr, "Error saving to X clipboard manager.\n\
-If the problem persists, set `x-select-enable-clipboard-manager' \
-to nil.\n");
+If the problem persists, set '%s' \
+to nil.\n", "x-select-enable-clipboard-manager");
   return Qnil;
 }
 
@@ -2229,9 +2202,7 @@ x_clipboard_manager_save_all (void)
       local_frame = XCAR (XCDR (XCDR (XCDR (local_selection))));
       if (FRAME_LIVE_P (XFRAME (local_frame)))
        {
-         Fmessage (1, ((Lisp_Object [])
-           { SCOPED_STRING
-               ("Saving clipboard to X clipboard manager...") }));
+         message ("Saving clipboard to X clipboard manager...");
          internal_condition_case_1 (x_clipboard_manager_save, local_frame,
                                     Qt, x_clipboard_manager_error_2);
        }
@@ -2286,32 +2257,32 @@ x_check_property_data (Lisp_Object data)
 void
 x_fill_property_data (Display *dpy, Lisp_Object data, void *ret, int format)
 {
-  long val;
-  long  *d32 = (long  *) ret;
-  short *d16 = (short *) ret;
-  char  *d08 = (char  *) ret;
+  unsigned long val;
+  unsigned long  *d32 = (unsigned long  *) ret;
+  unsigned short *d16 = (unsigned short *) ret;
+  unsigned char  *d08 = (unsigned char  *) ret;
   Lisp_Object iter;
 
   for (iter = data; CONSP (iter); iter = XCDR (iter))
     {
       Lisp_Object o = XCAR (iter);
 
-      if (INTEGERP (o) || FLOATP (o) || CONSP (o))
+      if (NUMBERP (o) || CONSP (o))
         {
           if (CONSP (o)
              && RANGED_INTEGERP (X_LONG_MIN >> 16, XCAR (o), X_LONG_MAX >> 16)
              && RANGED_INTEGERP (- (1 << 15), XCDR (o), -1))
             {
-              long v1 = XINT (XCAR (o));
-              long v2 = XINT (XCDR (o));
-              /* cons_to_signed does not handle negative values for v2.
+             /* cons_to_x_long does not handle negative values for v2.
                  For XDnd, v2 might be y of a window, and can be negative.
                  The XDnd spec. is not explicit about negative values,
                  but let's assume negative v2 is sent modulo 2**16.  */
-             val = (v1 << 16) | (v2 & 0xffff);
+             unsigned long v1 = XINT (XCAR (o)) & 0xffff;
+             unsigned long v2 = XINT (XCDR (o)) & 0xffff;
+             val = (v1 << 16) | v2;
             }
           else
-            val = cons_to_signed (o, X_LONG_MIN, X_LONG_MAX);
+            val = cons_to_x_long (o);
         }
       else if (STRINGP (o))
         {
@@ -2324,17 +2295,15 @@ x_fill_property_data (Display *dpy, Lisp_Object data, void *ret, int format)
 
       if (format == 8)
        {
-         if (CHAR_MIN <= val && val <= CHAR_MAX)
-           *d08++ = val;
-         else
+         if ((1 << 8) < val && val <= X_ULONG_MAX - (1 << 7))
            error ("Out of 'char' range");
+         *d08++ = val;
        }
       else if (format == 16)
        {
-         if (X_SHRT_MIN <= val && val <= X_SHRT_MAX)
-           *d16++ = val;
-         else
+         if ((1 << 16) < val && val <= X_ULONG_MAX - (1 << 15))
            error ("Out of 'short' range");
+         *d16++ = val;
        }
       else
         *d32++ = val;
@@ -2361,10 +2330,11 @@ x_property_data_to_lisp (struct frame *f, const unsigned char *data,
                         Atom type, int format, unsigned long size)
 {
   ptrdiff_t format_bytes = format >> 3;
-  if (PTRDIFF_MAX / format_bytes < size)
+  ptrdiff_t data_bytes;
+  if (INT_MULTIPLY_WRAPV (size, format_bytes, &data_bytes))
     memory_full (SIZE_MAX);
   return selection_data_to_lisp_data (FRAME_DISPLAY_INFO (f), data,
-                                     size * format_bytes, type, format);
+                                     data_bytes, type, format);
 }
 
 DEFUN ("x-get-atom-name", Fx_get_atom_name,
@@ -2391,7 +2361,7 @@ If the value is 0 or the atom is not known, return the empty string.  */)
   x_catch_errors (dpy);
   name = atom ? XGetAtomName (dpy, atom) : empty;
   had_errors_p = x_had_errors_p (dpy);
-  x_uncatch_errors ();
+  x_uncatch_errors_after_check ();
 
   if (!had_errors_p)
     ret = build_string (name);
@@ -2443,7 +2413,7 @@ 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
+bool
 x_handle_dnd_message (struct frame *f, const XClientMessageEvent *event,
                       struct x_display_info *dpyinfo, struct input_event *bufp)
 {
@@ -2459,7 +2429,7 @@ x_handle_dnd_message (struct frame *f, const XClientMessageEvent *event,
   for (i = 0; i < dpyinfo->x_dnd_atoms_length; ++i)
     if (dpyinfo->x_dnd_atoms[i] == event->message_type) break;
 
-  if (i == dpyinfo->x_dnd_atoms_length) return 0;
+  if (i == dpyinfo->x_dnd_atoms_length) return false;
 
   XSETFRAME (frame, f);
 
@@ -2495,7 +2465,7 @@ x_handle_dnd_message (struct frame *f, const XClientMessageEvent *event,
   bufp->arg = vec;
   bufp->modifiers = 0;
 
-  return 1;
+  return true;
 }
 
 DEFUN ("x-send-client-message", Fx_send_client_message,
@@ -2546,7 +2516,7 @@ x_send_client_event (Lisp_Object display, Lisp_Object dest, Lisp_Object from,
   Window wdest;
   XEvent event;
   struct frame *f = decode_window_system_frame (from);
-  int to_root;
+  bool to_root;
 
   CHECK_NUMBER (format);
   CHECK_CONS (values);
@@ -2574,7 +2544,7 @@ x_send_client_event (Lisp_Object display, Lisp_Object dest, Lisp_Object from,
       else
         error ("DEST as a string must be one of PointerWindow or InputFocus");
     }
-  else if (INTEGERP (dest) || FLOATP (dest) || CONSP (dest))
+  else if (NUMBERP (dest) || CONSP (dest))
     CONS_TO_INTEGER (dest, Window, wdest);
   else
     error ("DEST must be a frame, nil, string, number or cons");
@@ -2603,7 +2573,7 @@ x_send_client_event (Lisp_Object display, Lisp_Object dest, Lisp_Object from,
      event then goes to clients selecting for events on the root window.  */
   x_catch_errors (dpyinfo->display);
   {
-    int propagate = to_root ? False : True;
+    bool propagate = !to_root;
     long mask = to_root ? 0xffffff : 0;
 
     XSendEvent (dpyinfo->display, wdest, propagate, mask, &event);
@@ -2640,12 +2610,14 @@ syms_of_xselect (void)
   converted_selections = NULL;
   conversion_fail_tag = None;
 
+  /* FIXME: Duplicate definition in nsselect.c.  */
   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');
 a desired type to which the selection should be converted;
-and the local selection value (whatever was given to `x-own-selection').
+and the local selection value (whatever was given to
+`x-own-selection-internal').
 
 The function should return the value to send to the X server
 \(typically a string).  A return value of nil
@@ -2699,19 +2671,20 @@ A value of 0 means wait as long as necessary.  This is initialized from the
   DEFSYM (QCLIPBOARD, "CLIPBOARD");
   DEFSYM (QTIMESTAMP, "TIMESTAMP");
   DEFSYM (QTEXT, "TEXT");
+
+  /* These are types of selection.  */
   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");