(fix_submap_inheritance, get_keyelt, store_in_keymap,
[bpt/emacs.git] / src / xselect.c
index b7360a1..ec8d2af 100644 (file)
@@ -1,5 +1,5 @@
 /* X Selection processing for Emacs.
 /* X Selection processing for Emacs.
-   Copyright (C) 1993, 1994, 1995 Free Software Foundation.
+   Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation.
 
 This file is part of GNU Emacs.
 
 
 This file is part of GNU Emacs.
 
@@ -15,7 +15,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 /* Rewritten by jwz */
 
 
 /* Rewritten by jwz */
@@ -26,8 +27,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #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 "dispextern.h"        /* frame.h seems to want this */
 #include "frame.h"     /* Need this to get the X window of selected_frame */
 #include "blockinput.h"
-
-#define xfree free
+#include "buffer.h"
+#include "charset.h"
+#include "coding.h"
 
 #define CUT_BUFFER_SUPPORT
 
 
 #define CUT_BUFFER_SUPPORT
 
@@ -35,6 +37,8 @@ Lisp_Object QPRIMARY, QSECONDARY, QSTRING, QINTEGER, QCLIPBOARD, QTIMESTAMP,
   QTEXT, QDELETE, QMULTIPLE, QINCR, QEMACS_TMP, QTARGETS, QATOM, QNULL,
   QATOM_PAIR;
 
   QTEXT, QDELETE, QMULTIPLE, QINCR, QEMACS_TMP, QTARGETS, QATOM, QNULL,
   QATOM_PAIR;
 
+Lisp_Object QCOMPOUND_TEXT;    /* 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;
 #ifdef CUT_BUFFER_SUPPORT
 Lisp_Object QCUT_BUFFER0, QCUT_BUFFER1, QCUT_BUFFER2, QCUT_BUFFER3,
   QCUT_BUFFER4, QCUT_BUFFER5, QCUT_BUFFER6, QCUT_BUFFER7;
@@ -42,6 +46,9 @@ Lisp_Object QCUT_BUFFER0, QCUT_BUFFER1, QCUT_BUFFER2, QCUT_BUFFER3,
 
 static Lisp_Object Vx_lost_selection_hooks;
 static Lisp_Object Vx_sent_selection_hooks;
 
 static Lisp_Object Vx_lost_selection_hooks;
 static Lisp_Object Vx_sent_selection_hooks;
+/* Coding system for communicating with other X clients via cutbuffer,
+   selection, and clipboard.  */
+static Lisp_Object Vclipboard_coding_system;
 
 /* 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
 
 /* 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
@@ -58,7 +65,8 @@ static Lisp_Object Vx_sent_selection_hooks;
 #endif
 
 /* The timestamp of the last input event Emacs received from the X server.  */
 #endif
 
 /* The timestamp of the last input event Emacs received from the X server.  */
-unsigned long last_event_timestamp;
+/* 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)
 
 /* This is an association list whose elements are of the form
      ( SELECTION-NAME SELECTION-VALUE SELECTION-TIMESTAMP FRAME)
@@ -110,6 +118,7 @@ symbol_to_x_atom (dpyinfo, display, sym)
   if (EQ (sym, QCLIPBOARD)) return dpyinfo->Xatom_CLIPBOARD;
   if (EQ (sym, QTIMESTAMP)) return dpyinfo->Xatom_TIMESTAMP;
   if (EQ (sym, QTEXT))     return dpyinfo->Xatom_TEXT;
   if (EQ (sym, QCLIPBOARD)) return dpyinfo->Xatom_CLIPBOARD;
   if (EQ (sym, QTIMESTAMP)) return dpyinfo->Xatom_TIMESTAMP;
   if (EQ (sym, QTEXT))     return dpyinfo->Xatom_TEXT;
+  if (EQ (sym, QCOMPOUND_TEXT)) return dpyinfo->Xatom_COMPOUND_TEXT;
   if (EQ (sym, QDELETE))    return dpyinfo->Xatom_DELETE;
   if (EQ (sym, QMULTIPLE))  return dpyinfo->Xatom_MULTIPLE;
   if (EQ (sym, QINCR))     return dpyinfo->Xatom_INCR;
   if (EQ (sym, QDELETE))    return dpyinfo->Xatom_DELETE;
   if (EQ (sym, QMULTIPLE))  return dpyinfo->Xatom_MULTIPLE;
   if (EQ (sym, QINCR))     return dpyinfo->Xatom_INCR;
@@ -188,6 +197,8 @@ x_atom_to_symbol (dpyinfo, display, atom)
     return QTIMESTAMP;
   if (atom == dpyinfo->Xatom_TEXT)
     return QTEXT;
     return QTIMESTAMP;
   if (atom == dpyinfo->Xatom_TEXT)
     return QTEXT;
+  if (atom == dpyinfo->Xatom_COMPOUND_TEXT)
+    return QCOMPOUND_TEXT;
   if (atom == dpyinfo->Xatom_DELETE)
     return QDELETE;
   if (atom == dpyinfo->Xatom_MULTIPLE)
   if (atom == dpyinfo->Xatom_DELETE)
     return QDELETE;
   if (atom == dpyinfo->Xatom_MULTIPLE)
@@ -210,6 +221,7 @@ x_atom_to_symbol (dpyinfo, display, atom)
   if (! str) return Qnil;
   val = intern (str);
   BLOCK_INPUT;
   if (! str) return Qnil;
   val = intern (str);
   BLOCK_INPUT;
+  /* This was allocated by Xlib, so use XFree.  */
   XFree (str);
   UNBLOCK_INPUT;
   return val;
   XFree (str);
   UNBLOCK_INPUT;
   return val;
@@ -228,15 +240,16 @@ x_own_selection (selection_name, selection_value)
   Time time = last_event_timestamp;
   Atom selection_atom;
   struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (selected_frame);
   Time time = last_event_timestamp;
   Atom selection_atom;
   struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (selected_frame);
+  int count;
 
   CHECK_SYMBOL (selection_name, 0);
   selection_atom = symbol_to_x_atom (dpyinfo, display, selection_name);
 
   BLOCK_INPUT;
 
   CHECK_SYMBOL (selection_name, 0);
   selection_atom = symbol_to_x_atom (dpyinfo, display, selection_name);
 
   BLOCK_INPUT;
-  x_catch_errors (display);
+  count = x_catch_errors (display);
   XSetSelectionOwner (display, selection_atom, selecting_window, time);
   x_check_errors (display, "Can't set selection: %s");
   XSetSelectionOwner (display, selection_atom, selecting_window, time);
   x_check_errors (display, "Can't set selection: %s");
-  x_uncatch_errors (display);
+  x_uncatch_errors (display, count);
   UNBLOCK_INPUT;
 
   /* Now update the local cache */
   UNBLOCK_INPUT;
 
   /* Now update the local cache */
@@ -412,7 +425,7 @@ x_decline_selection_request (event)
 static struct input_event *x_selection_current_request;
 
 /* Used as an unwind-protect clause so that, if a selection-converter signals
 static struct input_event *x_selection_current_request;
 
 /* Used as an unwind-protect clause so that, if a selection-converter signals
-   an error, we tell the requestor that we were unable to do what they wanted
+   an error, we tell the requester 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
    before we throw to top-level or go into the debugger or whatever.  */
 
 static Lisp_Object
@@ -503,6 +516,7 @@ x_reply_selection_request (event, format, data, size, type)
   int format_bytes = format/8;
   int max_bytes = SELECTION_QUANTUM (display);
   struct x_display_info *dpyinfo = x_display_info_for_display (display);
   int format_bytes = format/8;
   int max_bytes = SELECTION_QUANTUM (display);
   struct x_display_info *dpyinfo = x_display_info_for_display (display);
+  int count;
 
   if (max_bytes > MAX_SELECTION_QUANTUM)
     max_bytes = MAX_SELECTION_QUANTUM;
 
   if (max_bytes > MAX_SELECTION_QUANTUM)
     max_bytes = MAX_SELECTION_QUANTUM;
@@ -519,7 +533,7 @@ x_reply_selection_request (event, format, data, size, type)
 
   /* #### XChangeProperty can generate BadAlloc, and we must handle it! */
   BLOCK_INPUT;
 
   /* #### XChangeProperty can generate BadAlloc, and we must handle it! */
   BLOCK_INPUT;
-  x_catch_errors (display);
+  count = x_catch_errors (display);
 
   /* Store the data on the requested property.
      If the selection is large, only store the first N bytes of it.
 
   /* Store the data on the requested property.
      If the selection is large, only store the first N bytes of it.
@@ -541,7 +555,6 @@ x_reply_selection_request (event, format, data, size, type)
       /* Send an INCR selection.  */
       struct prop_location *wait_object;
       int had_errors;
       /* Send an INCR selection.  */
       struct prop_location *wait_object;
       int had_errors;
-      int count = specpdl_ptr - specpdl;
       Lisp_Object frame;
 
       frame = some_frame_on_display (dpyinfo);
       Lisp_Object frame;
 
       frame = some_frame_on_display (dpyinfo);
@@ -558,7 +571,7 @@ x_reply_selection_request (event, format, data, size, type)
        }
 
       if (x_window_to_frame (dpyinfo, window)) /* #### debug */
        }
 
       if (x_window_to_frame (dpyinfo, window)) /* #### debug */
-       error ("attempt to transfer an INCR to ourself!");
+       error ("Attempt to transfer an INCR to ourself!");
 #if 0
       fprintf (stderr, "\nINCR %d\n", bytes_remaining);
 #endif
 #if 0
       fprintf (stderr, "\nINCR %d\n", bytes_remaining);
 #endif
@@ -576,7 +589,7 @@ x_reply_selection_request (event, format, data, size, type)
       had_errors = x_had_errors_p (display);
       UNBLOCK_INPUT;
 
       had_errors = x_had_errors_p (display);
       UNBLOCK_INPUT;
 
-      /* First, wait for the requestor to ack by deleting the property.
+      /* First, wait for the requester to ack by deleting the property.
         This can run random lisp code (process handlers) or signal.  */
       if (! had_errors)
        wait_for_property_change (wait_object);
         This can run random lisp code (process handlers) or signal.  */
       if (! had_errors)
        wait_for_property_change (wait_object);
@@ -607,12 +620,12 @@ x_reply_selection_request (event, format, data, size, type)
          if (had_errors)
            break;
 
          if (had_errors)
            break;
 
-         /* Now wait for the requestor to ack this chunk by deleting the
+         /* Now wait for the requester to ack this chunk by deleting the
             property.   This can run random lisp code or signal.
           */
          wait_for_property_change (wait_object);
        }
             property.   This can run random lisp code or signal.
           */
          wait_for_property_change (wait_object);
        }
-      /* Now write a zero-length chunk to the property to tell the requestor
+      /* Now write a zero-length chunk to the property to tell the requester
         that we're done.  */
 #if 0
       fprintf (stderr,"  INCR done\n");
         that we're done.  */
 #if 0
       fprintf (stderr,"  INCR done\n");
@@ -623,12 +636,10 @@ x_reply_selection_request (event, format, data, size, type)
 
       XChangeProperty (display, window, reply.property, type, format,
                       PropModeReplace, data, 0);
 
       XChangeProperty (display, window, reply.property, type, format,
                       PropModeReplace, data, 0);
-
-      unbind_to (count, Qnil);
     }
 
   XFlush (display);
     }
 
   XFlush (display);
-  x_uncatch_errors (display);
+  x_uncatch_errors (display, count);
   UNBLOCK_INPUT;
 }
 \f
   UNBLOCK_INPUT;
 }
 \f
@@ -719,6 +730,8 @@ x_handle_selection_request (event)
       /* Indicate we have successfully processed this event.  */
       x_selection_current_request = 0;
 
       /* Indicate we have successfully processed this event.  */
       x_selection_current_request = 0;
 
+      /* Use xfree, not XFree, because lisp_data_to_selection_data
+        calls xmalloc itself.  */
       if (!nofree)
        xfree (data);
     }
       if (!nofree)
        xfree (data);
     }
@@ -832,7 +845,11 @@ x_clear_frame_selections (f)
        {
          for (; CONSP (hooks); hooks = Fcdr (hooks))
            call1 (Fcar (hooks), selection_symbol);
        {
          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 ();
          redisplay_preserve_echo_area ();
+#endif
        }
 
       Vselection_alist = Fcdr (Vselection_alist);
        }
 
       Vselection_alist = Fcdr (Vselection_alist);
@@ -852,7 +869,9 @@ x_clear_frame_selections (f)
          {
            for (; CONSP (hooks); hooks = Fcdr (hooks))
              call1 (Fcar (hooks), selection_symbol);
          {
            for (; CONSP (hooks); hooks = Fcdr (hooks))
              call1 (Fcar (hooks), selection_symbol);
+#if 0 /* See above */
            redisplay_preserve_echo_area ();
            redisplay_preserve_echo_area ();
+#endif
          }
        XCONS (rest)->cdr = Fcdr (XCONS (rest)->cdr);
        break;
          }
        XCONS (rest)->cdr = Fcdr (XCONS (rest)->cdr);
        break;
@@ -885,7 +904,7 @@ static struct prop_location *
 expect_property_change (display, window, property, state)
      Display *display;
      Window window;
 expect_property_change (display, window, property, state)
      Display *display;
      Window window;
-     Lisp_Object property;
+     Atom property;
      int state;
 {
   struct prop_location *pl
      int state;
 {
   struct prop_location *pl
@@ -967,7 +986,7 @@ wait_for_property_change (location)
       wait_reading_process_input (secs, usecs, property_change_reply, 0);
 
       if (NILP (XCONS (property_change_reply)->car))
       wait_reading_process_input (secs, usecs, property_change_reply, 0);
 
       if (NILP (XCONS (property_change_reply)->car))
-       error ("timed out waiting for property-notify event");
+       error ("Timed out waiting for property-notify event");
     }
 
   unbind_to (count, Qnil);
     }
 
   unbind_to (count, Qnil);
@@ -1093,7 +1112,7 @@ x_get_foreign_selection (selection_symbol, target_type)
   Atom selection_atom = symbol_to_x_atom (dpyinfo, display, selection_symbol);
   Atom type_atom;
   int secs, usecs;
   Atom selection_atom = symbol_to_x_atom (dpyinfo, display, selection_symbol);
   Atom type_atom;
   int secs, usecs;
-  int count = specpdl_ptr - specpdl;
+  int count;
   Lisp_Object frame;
 
   if (CONSP (target_type))
   Lisp_Object frame;
 
   if (CONSP (target_type))
@@ -1102,7 +1121,7 @@ x_get_foreign_selection (selection_symbol, target_type)
     type_atom = symbol_to_x_atom (dpyinfo, display, target_type);
 
   BLOCK_INPUT;
     type_atom = symbol_to_x_atom (dpyinfo, display, target_type);
 
   BLOCK_INPUT;
-  x_catch_errors (display);
+  count = x_catch_errors (display);
   XConvertSelection (display, selection_atom, type_atom, target_property,
                     requestor_window, requestor_time);
   XFlush (display);
   XConvertSelection (display, selection_atom, type_atom, target_property,
                     requestor_window, requestor_time);
   XFlush (display);
@@ -1133,12 +1152,13 @@ x_get_foreign_selection (selection_symbol, target_type)
 
   BLOCK_INPUT;
   x_check_errors (display, "Cannot get selection: %s");
 
   BLOCK_INPUT;
   x_check_errors (display, "Cannot get selection: %s");
-  x_uncatch_errors (display);
-  unbind_to (count, Qnil);
+  x_uncatch_errors (display, count);
   UNBLOCK_INPUT;
 
   if (NILP (XCONS (reading_selection_reply)->car))
   UNBLOCK_INPUT;
 
   if (NILP (XCONS (reading_selection_reply)->car))
-    error ("timed out waiting for reply from selection owner");
+    error ("Timed out waiting for reply from selection owner");
+  if (EQ (XCONS (reading_selection_reply)->car, Qlambda))
+    error ("No `%s' selection", XSYMBOL (selection_symbol)->name->data);
 
   /* Otherwise, the selection is waiting for us on the requested property.  */
   return
 
   /* Otherwise, the selection is waiting for us on the requested property.  */
   return
@@ -1149,6 +1169,8 @@ x_get_foreign_selection (selection_symbol, target_type)
 \f
 /* Subroutines of x_get_window_property_as_lisp_data */
 
 \f
 /* Subroutines of x_get_window_property_as_lisp_data */
 
+/* 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,
 static void
 x_get_window_property (display, window, property, data_ret, bytes_ret,
                       actual_type_ret, actual_format_ret, actual_size_ret,
@@ -1185,7 +1207,8 @@ x_get_window_property (display, window, property, data_ret, bytes_ret,
       *bytes_ret = 0;
       return;
     }
       *bytes_ret = 0;
       return;
     }
-  xfree ((char *) tmp_data);
+  /* This was allocated by Xlib, so use XFree.  */
+  XFree ((char *) tmp_data);
   
   if (*actual_type_ret == None || *actual_format_ret == 0)
     {
   
   if (*actual_type_ret == None || *actual_format_ret == 0)
     {
@@ -1196,7 +1219,7 @@ x_get_window_property (display, window, property, data_ret, bytes_ret,
   total_size = bytes_remaining + 1;
   *data_ret = (unsigned char *) xmalloc (total_size);
   
   total_size = bytes_remaining + 1;
   *data_ret = (unsigned char *) xmalloc (total_size);
   
-  /* Now read, until weve gotten it all.  */
+  /* Now read, until we've gotten it all.  */
   while (bytes_remaining)
     {
 #if 0
   while (bytes_remaining)
     {
 #if 0
@@ -1220,7 +1243,8 @@ x_get_window_property (display, window, property, data_ret, bytes_ret,
       *actual_size_ret *= *actual_format_ret / 8;
       bcopy (tmp_data, (*data_ret) + offset, *actual_size_ret);
       offset += *actual_size_ret;
       *actual_size_ret *= *actual_format_ret / 8;
       bcopy (tmp_data, (*data_ret) + offset, *actual_size_ret);
       offset += *actual_size_ret;
-      xfree ((char *) tmp_data);
+      /* This was allocated by Xlib, so use XFree.  */
+      XFree ((char *) tmp_data);
     }
 
   XFlush (display);
     }
 
   XFlush (display);
@@ -1228,6 +1252,8 @@ x_get_window_property (display, window, property, data_ret, bytes_ret,
   *bytes_ret = offset;
 }
 \f
   *bytes_ret = offset;
 }
 \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,
 static void
 receive_incremental_selection (display, window, property, target_type,
                               min_size_bytes, data_ret, size_bytes_ret,
@@ -1273,7 +1299,7 @@ receive_incremental_selection (display, window, property, target_type,
       int tmp_size_bytes;
       wait_for_property_change (wait_object);
       /* expect it again immediately, because x_get_window_property may
       int tmp_size_bytes;
       wait_for_property_change (wait_object);
       /* expect it again immediately, because x_get_window_property may
-        .. no it wont, I dont get it.
+        .. no it won't, I don't get it.
         .. Ok, I get it now, the Xt code that implements INCR is broken.
        */
       x_get_window_property (display, window, property,
         .. Ok, I get it now, the Xt code that implements INCR is broken.
        */
       x_get_window_property (display, window, property,
@@ -1288,6 +1314,8 @@ receive_incremental_selection (display, window, property, target_type,
          if (! waiting_for_other_props_on_window (display, window))
            XSelectInput (display, window, STANDARD_EVENT_SET);
          unexpect_property_change (wait_object);
          if (! waiting_for_other_props_on_window (display, window))
            XSelectInput (display, window, STANDARD_EVENT_SET);
          unexpect_property_change (wait_object);
+         /* Use xfree, not XFree, because x_get_window_property
+            calls xmalloc itself.  */
          if (tmp_data) xfree (tmp_data);
          break;
        }
          if (tmp_data) xfree (tmp_data);
          break;
        }
@@ -1313,6 +1341,8 @@ receive_incremental_selection (display, window, property, target_type,
        }
       bcopy (tmp_data, (*data_ret) + offset, tmp_size_bytes);
       offset += tmp_size_bytes;
        }
       bcopy (tmp_data, (*data_ret) + offset, tmp_size_bytes);
       offset += tmp_size_bytes;
+      /* Use xfree, not XFree, because x_get_window_property
+        calls xmalloc itself.  */
       xfree (tmp_data);
     }
 }
       xfree (tmp_data);
     }
 }
@@ -1347,20 +1377,19 @@ x_get_window_property_as_lisp_data (display, window, property, target_type,
       there_is_a_selection_owner
        = XGetSelectionOwner (display, selection_atom);
       UNBLOCK_INPUT;
       there_is_a_selection_owner
        = XGetSelectionOwner (display, selection_atom);
       UNBLOCK_INPUT;
-      while (1) /* Note debugger can no longer return, so this is obsolete */
-       Fsignal (Qerror,
-                there_is_a_selection_owner ?
-                Fcons (build_string ("selection owner couldn't convert"),
+      Fsignal (Qerror,
+              there_is_a_selection_owner
+              ? Fcons (build_string ("selection owner couldn't convert"),
                        actual_type
                        ? Fcons (target_type,
                                 Fcons (x_atom_to_symbol (dpyinfo, display,
                                                          actual_type),
                                        Qnil))
                        : Fcons (target_type, Qnil))
                        actual_type
                        ? Fcons (target_type,
                                 Fcons (x_atom_to_symbol (dpyinfo, display,
                                                          actual_type),
                                        Qnil))
                        : Fcons (target_type, Qnil))
-                : Fcons (build_string ("no selection"),
-                         Fcons (x_atom_to_symbol (dpyinfo, display,
-                                                  selection_atom),
-                                Qnil)));
+              : Fcons (build_string ("no selection"),
+                       Fcons (x_atom_to_symbol (dpyinfo, display,
+                                                selection_atom),
+                              Qnil)));
     }
   
   if (actual_type == dpyinfo->Xatom_INCR)
     }
   
   if (actual_type == dpyinfo->Xatom_INCR)
@@ -1369,7 +1398,9 @@ x_get_window_property_as_lisp_data (display, window, property, target_type,
 
       unsigned int min_size_bytes = * ((unsigned int *) data);
       BLOCK_INPUT;
 
       unsigned int min_size_bytes = * ((unsigned int *) data);
       BLOCK_INPUT;
-      XFree ((char *) data);
+      /* Use xfree, not XFree, because x_get_window_property
+        calls xmalloc itself.  */
+      xfree ((char *) data);
       UNBLOCK_INPUT;
       receive_incremental_selection (display, window, property, target_type,
                                     min_size_bytes, &data, &bytes,
       UNBLOCK_INPUT;
       receive_incremental_selection (display, window, property, target_type,
                                     min_size_bytes, &data, &bytes,
@@ -1387,6 +1418,8 @@ x_get_window_property_as_lisp_data (display, window, property, target_type,
   val = selection_data_to_lisp_data (display, data, bytes,
                                     actual_type, actual_format);
   
   val = selection_data_to_lisp_data (display, data, bytes,
                                     actual_type, actual_format);
   
+  /* Use xfree, not XFree, because x_get_window_property
+     calls xmalloc itself.  */
   xfree ((char *) data);
   return val;
 }
   xfree ((char *) data);
   return val;
 }
@@ -1432,8 +1465,53 @@ selection_data_to_lisp_data (display, data, size, type, format)
 
   /* Convert any 8-bit data to a string, for compactness.  */
   else if (format == 8)
 
   /* Convert any 8-bit data to a string, for compactness.  */
   else if (format == 8)
-    return make_string ((char *) data, size);
+    {
+      Lisp_Object str;
+      int require_encoding = 0;
 
 
+      if (! NILP (buffer_defaults.enable_multibyte_characters))
+       {
+         /* If TYPE is `TEXT' or `COMPOUND_TEXT', we should decode
+            DATA to Emacs internal format because DATA may be encoded
+            in compound text format.  In addtion, if TYPE is `STRING'
+            and DATA contains any 8-bit Latin-1 code, we should also
+            decode it.  */
+         if (type == dpyinfo->Xatom_TEXT
+             || type == dpyinfo->Xatom_COMPOUND_TEXT)
+           require_encoding = 1;
+         else if (type == XA_STRING)
+           {
+             int i;
+             for (i = 0; i < size; i++)
+               {
+                 if (data[i] >= 0x80)
+                   {
+                     require_encoding = 1;
+                     break;
+                   }
+               }
+           }
+       }
+      if (!require_encoding)
+       str = make_unibyte_string ((char *) data, size);
+      else
+       {
+         int bufsize;
+         unsigned char *buf;
+         struct coding_system coding;
+
+         setup_coding_system
+            (Fcheck_coding_system(Vclipboard_coding_system), &coding);
+          coding.mode |= CODING_MODE_LAST_BLOCK;
+         bufsize = decoding_buffer_size (&coding, size);
+         buf = (unsigned char *) xmalloc (bufsize);
+         decode_coding (&coding, data, buf, size, bufsize);
+         str = make_multibyte_string ((char *) buf,
+                                      coding.produced_char, coding.produced);
+         xfree (buf);
+       }
+      return str;
+    }
   /* Convert a single atom to a Lisp_Symbol.  Convert a set of atoms to
      a vector of symbols.
    */
   /* Convert a single atom to a Lisp_Symbol.  Convert a set of atoms to
      a vector of symbols.
    */
@@ -1444,10 +1522,11 @@ selection_data_to_lisp_data (display, data, size, type, format)
        return x_atom_to_symbol (dpyinfo, display, *((Atom *) data));
       else
        {
        return x_atom_to_symbol (dpyinfo, display, *((Atom *) data));
       else
        {
-         Lisp_Object v = Fmake_vector (size / sizeof (Atom), 0);
+         Lisp_Object v = Fmake_vector (make_number (size / sizeof (Atom)),
+                                       make_number (0));
          for (i = 0; i < size / sizeof (Atom); i++)
          for (i = 0; i < size / sizeof (Atom); i++)
-           Faset (v, i, x_atom_to_symbol (dpyinfo, display,
-                                          ((Atom *) data) [i]));
+           Faset (v, make_number (i),
+                  x_atom_to_symbol (dpyinfo, display, ((Atom *) data) [i]));
          return v;
        }
     }
          return v;
        }
     }
@@ -1467,28 +1546,31 @@ selection_data_to_lisp_data (display, data, size, type, format)
   else if (format == 16)
     {
       int i;
   else if (format == 16)
     {
       int i;
-      Lisp_Object v = Fmake_vector (size / 4, 0);
-      for (i = 0; i < size / 4; 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];
        {
          int j = (int) ((unsigned short *) data) [i];
-         Faset (v, i, make_number (j));
+         Faset (v, make_number (i), make_number (j));
        }
       return v;
     }
   else
     {
       int i;
        }
       return v;
     }
   else
     {
       int i;
-      Lisp_Object v = Fmake_vector (size / 4, 0);
+      Lisp_Object v = Fmake_vector (make_number (size / 4), make_number (0));
       for (i = 0; i < size / 4; i++)
        {
          unsigned long j = ((unsigned long *) data) [i];
       for (i = 0; i < size / 4; i++)
        {
          unsigned long j = ((unsigned long *) data) [i];
-         Faset (v, i, long_to_cons (j));
+         Faset (v, make_number (i), long_to_cons (j));
        }
       return v;
     }
 }
 
 
        }
       return v;
     }
 }
 
 
+/* 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,
 static void
 lisp_data_to_selection_data (display, obj,
                             data_ret, type_ret, size_ret,
@@ -1523,11 +1605,56 @@ lisp_data_to_selection_data (display, obj,
     }
   else if (STRINGP (obj))
     {
     }
   else if (STRINGP (obj))
     {
+      /* Since we are now handling multilingual text, we must consider
+        sending back compound text.  */
+      int charsets[MAX_CHARSET + 1];
+      int num;
+
       *format_ret = 8;
       *format_ret = 8;
-      *size_ret = XSTRING (obj)->size;
+      *size_ret = XSTRING (obj)->size_byte;
       *data_ret = XSTRING (obj)->data;
       *data_ret = XSTRING (obj)->data;
-      *nofree_ret = 1;
-      if (NILP (type)) type = QSTRING;
+      bzero (charsets, (MAX_CHARSET + 1) * sizeof (int));
+      num = ((*size_ret <= 1   /* Check the possibility of short cut.  */
+             || NILP (buffer_defaults.enable_multibyte_characters))
+            ? 0
+            : find_charset_in_str (*data_ret, *size_ret, charsets, Qnil));
+
+      if (!num || (num == 1 && charsets[CHARSET_ASCII]))
+       {
+         /* No multibyte character in OBJ.  We need not encode it.  */
+         *nofree_ret = 1;
+         if (NILP (type)) type = QSTRING;
+       }
+      else
+       {
+         /* We must encode contents of OBJ to compound text format.
+             The format is compatible with what the target `STRING'
+             expects if OBJ contains only ASCII and Latin-1
+             characters.  */
+         int bufsize;
+         unsigned char *buf;
+         struct coding_system coding;
+
+         setup_coding_system
+            (Fcheck_coding_system (Vclipboard_coding_system), &coding);
+         coding.mode |= CODING_MODE_LAST_BLOCK;
+         bufsize = encoding_buffer_size (&coding, *size_ret);
+         buf = (unsigned char *) xmalloc (bufsize);
+         encode_coding (&coding, *data_ret, buf, *size_ret, bufsize);
+         *size_ret = coding.produced;
+         *data_ret = buf;
+          if (charsets[charset_latin_iso8859_1]
+             && (num == 1 || (num == 2 && charsets[CHARSET_ASCII])))
+           {
+             /* Ok, we can return it as `STRING'.  */
+             if (NILP (type)) type = QSTRING;
+           }
+         else
+           {
+             /* We must return it as `COMPOUND_TEXT'.  */
+             if (NILP (type)) type = QCOMPOUND_TEXT;
+           }
+       }
     }
   else if (SYMBOLP (obj))
     {
     }
   else if (SYMBOLP (obj))
     {
@@ -1681,7 +1808,7 @@ clean_local_selection_data (obj)
       Lisp_Object copy;
       if (size == 1)
        return clean_local_selection_data (XVECTOR (obj)->contents [0]);
       Lisp_Object copy;
       if (size == 1)
        return clean_local_selection_data (XVECTOR (obj)->contents [0]);
-      copy = Fmake_vector (size, Qnil);
+      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]);
       for (i = 0; i < size; i++)
        XVECTOR (copy)->contents [i]
          = clean_local_selection_data (XVECTOR (obj)->contents [i]);
@@ -1691,7 +1818,9 @@ clean_local_selection_data (obj)
 }
 \f
 /* Called from XTread_socket to handle SelectionNotify events.
 }
 \f
 /* Called from XTread_socket to handle SelectionNotify events.
-   If it's the selection we are waiting for, stop waiting.  */
+   If it's the selection we are waiting for, stop waiting
+   by setting the car of reading_selection_reply to non-nil.
+   We store t there if the reply is successful, lambda if not.  */
 
 void
 x_handle_selection_notify (event)
 
 void
 x_handle_selection_notify (event)
@@ -1702,13 +1831,13 @@ x_handle_selection_notify (event)
   if (event->selection != reading_which_selection)
     return;
 
   if (event->selection != reading_which_selection)
     return;
 
-  XCONS (reading_selection_reply)->car = Qt;
+  XCONS (reading_selection_reply)->car
+    = (event->property != 0 ? Qt : Qlambda);
 }
 
 \f
 }
 
 \f
-DEFUN ("x-own-selection-internal",
-       Fx_own_selection_internal, Sx_own_selection_internal,
-  2, 2, 0,
+DEFUN ("x-own-selection-internal", Fx_own_selection_internal,
+  Sx_own_selection_internal, 2, 2, 0,
   "Assert an X selection of the given TYPE with the given VALUE.\n\
 TYPE is a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'.\n\
 \(Those are literal upper-case symbol names, since that's what X expects.)\n\
   "Assert an X selection of the given TYPE with the given VALUE.\n\
 TYPE is a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'.\n\
 \(Those are literal upper-case symbol names, since that's what X expects.)\n\
@@ -1719,7 +1848,7 @@ anything that the functions on `selection-converter-alist' know about.")
 {
   check_x ();
   CHECK_SYMBOL (selection_name, 0);
 {
   check_x ();
   CHECK_SYMBOL (selection_name, 0);
-  if (NILP (selection_value)) error ("selection-value may not be nil.");
+  if (NILP (selection_value)) error ("selection-value may not be nil");
   x_own_selection (selection_name, selection_value);
   return selection_value;
 }
   x_own_selection (selection_name, selection_value);
   return selection_value;
 }
@@ -1729,8 +1858,8 @@ anything that the functions on `selection-converter-alist' know about.")
    simply return our selection value.  If we are not the owner, this
    will block until all of the data has arrived.  */
 
    simply return our selection value.  If we are not the owner, this
    will block until all of the data has arrived.  */
 
-DEFUN ("x-get-selection-internal",
-  Fx_get_selection_internal, Sx_get_selection_internal, 2, 2, 0,
+DEFUN ("x-get-selection-internal", Fx_get_selection_internal,
+  Sx_get_selection_internal, 2, 2, 0,
   "Return text selected from some X window.\n\
 SELECTION is a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'.\n\
 \(Those are literal upper-case symbol names, since that's what X expects.)\n\
   "Return text selected from some X window.\n\
 SELECTION is a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'.\n\
 \(Those are literal upper-case symbol names, since that's what X expects.)\n\
@@ -1777,8 +1906,8 @@ TYPE is the type of data desired, typically `STRING'.")
   return val;
 }
 
   return val;
 }
 
-DEFUN ("x-disown-selection-internal",
-  Fx_disown_selection_internal, Sx_disown_selection_internal, 1, 2, 0,
+DEFUN ("x-disown-selection-internal", Fx_disown_selection_internal,
+  Sx_disown_selection_internal, 1, 2, 0,
   "If we own the selection SELECTION, disown it.\n\
 Disowning it means there is no such selection.")
   (selection, time)
   "If we own the selection SELECTION, disown it.\n\
 Disowning it means there is no such selection.")
   (selection, time)
@@ -1787,7 +1916,7 @@ Disowning it means there is no such selection.")
 {
   Time timestamp;
   Atom selection_atom;
 {
   Time timestamp;
   Atom selection_atom;
-  XSelectionClearEvent event;
+  struct selection_input_event event;
   Display *display;
   struct x_display_info *dpyinfo;
 
   Display *display;
   struct x_display_info *dpyinfo;
 
@@ -1817,7 +1946,7 @@ Disowning it means there is no such selection.")
   SELECTION_EVENT_DISPLAY (&event) = display;
   SELECTION_EVENT_SELECTION (&event) = selection_atom;
   SELECTION_EVENT_TIME (&event) = timestamp;
   SELECTION_EVENT_DISPLAY (&event) = display;
   SELECTION_EVENT_SELECTION (&event) = selection_atom;
   SELECTION_EVENT_TIME (&event) = timestamp;
-  x_handle_selection_clear (&event);
+  x_handle_selection_clear ((struct input_event *) &event);
 
   return Qt;
 }
 
   return Qt;
 }
@@ -1971,6 +2100,8 @@ DEFUN ("x-get-cut-buffer-internal", Fx_get_cut_buffer_internal,
                           Fcons (make_number (format), Qnil))));
 
   ret = (bytes ? make_string ((char *) data, bytes) : Qnil);
                           Fcons (make_number (format), Qnil))));
 
   ret = (bytes ? make_string ((char *) data, bytes) : Qnil);
+  /* Use xfree, not XFree, because x_get_window_property
+     calls xmalloc itself.  */
   xfree (data);
   return ret;
 }
   xfree (data);
   return ret;
 }
@@ -2003,7 +2134,7 @@ DEFUN ("x-store-cut-buffer-internal", Fx_store_cut_buffer_internal,
   buffer_atom = symbol_to_x_atom (FRAME_X_DISPLAY_INFO (selected_frame),
                                  display, buffer);
   data = (unsigned char *) XSTRING (string)->data;
   buffer_atom = symbol_to_x_atom (FRAME_X_DISPLAY_INFO (selected_frame),
                                  display, buffer);
   data = (unsigned char *) XSTRING (string)->data;
-  bytes = XSTRING (string)->size;
+  bytes = XSTRING (string)->size_byte;
   bytes_remaining = bytes;
 
   if (! FRAME_X_DISPLAY_INFO (selected_frame)->cut_buffers_initialized)
   bytes_remaining = bytes;
 
   if (! FRAME_X_DISPLAY_INFO (selected_frame)->cut_buffers_initialized)
@@ -2038,8 +2169,8 @@ DEFUN ("x-store-cut-buffer-internal", Fx_store_cut_buffer_internal,
 
 DEFUN ("x-rotate-cut-buffers-internal", Fx_rotate_cut_buffers_internal,
   Sx_rotate_cut_buffers_internal, 1, 1, 0,
 
 DEFUN ("x-rotate-cut-buffers-internal", Fx_rotate_cut_buffers_internal,
   Sx_rotate_cut_buffers_internal, 1, 1, 0,
-  "Rotate the values of the cut buffers by the given number of steps;\n\
-positive means move values forward, negative means backward.")
+  "Rotate the values of the cut buffers by the given number of step.\n\
+Positive means shift the values forward, negative means backward.")
   (n)
      Lisp_Object n;
 {
   (n)
      Lisp_Object n;
 {
@@ -2104,7 +2235,7 @@ syms_of_xselect ()
   staticpro (&Vselection_alist);
 
   DEFVAR_LISP ("selection-converter-alist", &Vselection_converter_alist,
   staticpro (&Vselection_alist);
 
   DEFVAR_LISP ("selection-converter-alist", &Vselection_converter_alist,
-  "An alist associating X Windows selection-types with functions.\n\
+    "An alist associating X Windows selection-types with functions.\n\
 These functions are called to convert the selection, with three args:\n\
 the name of the selection (typically `PRIMARY', `SECONDARY', or `CLIPBOARD');\n\
 a desired type to which the selection should be converted;\n\
 These functions are called to convert the selection, with three args:\n\
 the name of the selection (typically `PRIMARY', `SECONDARY', or `CLIPBOARD');\n\
 a desired type to which the selection should be converted;\n\
@@ -2119,7 +2250,7 @@ and there is no meaningful selection value.");
   Vselection_converter_alist = Qnil;
 
   DEFVAR_LISP ("x-lost-selection-hooks", &Vx_lost_selection_hooks,
   Vselection_converter_alist = Qnil;
 
   DEFVAR_LISP ("x-lost-selection-hooks", &Vx_lost_selection_hooks,
-  "A list of functions to be called when Emacs loses an X selection.\n\
+    "A list of functions to be called when Emacs loses an X selection.\n\
 \(This happens when some other X client makes its own selection\n\
 or when a Lisp program explicitly clears the selection.)\n\
 The functions are called with one argument, the selection type\n\
 \(This happens when some other X client makes its own selection\n\
 or when a Lisp program explicitly clears the selection.)\n\
 The functions are called with one argument, the selection type\n\
@@ -2127,7 +2258,7 @@ The functions are called with one argument, the selection type\n\
   Vx_lost_selection_hooks = Qnil;
 
   DEFVAR_LISP ("x-sent-selection-hooks", &Vx_sent_selection_hooks,
   Vx_lost_selection_hooks = Qnil;
 
   DEFVAR_LISP ("x-sent-selection-hooks", &Vx_sent_selection_hooks,
-  "A list of functions to be called when Emacs answers a selection request.\n\
+    "A list of functions to be called when Emacs answers a selection request.\n\
 The functions are called with four arguments:\n\
   - the selection name (typically `PRIMARY', `SECONDARY', or `CLIPBOARD');\n\
   - the selection-type which Emacs was asked to convert the\n\
 The functions are called with four arguments:\n\
   - the selection name (typically `PRIMARY', `SECONDARY', or `CLIPBOARD');\n\
   - the selection-type which Emacs was asked to convert the\n\
@@ -2140,9 +2271,17 @@ This hook doesn't let you change the behavior of Emacs's selection replies,\n\
 it merely informs you that they have happened.");
   Vx_sent_selection_hooks = Qnil;
 
 it merely informs you that they have happened.");
   Vx_sent_selection_hooks = Qnil;
 
+  DEFVAR_LISP ("clipboard-coding-system", &Vclipboard_coding_system,
+    "Coding system for communicating with other X clients.\n\
+When sending or receiving text via cut_buffer, selection, and clipboard,\n\
+the text is encoded or decoded by this coding system.\n\
+A default value is `compound-text'");
+  Vclipboard_coding_system=intern ("compound-text");
+  staticpro(&Vclipboard_coding_system);
+
   DEFVAR_INT ("x-selection-timeout", &x_selection_timeout,
   DEFVAR_INT ("x-selection-timeout", &x_selection_timeout,
-   "Number of milliseconds to wait for a selection reply.\n\
-If the selection owner doens't reply in this time, we give up.\n\
+    "Number of milliseconds to wait for a selection reply.\n\
+If the selection owner doesn't reply in this time, we give up.\n\
 A value of 0 means wait as long as necessary.  This is initialized from the\n\
 \"*selectionTimeout\" resource.");
   x_selection_timeout = 0;
 A value of 0 means wait as long as necessary.  This is initialized from the\n\
 \"*selectionTimeout\" resource.");
   x_selection_timeout = 0;
@@ -2154,6 +2293,7 @@ A value of 0 means wait as long as necessary.  This is initialized from the\n\
   QCLIPBOARD = intern ("CLIPBOARD");   staticpro (&QCLIPBOARD);
   QTIMESTAMP = intern ("TIMESTAMP");   staticpro (&QTIMESTAMP);
   QTEXT      = intern ("TEXT");        staticpro (&QTEXT);
   QCLIPBOARD = intern ("CLIPBOARD");   staticpro (&QCLIPBOARD);
   QTIMESTAMP = intern ("TIMESTAMP");   staticpro (&QTIMESTAMP);
   QTEXT      = intern ("TEXT");        staticpro (&QTEXT);
+  QCOMPOUND_TEXT = intern ("COMPOUND_TEXT"); staticpro (&QCOMPOUND_TEXT);
   QTIMESTAMP = intern ("TIMESTAMP");   staticpro (&QTIMESTAMP);
   QDELETE    = intern ("DELETE");      staticpro (&QDELETE);
   QMULTIPLE  = intern ("MULTIPLE");    staticpro (&QMULTIPLE);
   QTIMESTAMP = intern ("TIMESTAMP");   staticpro (&QTIMESTAMP);
   QDELETE    = intern ("DELETE");      staticpro (&QDELETE);
   QMULTIPLE  = intern ("MULTIPLE");    staticpro (&QMULTIPLE);