]> code.delx.au - gnu-emacs/blobdiff - src/xselect.c
(compilation-directory-matcher): Doc fix (Nil -> nil).
[gnu-emacs] / src / xselect.c
index a0b4b091805bc377d86fa678110bad07d3125747..022226946a926f89d898c6eda5b1d49d0dbafaba 100644 (file)
@@ -55,6 +55,7 @@ static void x_decline_selection_request P_ ((struct input_event *));
 static Lisp_Object x_selection_request_lisp_error P_ ((Lisp_Object));
 static Lisp_Object queue_selection_requests_unwind P_ ((Lisp_Object));
 static Lisp_Object some_frame_on_display P_ ((struct x_display_info *));
+static Lisp_Object x_catch_errors_unwind P_ ((Lisp_Object));
 static void x_reply_selection_request P_ ((struct input_event *, int,
                                           unsigned char *, int, Atom));
 static int waiting_for_other_props_on_window P_ ((Display *, Window));
@@ -554,11 +555,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.  */
@@ -611,6 +610,16 @@ x_selection_request_lisp_error (ignore)
     x_decline_selection_request (x_selection_current_request);
   return Qnil;
 }
+
+static Lisp_Object
+x_catch_errors_unwind (dummy)
+     Lisp_Object dummy;
+{
+  BLOCK_INPUT;
+  x_uncatch_errors ();
+  UNBLOCK_INPUT;
+  return Qnil;
+}
 \f
 
 /* This stuff is so that INCR selections are reentrant (that is, so we can
@@ -703,8 +712,11 @@ x_reply_selection_request (event, format, data, size, type)
   if (reply.property == None)
     reply.property = reply.target;
 
-  /* #### XChangeProperty can generate BadAlloc, and we must handle it! */
   BLOCK_INPUT;
+  /* The protected block contains wait_for_property_change, which can
+     run random lisp code (process handlers) or signal.  Therefore, we
+     put the x_uncatch_errors call in an unwind.  */
+  record_unwind_protect (x_catch_errors_unwind, Qnil);
   x_catch_errors (display);
 
 #ifdef TRACE_SELECTION
@@ -858,9 +870,8 @@ x_reply_selection_request (event, format, data, size, type)
      UNBLOCK to enter the event loop and get possible errors delivered,
      and then BLOCK again because x_uncatch_errors requires it.  */
   BLOCK_INPUT;
-
+  /* This calls x_uncatch_errors.  */
   unbind_to (count, Qnil);
-  x_uncatch_errors ();
   UNBLOCK_INPUT;
 }
 \f
@@ -945,6 +956,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);
@@ -960,6 +977,8 @@ x_handle_selection_request (event)
       if (!nofree)
        xfree (data);
     }
+
+ DONE2:
   unbind_to (count, Qnil);
 
  DONE:
@@ -1335,8 +1354,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];
@@ -1370,7 +1388,7 @@ x_get_foreign_selection (selection_symbol, target_type, time_stamp)
   Atom selection_atom = symbol_to_x_atom (dpyinfo, display, selection_symbol);
   Atom type_atom;
   int secs, usecs;
-  int count;
+  int count = SPECPDL_INDEX ();
   Lisp_Object frame;
 
   if (CONSP (target_type))
@@ -1392,6 +1410,10 @@ x_get_foreign_selection (selection_symbol, target_type, time_stamp)
 
   BLOCK_INPUT;
 
+  /* The protected block contains wait_reading_process_output, which
+     can run random lisp code (process handlers) or signal.
+     Therefore, we put the x_uncatch_errors call in an unwind.  */
+  record_unwind_protect (x_catch_errors_unwind, Qnil);
   x_catch_errors (display);
 
   TRACE2 ("Get selection %s, type %s",
@@ -1409,8 +1431,6 @@ x_get_foreign_selection (selection_symbol, target_type, time_stamp)
 
   frame = some_frame_on_display (dpyinfo);
 
-  count = SPECPDL_INDEX ();
-
   /* If the display no longer has frames, we can't expect
      to get many more selection requests from it, so don't
      bother trying to queue them.  */
@@ -1432,9 +1452,10 @@ x_get_foreign_selection (selection_symbol, target_type, time_stamp)
   TRACE1 ("  Got event = %d", !NILP (XCAR (reading_selection_reply)));
 
   BLOCK_INPUT;
+  if (x_had_errors_p (display))
+    error ("Cannot get selection");
+  /* This calls x_uncatch_errors.  */
   unbind_to (count, Qnil);
-  x_check_errors (display, "Cannot get selection: %s");
-  x_uncatch_errors ();
   UNBLOCK_INPUT;
 
   if (NILP (XCAR (reading_selection_reply)))
@@ -1701,19 +1722,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)
@@ -1913,10 +1930,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;
@@ -1977,10 +1991,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]))
@@ -1996,10 +2007,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,
@@ -2009,10 +2019,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
@@ -2027,10 +2035,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.  */
@@ -2047,9 +2054,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);
 }
@@ -2335,15 +2340,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,
@@ -2376,10 +2379,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
@@ -2655,6 +2657,7 @@ If the value is 0 or the atom is not known, return the empty string.  */)
   Lisp_Object ret = Qnil;
   Display *dpy = FRAME_X_DISPLAY (f);
   Atom atom;
+  int had_errors;
 
   if (INTEGERP (value))
     atom = (Atom) XUINT (value);
@@ -2667,14 +2670,13 @@ If the value is 0 or the atom is not known, return the empty string.  */)
 
   BLOCK_INPUT;
   x_catch_errors (dpy);
-
   name = atom ? XGetAtomName (dpy, atom) : "";
+  had_errors = x_had_errors_p (dpy);
+  x_uncatch_errors ();
 
-  if (! x_had_errors_p (dpy))
+  if (!had_errors)
     ret = make_string (name, strlen (name));
 
-  x_uncatch_errors ();
-
   if (atom && name) XFree (name);
   if (NILP (ret)) ret = make_string ("", 0);
 
@@ -2683,8 +2685,48 @@ If the value is 0 or the atom is not known, return the empty string.  */)
   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)
@@ -2700,6 +2742,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);
 
@@ -2873,6 +2921,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);