]> code.delx.au - gnu-emacs/blobdiff - src/xselect.c
Merge from emacs--devo--0
[gnu-emacs] / src / xselect.c
index 30739c7433169b492624e422857c03de8014c666..7e77df0d6c3aaeb6429a896965f56d583c35c454 100644 (file)
@@ -1,12 +1,12 @@
 /* X Selection processing for Emacs.
    Copyright (C) 1993, 1994, 1995, 1996, 1997, 2000, 2001, 2002, 2003,
-                 2004, 2005, 2006 Free Software Foundation, Inc.
+                 2004, 2005, 2006, 2007 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 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
@@ -123,8 +123,8 @@ Lisp_Object QCUT_BUFFER0, QCUT_BUFFER1, QCUT_BUFFER2, QCUT_BUFFER3,
 
 static Lisp_Object Vx_lost_selection_functions;
 static Lisp_Object Vx_sent_selection_functions;
-/* Coding system for communicating with other X clients via cutbuffer,
-   selection, and clipboard.  */
+/* Coding system for communicating with other X clients via selection
+   and clipboard.  */
 static Lisp_Object Vselection_coding_system;
 
 /* Coding system for the next communicating with other X clients.  */
@@ -398,12 +398,19 @@ x_own_selection (selection_name, selection_value)
      Lisp_Object selection_name, selection_value;
 {
   struct frame *sf = SELECTED_FRAME ();
-  Window selecting_window = FRAME_X_WINDOW (sf);
-  Display *display = FRAME_X_DISPLAY (sf);
+  Window selecting_window;
+  Display *display;
   Time time = last_event_timestamp;
   Atom selection_atom;
-  struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (sf);
+  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);
 
@@ -555,11 +562,9 @@ x_get_local_selection (selection_symbol, target_type, local_request)
                && INTEGERP (XCAR (XCDR (check)))
                && NILP (XCDR (XCDR (check))))))
     return value;
-  else
-    return
-      Fsignal (Qerror,
-              Fcons (build_string ("invalid data returned by selection-conversion function"),
-                     Fcons (handler_fn, Fcons (value, Qnil))));
+
+  signal_error ("Invalid data returned by selection-conversion function",
+               list2 (handler_fn, value));
 }
 \f
 /* Subroutines of x_reply_selection_request.  */
@@ -620,6 +625,7 @@ x_catch_errors_unwind (dummy)
   BLOCK_INPUT;
   x_uncatch_errors ();
   UNBLOCK_INPUT;
+  return Qnil;
 }
 \f
 
@@ -672,7 +678,8 @@ some_frame_on_display (dpyinfo)
 
   FOR_EACH_FRAME (list, frame)
     {
-      if (FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
+      if (FRAME_X_P (XFRAME (frame))
+          && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
        return frame;
     }
 
@@ -836,7 +843,7 @@ x_reply_selection_request (event, format, data, size, type)
            break;
 
          /* Now wait for the requester to ack this chunk by deleting the
-            property.   This can run random lisp code or signal.  */
+            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);
@@ -957,6 +964,12 @@ x_handle_selection_request (event)
       Atom type;
       int nofree;
 
+      if (CONSP (converted_selection) && NILP (XCDR (converted_selection)))
+        {
+          x_decline_selection_request (event);
+          goto DONE2;
+        }
+
       lisp_data_to_selection_data (SELECTION_EVENT_DISPLAY (event),
                                   converted_selection,
                                   &data, &type, &size, &format, &nofree);
@@ -972,6 +985,8 @@ x_handle_selection_request (event)
       if (!nofree)
        xfree (data);
     }
+
+ DONE2:
   unbind_to (count, Qnil);
 
  DONE:
@@ -1007,6 +1022,7 @@ x_handle_selection_clear (event)
 
   TRACE0 ("x_handle_selection_clear");
 
+#ifdef MULTI_KBOARD  
   /* If the new selection owner is also Emacs,
      don't clear the new selection.  */
   BLOCK_INPUT;
@@ -1014,7 +1030,7 @@ x_handle_selection_clear (event)
      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->kboard == dpyinfo->kboard)
+    if (t_dpyinfo->terminal->kboard == dpyinfo->terminal->kboard)
       {
        Window owner_window
          = XGetSelectionOwner (t_dpyinfo->display, selection);
@@ -1025,7 +1041,8 @@ x_handle_selection_clear (event)
          }
       }
   UNBLOCK_INPUT;
-
+#endif
+  
   selection_symbol = x_atom_to_symbol (display, selection);
 
   local_selection_data = assq_no_quit (selection_symbol, Vselection_alist);
@@ -1347,8 +1364,7 @@ copy_multiple_data (obj)
       CHECK_VECTOR (vec2);
       if (XVECTOR (vec2)->size != 2)
        /* ??? Confusing error message */
-       Fsignal (Qerror, Fcons (build_string ("vectors must be of length 2"),
-                               Fcons (vec2, Qnil)));
+       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];
@@ -1374,17 +1390,26 @@ x_get_foreign_selection (selection_symbol, target_type, time_stamp)
      Lisp_Object selection_symbol, target_type, time_stamp;
 {
   struct frame *sf = SELECTED_FRAME ();
-  Window requestor_window = FRAME_X_WINDOW (sf);
-  Display *display = FRAME_X_DISPLAY (sf);
-  struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (sf);
+  Window requestor_window;
+  Display *display;
+  struct x_display_info *dpyinfo;
   Time requestor_time = last_event_timestamp;
-  Atom target_property = dpyinfo->Xatom_EMACS_TMP;
-  Atom selection_atom = symbol_to_x_atom (dpyinfo, display, selection_symbol);
+  Atom target_property;
+  Atom selection_atom;
   Atom type_atom;
   int secs, usecs;
   int count = SPECPDL_INDEX ();
   Lisp_Object frame;
 
+  if (! FRAME_X_P (sf))
+    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
@@ -1716,19 +1741,15 @@ x_get_window_property_as_lisp_data (display, window, property, target_type,
       there_is_a_selection_owner
        = XGetSelectionOwner (display, selection_atom);
       UNBLOCK_INPUT;
-      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 (display,
-                                                         actual_type),
-                                       Qnil))
-                       : Fcons (target_type, Qnil))
-              : Fcons (build_string ("no selection"),
-                       Fcons (x_atom_to_symbol (display,
-                                                selection_atom),
-                              Qnil)));
+      if (there_is_a_selection_owner)
+       signal_error ("Selection owner couldn't convert",
+                     actual_type
+                     ? list2 (target_type,
+                              x_atom_to_symbol (display, actual_type))
+                     : target_type);
+      else
+       signal_error ("No selection",
+                     x_atom_to_symbol (display, selection_atom));
     }
 
   if (actual_type == dpyinfo->Xatom_INCR)
@@ -1928,10 +1949,7 @@ lisp_data_to_selection_data (display, obj,
     {
       if (SCHARS (obj) < SBYTES (obj))
        /* OBJ is a multibyte string containing a non-ASCII char.  */
-       Fsignal (Qerror, /* Qselection_error */
-                Fcons (build_string
-                       ("Non-ASCII string must be encoded in advance"),
-                       Fcons (obj, Qnil)));
+       signal_error ("Non-ASCII string must be encoded in advance", obj);
       if (NILP (type))
        type = QSTRING;
       *format_ret = 8;
@@ -1992,10 +2010,7 @@ lisp_data_to_selection_data (display, obj,
              (*(Atom **) data_ret) [i]
                = symbol_to_x_atom (dpyinfo, display, XVECTOR (obj)->contents [i]);
            else
-             Fsignal (Qerror, /* Qselection_error */
-                      Fcons (build_string
-                  ("all elements of selection vector must have same type"),
-                             Fcons (obj, Qnil)));
+             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]))
@@ -2011,10 +2026,9 @@ lisp_data_to_selection_data (display, obj,
              {
                Lisp_Object pair = XVECTOR (obj)->contents [i];
                if (XVECTOR (pair)->size != 2)
-                 Fsignal (Qerror,
-                          Fcons (build_string
-       ("elements of the vector must be vectors of exactly two elements"),
-                                 Fcons (pair, Qnil)));
+                 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,
@@ -2024,10 +2038,8 @@ lisp_data_to_selection_data (display, obj,
                                      XVECTOR (pair)->contents [1]);
              }
            else
-             Fsignal (Qerror,
-                      Fcons (build_string
-                  ("all elements of the vector must be of the same type"),
-                             Fcons (obj, Qnil)));
+             signal_error ("All elements of the vector must be of the same type",
+                           obj);
 
        }
 #endif
@@ -2042,10 +2054,9 @@ lisp_data_to_selection_data (display, obj,
            if (CONSP (XVECTOR (obj)->contents [i]))
              *format_ret = 32;
            else if (!INTEGERP (XVECTOR (obj)->contents [i]))
-             Fsignal (Qerror, /* Qselection_error */
-                      Fcons (build_string
-       ("elements of selection vector must be integers or conses of integers"),
-                             Fcons (obj, Qnil)));
+             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.  */
@@ -2062,9 +2073,7 @@ lisp_data_to_selection_data (display, obj,
        }
     }
   else
-    Fsignal (Qerror, /* Qselection_error */
-            Fcons (build_string ("unrecognized selection data"),
-                   Fcons (obj, Qnil)));
+    signal_error (/* Qselection_error */ "Unrecognized selection data", obj);
 
   *type_ret = symbol_to_x_atom (dpyinfo, display, type);
 }
@@ -2216,6 +2225,9 @@ Disowning it means there is no such selection.  */)
   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);
   CHECK_SYMBOL (selection);
@@ -2350,15 +2362,13 @@ initialize_cut_buffers (display, window)
 
 
 #define CHECK_CUT_BUFFER(symbol)                                       \
-  { CHECK_SYMBOL ((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))  \
-      Fsignal (Qerror,                                                 \
-              Fcons (build_string ("doesn't name a cut buffer"),       \
-                            Fcons ((symbol), Qnil)));                  \
-  }
+      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,
@@ -2379,6 +2389,10 @@ DEFUN ("x-get-cut-buffer-internal", Fx_get_cut_buffer_internal,
   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 */
@@ -2391,10 +2405,9 @@ DEFUN ("x-get-cut-buffer-internal", Fx_get_cut_buffer_internal,
     return Qnil;
 
   if (format != 8 || type != XA_STRING)
-    Fsignal (Qerror,
-            Fcons (build_string ("cut buffer doesn't contain 8-bit data"),
-                   Fcons (x_atom_to_symbol (display, type),
-                          Fcons (make_number (format), Qnil))));
+    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
@@ -2420,6 +2433,10 @@ DEFUN ("x-store-cut-buffer-internal", Fx_store_cut_buffer_internal,
   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 */
 
@@ -2476,8 +2493,12 @@ Positive means shift the values forward, negative means backward.  */)
   Atom props[8];
   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 */
   CHECK_NUMBER (n);
@@ -2691,15 +2712,55 @@ If the value is 0 or the atom is not known, return the empty string.  */)
     ret = make_string (name, strlen (name));
 
   if (atom && name) XFree (name);
-  if (NILP (ret)) ret = make_string ("", 0);
+  if (NILP (ret)) ret = empty_unibyte_string;
 
   UNBLOCK_INPUT;
 
   return ret;
 }
 
-/* Convert an XClientMessageEvent to a Lisp event of type DRAG_N_DROP_EVENT.
-   TODO: Check if this client event really is a DND event?  */
+DEFUN ("x-register-dnd-atom", Fx_register_dnd_atom,
+       Sx_register_dnd_atom, 1, 2, 0,
+       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;
+{
+  Atom x_atom;
+  struct frame *f = check_x_frame (frame);
+  size_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);
+  else if (STRINGP (atom))
+    {
+      BLOCK_INPUT;
+      x_atom = XInternAtom (FRAME_X_DISPLAY (f), (char *) SDATA (atom), False);
+      UNBLOCK_INPUT;
+    }
+  else
+    error ("ATOM must be a symbol or a string");
+
+  for (i = 0; i < dpyinfo->x_dnd_atoms_length; ++i)
+    if (dpyinfo->x_dnd_atoms[i] == x_atom)
+      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[dpyinfo->x_dnd_atoms_length++] = x_atom;
+  return Qnil;
+}
+
+/* Convert an XClientMessageEvent to a Lisp event of type DRAG_N_DROP_EVENT.  */
 
 int
 x_handle_dnd_message (f, event, dpyinfo, bufp)
@@ -2715,6 +2776,12 @@ 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;
+
+  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;
 
   XSETFRAME (frame, f);
 
@@ -2888,6 +2955,7 @@ syms_of_xselect ()
 
   defsubr (&Sx_get_atom_name);
   defsubr (&Sx_send_client_message);
+  defsubr (&Sx_register_dnd_atom);
 
   reading_selection_reply = Fcons (Qnil, Qnil);
   staticpro (&reading_selection_reply);
@@ -2941,8 +3009,17 @@ it merely informs you that they have happened.  */);
 
   DEFVAR_LISP ("selection-coding-system", &Vselection_coding_system,
               doc: /* Coding system for communicating with other X clients.
-When sending or receiving text via cut_buffer, selection, and clipboard,
-the text is encoded or decoded by this coding system.
+
+When sending text via selection and clipboard, if the requested
+data-type is not "UTF8_STRING", the text is encoded by this coding
+system.
+
+When receiving text, if the data-type of the received text is not
+"UTF8_STRING", it is decoded by this coding system.
+
+See also the documentation of the variable `x-select-request-type' how
+to control which data-type to request for receiving text.
+
 The default value is `compound-text-with-extensions'.  */);
   Vselection_coding_system = intern ("compound-text-with-extensions");