xselect.c 86 KB
Newer Older
1
/* X Selection processing for Emacs.
Kim F. Storm's avatar
Kim F. Storm committed
2
   Copyright (C) 1993, 1994, 1995, 1996, 1997, 2000, 2001, 2003, 2004
3
   Free Software Foundation.
Richard M. Stallman's avatar
Richard M. Stallman committed
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

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)
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
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
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
19 20
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.  */
Richard M. Stallman's avatar
Richard M. Stallman committed
21

Jim Blandy's avatar
Jim Blandy committed
22

Richard M. Stallman's avatar
Richard M. Stallman committed
23 24
/* Rewritten by jwz */

25
#include <config.h>
Jan Djärv's avatar
Jan Djärv committed
26
#include <stdio.h>      /* termhooks.h needs this */
Richard M. Stallman's avatar
Richard M. Stallman committed
27 28
#include "lisp.h"
#include "xterm.h"	/* for all of the X includes */
29 30
#include "dispextern.h"	/* frame.h seems to want this */
#include "frame.h"	/* Need this to get the X window of selected_frame */
31
#include "blockinput.h"
Kenichi Handa's avatar
Kenichi Handa committed
32
#include "buffer.h"
Andreas Schwab's avatar
Andreas Schwab committed
33
#include "process.h"
34 35 36
#include "termhooks.h"

#include <X11/Xproto.h>
37

38 39 40 41 42 43
struct prop_location;

static Lisp_Object x_atom_to_symbol P_ ((Display *dpy, Atom atom));
static Atom symbol_to_x_atom P_ ((struct x_display_info *, Display *,
				  Lisp_Object));
static void x_own_selection P_ ((Lisp_Object, Lisp_Object));
Kenichi Handa's avatar
Kenichi Handa committed
44
static Lisp_Object x_get_local_selection P_ ((Lisp_Object, Lisp_Object, int));
45 46 47 48 49 50 51 52 53 54 55 56
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 void x_reply_selection_request P_ ((struct input_event *, int,
					   unsigned char *, int, Atom));
static int waiting_for_other_props_on_window P_ ((Display *, Window));
static struct prop_location *expect_property_change P_ ((Display *, Window,
							 Atom, int));
static void unexpect_property_change P_ ((struct prop_location *));
static Lisp_Object wait_for_property_change_unwind P_ ((Lisp_Object));
static void wait_for_property_change P_ ((struct prop_location *));
57 58 59
static Lisp_Object x_get_foreign_selection P_ ((Lisp_Object,
                                                Lisp_Object,
                                                Lisp_Object));
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
static void x_get_window_property P_ ((Display *, Window, Atom,
				       unsigned char **, int *,
				       Atom *, int *, unsigned long *, int));
static void receive_incremental_selection P_ ((Display *, Window, Atom,
					       Lisp_Object, unsigned,
					       unsigned char **, int *,
					       Atom *, int *, unsigned long *));
static Lisp_Object x_get_window_property_as_lisp_data P_ ((Display *,
							   Window, Atom,
							   Lisp_Object, Atom));
static Lisp_Object selection_data_to_lisp_data P_ ((Display *, unsigned char *,
						    int, Atom, int));
static void lisp_data_to_selection_data P_ ((Display *, Lisp_Object,
					     unsigned char **, Atom *,
					     unsigned *, int *, int *));
static Lisp_Object clean_local_selection_data P_ ((Lisp_Object));
static void initialize_cut_buffers P_ ((Display *, Window));


/* Printing traces to stderr.  */

#ifdef TRACE_SELECTION
#define TRACE0(fmt) \
  fprintf (stderr, "%d: " fmt "\n", getpid ())
#define TRACE1(fmt, a0) \
  fprintf (stderr, "%d: " fmt "\n", getpid (), a0)
#define TRACE2(fmt, a0, a1) \
  fprintf (stderr, "%d: " fmt "\n", getpid (), a0, a1)
#else
#define TRACE0(fmt)		(void) 0
#define TRACE1(fmt, a0)		(void) 0
#define TRACE2(fmt, a0, a1)	(void) 0
#endif


Richard M. Stallman's avatar
Richard M. Stallman committed
95 96 97 98 99 100
#define CUT_BUFFER_SUPPORT

Lisp_Object QPRIMARY, QSECONDARY, QSTRING, QINTEGER, QCLIPBOARD, QTIMESTAMP,
  QTEXT, QDELETE, QMULTIPLE, QINCR, QEMACS_TMP, QTARGETS, QATOM, QNULL,
  QATOM_PAIR;

Karl Heuer's avatar
Karl Heuer committed
101
Lisp_Object QCOMPOUND_TEXT;	/* This is a type of selection.  */
Kenichi Handa's avatar
Kenichi Handa committed
102
Lisp_Object QUTF8_STRING;	/* This is a type of selection.  */
Karl Heuer's avatar
Karl Heuer committed
103

104
Lisp_Object Qcompound_text_with_extensions;
105

Richard M. Stallman's avatar
Richard M. Stallman committed
106 107 108 109 110
#ifdef CUT_BUFFER_SUPPORT
Lisp_Object QCUT_BUFFER0, QCUT_BUFFER1, QCUT_BUFFER2, QCUT_BUFFER3,
  QCUT_BUFFER4, QCUT_BUFFER5, QCUT_BUFFER6, QCUT_BUFFER7;
#endif

111 112
static Lisp_Object Vx_lost_selection_hooks;
static Lisp_Object Vx_sent_selection_hooks;
113 114
/* Coding system for communicating with other X clients via cutbuffer,
   selection, and clipboard.  */
115
static Lisp_Object Vselection_coding_system;
Richard M. Stallman's avatar
Richard M. Stallman committed
116

117 118 119
/* Coding system for the next communicating with other X clients.  */
static Lisp_Object Vnext_selection_coding_system;

120 121
static Lisp_Object Qforeign_selection;

Richard M. Stallman's avatar
Richard M. Stallman committed
122 123 124
/* 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
125
   emacs to use incremental selection transfers when the selection is
Richard M. Stallman's avatar
Richard M. Stallman committed
126
   smaller than that, set this.  I added this mostly for debugging the
127
   incremental transfer stuff, but it might improve server performance.  */
Richard M. Stallman's avatar
Richard M. Stallman committed
128 129
#define MAX_SELECTION_QUANTUM 0xFFFFFF

130 131 132 133 134
#ifdef HAVE_X11R4
#define SELECTION_QUANTUM(dpy) ((XMaxRequestSize(dpy) << 2) - 100)
#else
#define SELECTION_QUANTUM(dpy) (((dpy)->max_request_size << 2) - 100)
#endif
Richard M. Stallman's avatar
Richard M. Stallman committed
135

136
/* The timestamp of the last input event Emacs received from the X server.  */
137 138
/* Defined in keyboard.c.  */
extern unsigned long last_event_timestamp;
Richard M. Stallman's avatar
Richard M. Stallman committed
139 140

/* This is an association list whose elements are of the form
141 142 143
     ( SELECTION-NAME SELECTION-VALUE SELECTION-TIMESTAMP FRAME)
   SELECTION-NAME is a lisp symbol, whose name is the name of an X Atom.
   SELECTION-VALUE is the value that emacs owns for that selection.
Richard M. Stallman's avatar
Richard M. Stallman committed
144
     It may be any kind of Lisp object.
145
   SELECTION-TIMESTAMP is the time at which emacs began owning this selection,
Richard M. Stallman's avatar
Richard M. Stallman committed
146
     as a cons of two 16-bit numbers (making a 32 bit time.)
147 148
   FRAME is the frame for which we made the selection.
   If there is an entry in this alist, then it can be assumed that Emacs owns
Richard M. Stallman's avatar
Richard M. Stallman committed
149 150
    that selection.
   The only (eq) parts of this list that are visible from Lisp are the
151 152
    selection-values.  */
static Lisp_Object Vselection_alist;
Richard M. Stallman's avatar
Richard M. Stallman committed
153 154 155

/* This is an alist whose CARs are selection-types (whose names are the same
   as the names of X Atoms) and whose CDRs are the names of Lisp functions to
156
   call to convert the given Emacs selection value to a string representing
Richard M. Stallman's avatar
Richard M. Stallman committed
157
   the given selection type.  This is for Lisp-level extension of the emacs
158 159
   selection handling.  */
static Lisp_Object Vselection_converter_alist;
Richard M. Stallman's avatar
Richard M. Stallman committed
160 161

/* If the selection owner takes too long to reply to a selection request,
162
   we give up on it.  This is in milliseconds (0 = no timeout.)  */
163
static EMACS_INT x_selection_timeout;
Richard M. Stallman's avatar
Richard M. Stallman committed
164 165 166 167 168 169 170

/* Utility functions */

static void lisp_data_to_selection_data ();
static Lisp_Object selection_data_to_lisp_data ();
static Lisp_Object x_get_window_property_as_lisp_data ();

171
/* This converts a Lisp symbol to a server Atom, avoiding a server
Richard M. Stallman's avatar
Richard M. Stallman committed
172 173 174
   roundtrip whenever possible.  */

static Atom
175 176
symbol_to_x_atom (dpyinfo, display, sym)
     struct x_display_info *dpyinfo;
Richard M. Stallman's avatar
Richard M. Stallman committed
177 178 179 180 181 182 183 184 185 186
     Display *display;
     Lisp_Object sym;
{
  Atom val;
  if (NILP (sym))	    return 0;
  if (EQ (sym, QPRIMARY))   return XA_PRIMARY;
  if (EQ (sym, QSECONDARY)) return XA_SECONDARY;
  if (EQ (sym, QSTRING))    return XA_STRING;
  if (EQ (sym, QINTEGER))   return XA_INTEGER;
  if (EQ (sym, QATOM))	    return XA_ATOM;
187 188 189
  if (EQ (sym, QCLIPBOARD)) return dpyinfo->Xatom_CLIPBOARD;
  if (EQ (sym, QTIMESTAMP)) return dpyinfo->Xatom_TIMESTAMP;
  if (EQ (sym, QTEXT))	    return dpyinfo->Xatom_TEXT;
Karl Heuer's avatar
Karl Heuer committed
190
  if (EQ (sym, QCOMPOUND_TEXT)) return dpyinfo->Xatom_COMPOUND_TEXT;
Kenichi Handa's avatar
Kenichi Handa committed
191
  if (EQ (sym, QUTF8_STRING)) return dpyinfo->Xatom_UTF8_STRING;
192 193 194 195 196 197
  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, QEMACS_TMP)) return dpyinfo->Xatom_EMACS_TMP;
  if (EQ (sym, QTARGETS))   return dpyinfo->Xatom_TARGETS;
  if (EQ (sym, QNULL))	    return dpyinfo->Xatom_NULL;
Richard M. Stallman's avatar
Richard M. Stallman committed
198 199 200 201 202 203 204 205 206 207 208 209
#ifdef CUT_BUFFER_SUPPORT
  if (EQ (sym, QCUT_BUFFER0)) return XA_CUT_BUFFER0;
  if (EQ (sym, QCUT_BUFFER1)) return XA_CUT_BUFFER1;
  if (EQ (sym, QCUT_BUFFER2)) return XA_CUT_BUFFER2;
  if (EQ (sym, QCUT_BUFFER3)) return XA_CUT_BUFFER3;
  if (EQ (sym, QCUT_BUFFER4)) return XA_CUT_BUFFER4;
  if (EQ (sym, QCUT_BUFFER5)) return XA_CUT_BUFFER5;
  if (EQ (sym, QCUT_BUFFER6)) return XA_CUT_BUFFER6;
  if (EQ (sym, QCUT_BUFFER7)) return XA_CUT_BUFFER7;
#endif
  if (!SYMBOLP (sym)) abort ();

210
  TRACE1 (" XInternAtom %s", (char *) SDATA (SYMBOL_NAME (sym)));
Richard M. Stallman's avatar
Richard M. Stallman committed
211
  BLOCK_INPUT;
212
  val = XInternAtom (display, (char *) SDATA (SYMBOL_NAME (sym)), False);
Richard M. Stallman's avatar
Richard M. Stallman committed
213 214 215 216 217 218 219 220 221
  UNBLOCK_INPUT;
  return val;
}


/* This converts a server Atom to a Lisp symbol, avoiding server roundtrips
   and calls to intern whenever possible.  */

static Lisp_Object
222 223
x_atom_to_symbol (dpy, atom)
     Display *dpy;
Richard M. Stallman's avatar
Richard M. Stallman committed
224 225
     Atom atom;
{
226
  struct x_display_info *dpyinfo;
Richard M. Stallman's avatar
Richard M. Stallman committed
227 228
  char *str;
  Lisp_Object val;
229

230 231
  if (! atom)
    return Qnil;
232

233 234 235 236 237 238 239 240 241 242 243 244
  switch (atom)
    {
    case XA_PRIMARY:
      return QPRIMARY;
    case XA_SECONDARY:
      return QSECONDARY;
    case XA_STRING:
      return QSTRING;
    case XA_INTEGER:
      return QINTEGER;
    case XA_ATOM:
      return QATOM;
Richard M. Stallman's avatar
Richard M. Stallman committed
245
#ifdef CUT_BUFFER_SUPPORT
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
    case XA_CUT_BUFFER0:
      return QCUT_BUFFER0;
    case XA_CUT_BUFFER1:
      return QCUT_BUFFER1;
    case XA_CUT_BUFFER2:
      return QCUT_BUFFER2;
    case XA_CUT_BUFFER3:
      return QCUT_BUFFER3;
    case XA_CUT_BUFFER4:
      return QCUT_BUFFER4;
    case XA_CUT_BUFFER5:
      return QCUT_BUFFER5;
    case XA_CUT_BUFFER6:
      return QCUT_BUFFER6;
    case XA_CUT_BUFFER7:
      return QCUT_BUFFER7;
Richard M. Stallman's avatar
Richard M. Stallman committed
262
#endif
263 264
    }

265
  dpyinfo = x_display_info_for_display (dpy);
266
  if (atom == dpyinfo->Xatom_CLIPBOARD)
267
    return QCLIPBOARD;
268
  if (atom == dpyinfo->Xatom_TIMESTAMP)
269
    return QTIMESTAMP;
270
  if (atom == dpyinfo->Xatom_TEXT)
271
    return QTEXT;
Karl Heuer's avatar
Karl Heuer committed
272 273
  if (atom == dpyinfo->Xatom_COMPOUND_TEXT)
    return QCOMPOUND_TEXT;
Kenichi Handa's avatar
Kenichi Handa committed
274 275
  if (atom == dpyinfo->Xatom_UTF8_STRING)
    return QUTF8_STRING;
276
  if (atom == dpyinfo->Xatom_DELETE)
277
    return QDELETE;
278
  if (atom == dpyinfo->Xatom_MULTIPLE)
279
    return QMULTIPLE;
280
  if (atom == dpyinfo->Xatom_INCR)
281
    return QINCR;
282
  if (atom == dpyinfo->Xatom_EMACS_TMP)
283
    return QEMACS_TMP;
284
  if (atom == dpyinfo->Xatom_TARGETS)
285
    return QTARGETS;
286
  if (atom == dpyinfo->Xatom_NULL)
287
    return QNULL;
Richard M. Stallman's avatar
Richard M. Stallman committed
288 289

  BLOCK_INPUT;
290
  str = XGetAtomName (dpy, atom);
Richard M. Stallman's avatar
Richard M. Stallman committed
291
  UNBLOCK_INPUT;
292
  TRACE1 ("XGetAtomName --> %s", str);
Richard M. Stallman's avatar
Richard M. Stallman committed
293 294 295
  if (! str) return Qnil;
  val = intern (str);
  BLOCK_INPUT;
296
  /* This was allocated by Xlib, so use XFree.  */
Richard M. Stallman's avatar
Richard M. Stallman committed
297 298 299 300
  XFree (str);
  UNBLOCK_INPUT;
  return val;
}
301

Richard M. Stallman's avatar
Richard M. Stallman committed
302
/* Do protocol to assert ourself as a selection owner.
303
   Update the Vselection_alist so that we can reply to later requests for
Richard M. Stallman's avatar
Richard M. Stallman committed
304 305 306 307 308 309
   our selection.  */

static void
x_own_selection (selection_name, selection_value)
     Lisp_Object selection_name, selection_value;
{
310 311 312
  struct frame *sf = SELECTED_FRAME ();
  Window selecting_window = FRAME_X_WINDOW (sf);
  Display *display = FRAME_X_DISPLAY (sf);
313
  Time time = last_event_timestamp;
Richard M. Stallman's avatar
Richard M. Stallman committed
314
  Atom selection_atom;
315
  struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (sf);
316
  int count;
Richard M. Stallman's avatar
Richard M. Stallman committed
317

318
  CHECK_SYMBOL (selection_name);
319
  selection_atom = symbol_to_x_atom (dpyinfo, display, selection_name);
Richard M. Stallman's avatar
Richard M. Stallman committed
320 321

  BLOCK_INPUT;
322
  count = x_catch_errors (display);
Richard M. Stallman's avatar
Richard M. Stallman committed
323
  XSetSelectionOwner (display, selection_atom, selecting_window, time);
324
  x_check_errors (display, "Can't set selection: %s");
325
  x_uncatch_errors (display, count);
Richard M. Stallman's avatar
Richard M. Stallman committed
326 327 328 329 330 331 332 333 334 335 336
  UNBLOCK_INPUT;

  /* Now update the local cache */
  {
    Lisp_Object selection_time;
    Lisp_Object selection_data;
    Lisp_Object prev_value;

    selection_time = long_to_cons ((unsigned long) time);
    selection_data = Fcons (selection_name,
			    Fcons (selection_value,
337
				   Fcons (selection_time,
338
					  Fcons (selected_frame, Qnil))));
Richard M. Stallman's avatar
Richard M. Stallman committed
339 340 341 342 343 344 345 346 347 348 349
    prev_value = assq_no_quit (selection_name, Vselection_alist);

    Vselection_alist = Fcons (selection_data, Vselection_alist);

    /* If we already owned the selection, remove the old selection data.
       Perhaps we should destructively modify it instead.
       Don't use Fdelq as that may QUIT.  */
    if (!NILP (prev_value))
      {
	Lisp_Object rest;	/* we know it's not the CAR, so it's easy.  */
	for (rest = Vselection_alist; !NILP (rest); rest = Fcdr (rest))
350
	  if (EQ (prev_value, Fcar (XCDR (rest))))
Richard M. Stallman's avatar
Richard M. Stallman committed
351
	    {
352
	      XSETCDR (rest, Fcdr (XCDR (rest)));
Richard M. Stallman's avatar
Richard M. Stallman committed
353 354 355 356 357 358 359 360 361
	      break;
	    }
      }
  }
}

/* Given a selection-name and desired type, look up our local copy of
   the selection value and convert it to the type.
   The value is nil or a string.
Kenichi Handa's avatar
Kenichi Handa committed
362 363
   This function is used both for remote requests (LOCAL_REQUEST is zero)
   and for local x-get-selection-internal (LOCAL_REQUEST is nonzero).
Richard M. Stallman's avatar
Richard M. Stallman committed
364 365 366 367

   This calls random Lisp code, and may signal or gc.  */

static Lisp_Object
Kenichi Handa's avatar
Kenichi Handa committed
368
x_get_local_selection (selection_symbol, target_type, local_request)
Richard M. Stallman's avatar
Richard M. Stallman committed
369
     Lisp_Object selection_symbol, target_type;
Kenichi Handa's avatar
Kenichi Handa committed
370
     int local_request;
Richard M. Stallman's avatar
Richard M. Stallman committed
371 372 373 374 375 376 377 378 379 380 381 382 383
{
  Lisp_Object local_value;
  Lisp_Object handler_fn, value, type, check;
  int count;

  local_value = assq_no_quit (selection_symbol, Vselection_alist);

  if (NILP (local_value)) return Qnil;

  /* TIMESTAMP and MULTIPLE are special cases 'cause that's easiest.  */
  if (EQ (target_type, QTIMESTAMP))
    {
      handler_fn = Qnil;
384
      value = XCAR (XCDR (XCDR (local_value)));
Richard M. Stallman's avatar
Richard M. Stallman committed
385 386 387 388 389 390 391
    }
#if 0
  else if (EQ (target_type, QDELETE))
    {
      handler_fn = Qnil;
      Fx_disown_selection_internal
	(selection_symbol,
392
	 XCAR (XCDR (XCDR (local_value))));
Richard M. Stallman's avatar
Richard M. Stallman committed
393 394 395 396 397 398
      value = QNULL;
    }
#endif

#if 0 /* #### MULTIPLE doesn't work yet */
  else if (CONSP (target_type)
399
	   && XCAR (target_type) == QMULTIPLE)
Richard M. Stallman's avatar
Richard M. Stallman committed
400
    {
401 402
      Lisp_Object pairs;
      int size;
Richard M. Stallman's avatar
Richard M. Stallman committed
403
      int i;
404
      pairs = XCDR (target_type);
405
      size = XVECTOR (pairs)->size;
Richard M. Stallman's avatar
Richard M. Stallman committed
406 407 408 409 410 411 412
      /* If the target is MULTIPLE, then target_type looks like
	  (MULTIPLE . [[SELECTION1 TARGET1] [SELECTION2 TARGET2] ... ])
	 We modify the second element of each pair in the vector and
	 return it as [[SELECTION1 <value1>] [SELECTION2 <value2>] ... ]
       */
      for (i = 0; i < size; i++)
	{
413 414
	  Lisp_Object pair;
	  pair = XVECTOR (pairs)->contents [i];
Richard M. Stallman's avatar
Richard M. Stallman committed
415 416
	  XVECTOR (pair)->contents [1]
	    = x_get_local_selection (XVECTOR (pair)->contents [0],
Kenichi Handa's avatar
Kenichi Handa committed
417 418
				     XVECTOR (pair)->contents [1],
				     local_request);
Richard M. Stallman's avatar
Richard M. Stallman committed
419 420 421 422 423 424 425 426 427
	}
      return pairs;
    }
#endif
  else
    {
      /* Don't allow a quit within the converter.
	 When the user types C-g, he would be surprised
	 if by luck it came during a converter.  */
Juanma Barranquero's avatar
Juanma Barranquero committed
428
      count = SPECPDL_INDEX ();
Richard M. Stallman's avatar
Richard M. Stallman committed
429 430
      specbind (Qinhibit_quit, Qt);

431
      CHECK_SYMBOL (target_type);
Richard M. Stallman's avatar
Richard M. Stallman committed
432
      handler_fn = Fcdr (Fassq (target_type, Vselection_converter_alist));
433 434 435
      /* gcpro is not needed here since nothing but HANDLER_FN
	 is live, and that ought to be a symbol.  */

436 437
      if (!NILP (handler_fn))
	value = call3 (handler_fn,
Kenichi Handa's avatar
Kenichi Handa committed
438
		       selection_symbol, (local_request ? Qnil : target_type),
439
		       XCAR (XCDR (local_value)));
440 441
      else
	value = Qnil;
Richard M. Stallman's avatar
Richard M. Stallman committed
442 443 444 445 446
      unbind_to (count, Qnil);
    }

  /* Make sure this value is of a type that we could transmit
     to another X client.  */
Richard M. Stallman's avatar
Richard M. Stallman committed
447

Richard M. Stallman's avatar
Richard M. Stallman committed
448 449
  check = value;
  if (CONSP (value)
450 451 452
      && SYMBOLP (XCAR (value)))
    type = XCAR (value),
    check = XCDR (value);
453

Richard M. Stallman's avatar
Richard M. Stallman committed
454 455 456
  if (STRINGP (check)
      || VECTORP (check)
      || SYMBOLP (check)
457
      || INTEGERP (check)
Richard M. Stallman's avatar
Richard M. Stallman committed
458 459
      || NILP (value))
    return value;
Richard M. Stallman's avatar
Richard M. Stallman committed
460
  /* Check for a value that cons_to_long could handle.  */
Richard M. Stallman's avatar
Richard M. Stallman committed
461
  else if (CONSP (check)
462 463
	   && INTEGERP (XCAR (check))
	   && (INTEGERP (XCDR (check))
Richard M. Stallman's avatar
Richard M. Stallman committed
464
	       ||
465 466 467
	       (CONSP (XCDR (check))
		&& INTEGERP (XCAR (XCDR (check)))
		&& NILP (XCDR (XCDR (check))))))
Richard M. Stallman's avatar
Richard M. Stallman committed
468 469 470 471
    return value;
  else
    return
      Fsignal (Qerror,
Richard M. Stallman's avatar
Richard M. Stallman committed
472
	       Fcons (build_string ("invalid data returned by selection-conversion function"),
Richard M. Stallman's avatar
Richard M. Stallman committed
473 474 475 476 477
		      Fcons (handler_fn, Fcons (value, Qnil))));
}

/* Subroutines of x_reply_selection_request.  */

478
/* Send a SelectionNotify event to the requestor with property=None,
Richard M. Stallman's avatar
Richard M. Stallman committed
479 480 481 482 483 484 485
   meaning we were unable to do what they wanted.  */

static void
x_decline_selection_request (event)
     struct input_event *event;
{
  XSelectionEvent reply;
486
  int count;
487

Richard M. Stallman's avatar
Richard M. Stallman committed
488 489
  reply.type = SelectionNotify;
  reply.display = SELECTION_EVENT_DISPLAY (event);
490
  reply.requestor = SELECTION_EVENT_REQUESTOR (event);
Richard M. Stallman's avatar
Richard M. Stallman committed
491 492 493 494 495
  reply.selection = SELECTION_EVENT_SELECTION (event);
  reply.time = SELECTION_EVENT_TIME (event);
  reply.target = SELECTION_EVENT_TARGET (event);
  reply.property = None;

496 497
  /* The reason for the error may be that the receiver has
     died in the meantime.  Handle that case.  */
Richard M. Stallman's avatar
Richard M. Stallman committed
498
  BLOCK_INPUT;
499 500
  count = x_catch_errors (reply.display);
  XSendEvent (reply.display, reply.requestor, False, 0L, (XEvent *) &reply);
501
  XFlush (reply.display);
502
  x_uncatch_errors (reply.display, count);
Richard M. Stallman's avatar
Richard M. Stallman committed
503 504 505 506 507 508 509
  UNBLOCK_INPUT;
}

/* 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;

510 511 512 513
/* Display info in x_selection_request.  */

static struct x_display_info *selection_request_dpyinfo;

Richard M. Stallman's avatar
Richard M. Stallman committed
514
/* Used as an unwind-protect clause so that, if a selection-converter signals
515
   an error, we tell the requester that we were unable to do what they wanted
Richard M. Stallman's avatar
Richard M. Stallman committed
516 517 518 519 520 521
   before we throw to top-level or go into the debugger or whatever.  */

static Lisp_Object
x_selection_request_lisp_error (ignore)
     Lisp_Object ignore;
{
522 523
  if (x_selection_current_request != 0
      && selection_request_dpyinfo->display)
Richard M. Stallman's avatar
Richard M. Stallman committed
524 525 526 527
    x_decline_selection_request (x_selection_current_request);
  return Qnil;
}

528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557

/* This stuff is so that INCR selections are reentrant (that is, so we can
   be servicing multiple INCR selection requests simultaneously.)  I haven't
   actually tested that yet.  */

/* Keep a list of the property changes that are awaited.  */

struct prop_location
{
  int identifier;
  Display *display;
  Window window;
  Atom property;
  int desired_state;
  int arrived;
  struct prop_location *next;
};

static struct prop_location *expect_property_change ();
static void wait_for_property_change ();
static void unexpect_property_change ();
static int waiting_for_other_props_on_window ();

static int prop_location_identifier;

static Lisp_Object property_change_reply;

static struct prop_location *property_change_reply_object;

static struct prop_location *property_change_wait_list;
558 559 560 561 562 563 564 565 566

static Lisp_Object
queue_selection_requests_unwind (frame)
     Lisp_Object frame;
{
  FRAME_PTR f = XFRAME (frame);

  if (! NILP (frame))
    x_stop_queuing_selection_requests (FRAME_X_DISPLAY (f));
567
  return Qnil;
568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586
}

/* Return some frame whose display info is DPYINFO.
   Return nil if there is none.  */

static Lisp_Object
some_frame_on_display (dpyinfo)
     struct x_display_info *dpyinfo;
{
  Lisp_Object list, frame;

  FOR_EACH_FRAME (list, frame)
    {
      if (FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
	return frame;
    }

  return Qnil;
}
587

Richard M. Stallman's avatar
Richard M. Stallman committed
588 589 590 591 592 593 594 595 596 597 598 599 600 601
/* Send the reply to a selection request event EVENT.
   TYPE is the type of selection data requested.
   DATA and SIZE describe the data to send, already converted.
   FORMAT is the unit-size (in bits) of the data to be transmitted.  */

static void
x_reply_selection_request (event, format, data, size, type)
     struct input_event *event;
     int format, size;
     unsigned char *data;
     Atom type;
{
  XSelectionEvent reply;
  Display *display = SELECTION_EVENT_DISPLAY (event);
602
  Window window = SELECTION_EVENT_REQUESTOR (event);
Richard M. Stallman's avatar
Richard M. Stallman committed
603 604 605
  int bytes_remaining;
  int format_bytes = format/8;
  int max_bytes = SELECTION_QUANTUM (display);
606
  struct x_display_info *dpyinfo = x_display_info_for_display (display);
607
  int count;
Richard M. Stallman's avatar
Richard M. Stallman committed
608 609 610 611 612 613

  if (max_bytes > MAX_SELECTION_QUANTUM)
    max_bytes = MAX_SELECTION_QUANTUM;

  reply.type = SelectionNotify;
  reply.display = display;
614
  reply.requestor = window;
Richard M. Stallman's avatar
Richard M. Stallman committed
615 616 617 618 619 620 621 622
  reply.selection = SELECTION_EVENT_SELECTION (event);
  reply.time = SELECTION_EVENT_TIME (event);
  reply.target = SELECTION_EVENT_TARGET (event);
  reply.property = SELECTION_EVENT_PROPERTY (event);
  if (reply.property == None)
    reply.property = reply.target;

  /* #### XChangeProperty can generate BadAlloc, and we must handle it! */
623
  BLOCK_INPUT;
624
  count = x_catch_errors (display);
Richard M. Stallman's avatar
Richard M. Stallman committed
625 626 627 628 629 630 631 632

  /* Store the data on the requested property.
     If the selection is large, only store the first N bytes of it.
   */
  bytes_remaining = size * format_bytes;
  if (bytes_remaining <= max_bytes)
    {
      /* Send all the data at once, with minimal handshaking.  */
633
      TRACE1 ("Sending all %d bytes", bytes_remaining);
Richard M. Stallman's avatar
Richard M. Stallman committed
634 635 636
      XChangeProperty (display, window, reply.property, type, format,
		       PropModeReplace, data, size);
      /* At this point, the selection was successfully stored; ack it.  */
637
      XSendEvent (display, window, False, 0L, (XEvent *) &reply);
Richard M. Stallman's avatar
Richard M. Stallman committed
638 639 640 641
    }
  else
    {
      /* Send an INCR selection.  */
642
      struct prop_location *wait_object;
643
      int had_errors;
644
      Lisp_Object frame;
Richard M. Stallman's avatar
Richard M. Stallman committed
645

646 647 648 649 650 651 652 653 654 655 656 657
      frame = some_frame_on_display (dpyinfo);

      /* If the display no longer has frames, we can't expect
	 to get many more selection requests from it, so don't
	 bother trying to queue them.  */
      if (!NILP (frame))
	{
	  x_start_queuing_selection_requests (display);

	  record_unwind_protect (queue_selection_requests_unwind,
				 frame);
	}
658

659
      if (x_window_to_frame (dpyinfo, window)) /* #### debug */
660
	error ("Attempt to transfer an INCR to ourself!");
661

662 663
      TRACE2 ("Start sending %d bytes incrementally (%s)",
	      bytes_remaining,  XGetAtomName (display, reply.property));
664 665
      wait_object = expect_property_change (display, window, reply.property,
					    PropertyDelete);
Richard M. Stallman's avatar
Richard M. Stallman committed
666

667 668
      TRACE1 ("Set %s to number of bytes to send",
	      XGetAtomName (display, reply.property));
669
      XChangeProperty (display, window, reply.property, dpyinfo->Xatom_INCR,
670 671
		       32, PropModeReplace,
		       (unsigned char *) &bytes_remaining, 1);
Richard M. Stallman's avatar
Richard M. Stallman committed
672
      XSelectInput (display, window, PropertyChangeMask);
673

Richard M. Stallman's avatar
Richard M. Stallman committed
674
      /* Tell 'em the INCR data is there...  */
675
      TRACE0 ("Send SelectionNotify event");
676
      XSendEvent (display, window, False, 0L, (XEvent *) &reply);
677
      XFlush (display);
678 679

      had_errors = x_had_errors_p (display);
680
      UNBLOCK_INPUT;
Richard M. Stallman's avatar
Richard M. Stallman committed
681

682
      /* First, wait for the requester to ack by deleting the property.
Richard M. Stallman's avatar
Richard M. Stallman committed
683
	 This can run random lisp code (process handlers) or signal.  */
684
      if (! had_errors)
685 686 687 688 689
	{
	  TRACE1 ("Waiting for ACK (deletion of %s)",
		  XGetAtomName (display, reply.property));
	  wait_for_property_change (wait_object);
	}
Richard M. Stallman's avatar
Richard M. Stallman committed
690

691
      TRACE0 ("Got ACK");
Richard M. Stallman's avatar
Richard M. Stallman committed
692 693 694 695 696
      while (bytes_remaining)
	{
	  int i = ((bytes_remaining < max_bytes)
		   ? bytes_remaining
		   : max_bytes);
697 698 699

	  BLOCK_INPUT;

700 701 702
	  wait_object
	    = expect_property_change (display, window, reply.property,
				      PropertyDelete);
703 704 705 706

	  TRACE1 ("Sending increment of %d bytes", i);
	  TRACE1 ("Set %s to increment data",
		  XGetAtomName (display, reply.property));
707

Richard M. Stallman's avatar
Richard M. Stallman committed
708 709 710 711 712
	  /* Append the next chunk of data to the property.  */
	  XChangeProperty (display, window, reply.property, type, format,
			   PropModeAppend, data, i / format_bytes);
	  bytes_remaining -= i;
	  data += i;
713
	  XFlush (display);
714
	  had_errors = x_had_errors_p (display);
715
	  UNBLOCK_INPUT;
Richard M. Stallman's avatar
Richard M. Stallman committed
716

717 718 719
	  if (had_errors)
	    break;

720
	  /* Now wait for the requester to ack this chunk by deleting the
721 722 723
	     property.	 This can run random lisp code or signal.  */
	  TRACE1 ("Waiting for increment ACK (deletion of %s)",
		  XGetAtomName (display, reply.property));
724
	  wait_for_property_change (wait_object);
Richard M. Stallman's avatar
Richard M. Stallman committed
725
	}
726

727 728
      /* Now write a zero-length chunk to the property to tell the
	 requester that we're done.  */
729
      BLOCK_INPUT;
Richard M. Stallman's avatar
Richard M. Stallman committed
730 731 732
      if (! waiting_for_other_props_on_window (display, window))
	XSelectInput (display, window, 0L);

733 734
      TRACE1 ("Set %s to a 0-length chunk to indicate EOF",
	      XGetAtomName (display, reply.property));
Richard M. Stallman's avatar
Richard M. Stallman committed
735 736
      XChangeProperty (display, window, reply.property, type, format,
		       PropModeReplace, data, 0);
737
      TRACE0 ("Done sending incrementally");
Richard M. Stallman's avatar
Richard M. Stallman committed
738
    }
739

Richard M. Stallman's avatar
Richard M. Stallman committed
740
  /* rms, 2003-01-03: I think I have fixed this bug.  */
741 742 743 744 745 746
  /* The window we're communicating with may have been deleted
     in the meantime (that's a real situation from a bug report).
     In this case, there may be events in the event queue still
     refering to the deleted window, and we'll get a BadWindow error
     in XTread_socket when processing the events.  I don't have
     an idea how to fix that.  gerd, 2001-01-98.   */
747 748 749
  /* 2004-09-10: XSync and UNBLOCK so that possible protocol errors are
     delivered before uncatch errors.  */
  XSync (display, False);
750
  UNBLOCK_INPUT;
751 752 753 754 755

  /* GTK queues events in addition to the queue in Xlib.  So we
     UNBLOCK to enter the event loop and get possible errors delivered,
     and then BLOCK again because x_uncatch_errors requires it.  */
  BLOCK_INPUT;
756
  x_uncatch_errors (display, count);
757
  UNBLOCK_INPUT;
Richard M. Stallman's avatar
Richard M. Stallman committed
758 759 760 761 762 763 764 765 766 767
}

/* Handle a SelectionRequest event EVENT.
   This is called from keyboard.c when such an event is found in the queue.  */

void
x_handle_selection_request (event)
     struct input_event *event;
{
  struct gcpro gcpro1, gcpro2, gcpro3;
768
  Lisp_Object local_selection_data;
Richard M. Stallman's avatar
Richard M. Stallman committed
769
  Lisp_Object selection_symbol;
770 771
  Lisp_Object target_symbol;
  Lisp_Object converted_selection;
Richard M. Stallman's avatar
Richard M. Stallman committed
772
  Time local_selection_time;
773
  Lisp_Object successful_p;
Richard M. Stallman's avatar
Richard M. Stallman committed
774
  int count;
775 776
  struct x_display_info *dpyinfo
    = x_display_info_for_display (SELECTION_EVENT_DISPLAY (event));
Richard M. Stallman's avatar
Richard M. Stallman committed
777

778 779 780 781 782
  local_selection_data = Qnil;
  target_symbol = Qnil;
  converted_selection = Qnil;
  successful_p = Qnil;

Richard M. Stallman's avatar
Richard M. Stallman committed
783 784
  GCPRO3 (local_selection_data, converted_selection, target_symbol);

785
  selection_symbol = x_atom_to_symbol (SELECTION_EVENT_DISPLAY (event),
Richard M. Stallman's avatar
Richard M. Stallman committed
786 787 788 789 790 791 792 793 794 795 796 797 798
				       SELECTION_EVENT_SELECTION (event));

  local_selection_data = assq_no_quit (selection_symbol, Vselection_alist);

  if (NILP (local_selection_data))
    {
      /* Someone asked for the selection, but we don't have it any more.
       */
      x_decline_selection_request (event);
      goto DONE;
    }

  local_selection_time = (Time)
799
    cons_to_long (XCAR (XCDR (XCDR (local_selection_data))));
Richard M. Stallman's avatar
Richard M. Stallman committed
800 801

  if (SELECTION_EVENT_TIME (event) != CurrentTime
802
      && local_selection_time > SELECTION_EVENT_TIME (event))
Richard M. Stallman's avatar
Richard M. Stallman committed
803 804 805 806 807 808 809 810 811
    {
      /* Someone asked for the selection, and we have one, but not the one
	 they're looking for.
       */
      x_decline_selection_request (event);
      goto DONE;
    }

  x_selection_current_request = event;
812
  count = SPECPDL_INDEX ();
813
  selection_request_dpyinfo = dpyinfo;
Richard M. Stallman's avatar
Richard M. Stallman committed
814 815
  record_unwind_protect (x_selection_request_lisp_error, Qnil);

816
  target_symbol = x_atom_to_symbol (SELECTION_EVENT_DISPLAY (event),
Richard M. Stallman's avatar
Richard M. Stallman committed
817 818 819 820 821 822
				    SELECTION_EVENT_TARGET (event));

#if 0 /* #### MULTIPLE doesn't work yet */
  if (EQ (target_symbol, QMULTIPLE))
    target_symbol = fetch_multiple_target (event);
#endif
823

Richard M. Stallman's avatar
Richard M. Stallman committed
824
  /* Convert lisp objects back into binary data */
825

Richard M. Stallman's avatar
Richard M. Stallman committed
826
  converted_selection
Kenichi Handa's avatar
Kenichi Handa committed
827
    = x_get_local_selection (selection_symbol, target_symbol, 0);
828

Richard M. Stallman's avatar
Richard M. Stallman committed
829 830 831 832 833 834
  if (! NILP (converted_selection))
    {
      unsigned char *data;
      unsigned int size;
      int format;
      Atom type;
835 836
      int nofree;

837 838
      lisp_data_to_selection_data (SELECTION_EVENT_DISPLAY (event),
				   converted_selection,
839
				   &data, &type, &size, &format, &nofree);
840

Richard M. Stallman's avatar
Richard M. Stallman committed
841 842 843 844
      x_reply_selection_request (event, format, data, size, type);
      successful_p = Qt;

      /* Indicate we have successfully processed this event.  */
845
      x_selection_current_request = 0;
Richard M. Stallman's avatar
Richard M. Stallman committed
846

847
      /* Use xfree, not XFree, because lisp_data_to_selection_data
848
	 calls xmalloc itself.  */
849
      if (!nofree)
850
	xfree (data);
Richard M. Stallman's avatar
Richard M. Stallman committed
851 852 853 854 855 856 857
    }
  unbind_to (count, Qnil);

 DONE:

  /* Let random lisp code notice that the selection has been asked for.  */
  {
858 859
    Lisp_Object rest;
    rest = Vx_sent_selection_hooks;
Richard M. Stallman's avatar
Richard M. Stallman committed
860 861 862 863
    if (!EQ (rest, Qunbound))
      for (; CONSP (rest); rest = Fcdr (rest))
	call3 (Fcar (rest), selection_symbol, target_symbol, successful_p);
  }
864 865

  UNGCPRO;
Richard M. Stallman's avatar
Richard M. Stallman committed
866 867
}

868
/* Handle a SelectionClear event EVENT, which indicates that some
Richard M. Stallman's avatar
Richard M. Stallman committed
869 870 871 872 873 874 875 876 877 878
   client cleared out our previously asserted selection.
   This is called from keyboard.c when such an event is found in the queue.  */

void
x_handle_selection_clear (event)
     struct input_event *event;
{
  Display *display = SELECTION_EVENT_DISPLAY (event);
  Atom selection = SELECTION_EVENT_SELECTION (event);
  Time changed_owner_time = SELECTION_EVENT_TIME (event);
879

Richard M. Stallman's avatar
Richard M. Stallman committed
880 881
  Lisp_Object selection_symbol, local_selection_data;
  Time local_selection_time;
882
  struct x_display_info *dpyinfo = x_display_info_for_display (display);
883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902
  struct x_display_info *t_dpyinfo;

  /* If the new selection owner is also Emacs,
     don't clear the new selection.  */
  BLOCK_INPUT;
  /* Check each display on the same terminal,
     to see if this Emacs job now owns the selection
     through that display.  */
  for (t_dpyinfo = x_display_list; t_dpyinfo; t_dpyinfo = t_dpyinfo->next)
    if (t_dpyinfo->kboard == dpyinfo->kboard)
      {
	Window owner_window
	  = XGetSelectionOwner (t_dpyinfo->display, selection);
	if (x_window_to_frame (t_dpyinfo, owner_window) != 0)
	  {
	    UNBLOCK_INPUT;
	    return;
	  }
      }
  UNBLOCK_INPUT;
Richard M. Stallman's avatar
Richard M. Stallman committed
903

904
  selection_symbol = x_atom_to_symbol (display, selection);
Richard M. Stallman's avatar
Richard M. Stallman committed
905 906 907 908 909 910 911

  local_selection_data = assq_no_quit (selection_symbol, Vselection_alist);

  /* Well, we already believe that we don't own it, so that's just fine.  */
  if (NILP (local_selection_data)) return;

  local_selection_time = (Time)
912
    cons_to_long (XCAR (XCDR (XCDR (local_selection_data))));
Richard M. Stallman's avatar
Richard M. Stallman committed
913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930

  /* This SelectionClear is for a selection that we no longer own, so we can
     disregard it.  (That is, we have reasserted the selection since this
     request was generated.)  */

  if (changed_owner_time != CurrentTime
      && local_selection_time > changed_owner_time)
    return;

  /* Otherwise, we're really honest and truly being told to drop it.
     Don't use Fdelq as that may QUIT;.  */

  if (EQ (local_selection_data, Fcar (Vselection_alist)))
    Vselection_alist = Fcdr (Vselection_alist);
  else
    {
      Lisp_Object rest;
      for (rest = Vselection_alist; !NILP (rest); rest = Fcdr (rest))
931
	if (EQ (local_selection_data, Fcar (XCDR (rest))))
Richard M. Stallman's avatar
Richard M. Stallman committed
932
	  {
933
	    XSETCDR (rest, Fcdr (XCDR (rest)));
Richard M. Stallman's avatar
Richard M. Stallman committed
934 935 936 937 938 939 940
	    break;
	  }
    }

  /* Let random lisp code notice that the selection has been stolen.  */

  {
941 942
    Lisp_Object rest;
    rest = Vx_lost_selection_hooks;
Richard M. Stallman's avatar
Richard M. Stallman committed
943
    if (!EQ (rest, Qunbound))
944 945 946
      {
	for (; CONSP (rest); rest = Fcdr (rest))
	  call1 (Fcar (rest), selection_symbol);
947
	prepare_menu_bars ();
948
	redisplay_preserve_echo_area (20);
949
      }
Richard M. Stallman's avatar
Richard M. Stallman committed
950 951 952
  }
}

953 954 955 956 957 958 959 960 961 962
/* Clear all selections that were made from frame F.
   We do this when about to delete a frame.  */

void
x_clear_frame_selections (f)
     FRAME_PTR f;
{
  Lisp_Object frame;
  Lisp_Object rest;

963
  XSETFRAME (frame, f);
964 965 966 967

  /* Otherwise, we're really honest and truly being told to drop it.
     Don't use Fdelq as that may QUIT;.  */

968 969 970 971 972 973 974 975 976 977 978 979 980 981
  /* Delete elements from the beginning of Vselection_alist.  */
  while (!NILP (Vselection_alist)
	 && EQ (frame, Fcar (Fcdr (Fcdr (Fcdr (Fcar (Vselection_alist)))))))
    {
      /* Let random Lisp code notice that the selection has been stolen.  */
      Lisp_Object hooks, selection_symbol;

      hooks = Vx_lost_selection_hooks;
      selection_symbol = Fcar (Fcar (Vselection_alist));

      if (!EQ (hooks, Qunbound))
	{
	  for (; CONSP (hooks); hooks = Fcdr (hooks))
	    call1 (Fcar (hooks), selection_symbol);
982 983 984
#if 0 /* This can crash when deleting a frame
	 from x_connection_closed.  Anyway, it seems unnecessary;
	 something else should cause a redisplay.  */
985
	  redisplay_preserve_echo_area (21);
986
#endif
987 988 989 990 991 992
	}

      Vselection_alist = Fcdr (Vselection_alist);
    }

  /* Delete elements after the beginning of Vselection_alist.  */
993
  for (rest = Vselection_alist; !NILP (rest); rest = Fcdr (rest))
994
    if (EQ (frame, Fcar (Fcdr (Fcdr (Fcdr (Fcar (XCDR (rest))))))))
995 996 997 998 999
      {
	/* Let random Lisp code notice that the selection has been stolen.  */
	Lisp_Object hooks, selection_symbol;

	hooks = Vx_lost_selection_hooks;
1000
	selection_symbol = Fcar (Fcar (XCDR (rest)));
1001 1002 1003 1004 1005

	if (!EQ (hooks, Qunbound))
	  {
	    for (; CONSP (hooks); hooks = Fcdr (hooks))
	      call1 (Fcar (hooks), selection_symbol);
1006
#if 0 /* See above */
1007
	    redisplay_preserve_echo_area (22);
Miles Bader's avatar