XEmacs 21.2.28 "Hermes".
[chise/xemacs-chise.git.1] / src / select-x.c
1 /* X Selection processing for XEmacs
2    Copyright (C) 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
3
4 This file is part of XEmacs.
5
6 XEmacs is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
10
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with XEmacs; see the file COPYING.  If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.  */
20
21 /* Synched up with: Not synched with FSF. */
22
23 /* Rewritten by jwz */
24
25 #include <config.h>
26 #include "lisp.h"
27
28 #include "buffer.h"
29 #include "console-x.h"
30 #include "objects-x.h"
31
32 #include "frame.h"
33 #include "opaque.h"
34 #include "systime.h"
35 #include "select.h"
36
37 int lisp_to_time (Lisp_Object, time_t *);
38 Lisp_Object time_to_lisp (time_t);
39
40 #ifdef LWLIB_USES_MOTIF
41 # define MOTIF_CLIPBOARDS
42 #endif
43
44 #ifdef MOTIF_CLIPBOARDS
45 # include <Xm/CutPaste.h>
46 static void hack_motif_clipboard_selection (Atom selection_atom,
47                                             Lisp_Object selection_value,
48                                             Time thyme, Display *display,
49                                             Window selecting_window);
50 #endif
51
52 #define CUT_BUFFER_SUPPORT
53
54 #ifdef CUT_BUFFER_SUPPORT
55 Lisp_Object QCUT_BUFFER0, QCUT_BUFFER1, QCUT_BUFFER2, QCUT_BUFFER3,
56   QCUT_BUFFER4, QCUT_BUFFER5, QCUT_BUFFER6, QCUT_BUFFER7;
57 #endif
58
59 Lisp_Object Vx_sent_selection_hooks;
60
61 /* If this is a smaller number than the max-request-size of the display,
62    emacs will use INCR selection transfer when the selection is larger
63    than this.  The max-request-size is usually around 64k, so if you want
64    emacs to use incremental selection transfers when the selection is
65    smaller than that, set this.  I added this mostly for debugging the
66    incremental transfer stuff, but it might improve server performance.
67  */
68 #define MAX_SELECTION_QUANTUM 0xFFFFFF
69
70 #define SELECTION_QUANTUM(dpy) ((XMaxRequestSize (dpy) << 2) - 100)
71
72 /* If the selection owner takes too long to reply to a selection request,
73    we give up on it.  This is in seconds (0 = no timeout).
74  */
75 int x_selection_timeout;
76
77 \f
78 /* Utility functions */
79
80 static void lisp_data_to_selection_data (struct device *,
81                                          Lisp_Object obj,
82                                          unsigned char **data_ret,
83                                          Atom *type_ret,
84                                          unsigned int *size_ret,
85                                          int *format_ret);
86 static Lisp_Object selection_data_to_lisp_data (struct device *,
87                                                 unsigned char *data,
88                                                 size_t size,
89                                                 Atom type,
90                                                 int format);
91 static Lisp_Object x_get_window_property_as_lisp_data (Display *,
92                                                        Window,
93                                                        Atom property,
94                                                        Lisp_Object target_type,
95                                                        Atom selection_atom);
96
97 static int expect_property_change (Display *, Window, Atom prop, int state);
98 static void wait_for_property_change (long);
99 static void unexpect_property_change (int);
100 static int waiting_for_other_props_on_window (Display *, Window);
101
102 /* This converts a Lisp symbol to a server Atom, avoiding a server
103    roundtrip whenever possible.
104  */
105 static Atom
106 symbol_to_x_atom (struct device *d, Lisp_Object sym, int only_if_exists)
107 {
108   Display *display = DEVICE_X_DISPLAY (d);
109
110   if (NILP (sym))               return XA_PRIMARY;
111   if (EQ (sym, Qt))             return XA_SECONDARY;
112   if (EQ (sym, QPRIMARY))       return XA_PRIMARY;
113   if (EQ (sym, QSECONDARY))     return XA_SECONDARY;
114   if (EQ (sym, QSTRING))        return XA_STRING;
115   if (EQ (sym, QINTEGER))       return XA_INTEGER;
116   if (EQ (sym, QATOM))          return XA_ATOM;
117   if (EQ (sym, QCLIPBOARD))     return DEVICE_XATOM_CLIPBOARD (d);
118   if (EQ (sym, QTIMESTAMP))     return DEVICE_XATOM_TIMESTAMP (d);
119   if (EQ (sym, QTEXT))          return DEVICE_XATOM_TEXT      (d);
120   if (EQ (sym, QDELETE))        return DEVICE_XATOM_DELETE    (d);
121   if (EQ (sym, QMULTIPLE))      return DEVICE_XATOM_MULTIPLE  (d);
122   if (EQ (sym, QINCR))          return DEVICE_XATOM_INCR      (d);
123   if (EQ (sym, QEMACS_TMP))     return DEVICE_XATOM_EMACS_TMP (d);
124   if (EQ (sym, QTARGETS))       return DEVICE_XATOM_TARGETS   (d);
125   if (EQ (sym, QNULL))          return DEVICE_XATOM_NULL      (d);
126   if (EQ (sym, QATOM_PAIR))     return DEVICE_XATOM_ATOM_PAIR (d);
127   if (EQ (sym, QCOMPOUND_TEXT)) return DEVICE_XATOM_COMPOUND_TEXT (d);
128
129 #ifdef CUT_BUFFER_SUPPORT
130   if (EQ (sym, QCUT_BUFFER0))   return XA_CUT_BUFFER0;
131   if (EQ (sym, QCUT_BUFFER1))   return XA_CUT_BUFFER1;
132   if (EQ (sym, QCUT_BUFFER2))   return XA_CUT_BUFFER2;
133   if (EQ (sym, QCUT_BUFFER3))   return XA_CUT_BUFFER3;
134   if (EQ (sym, QCUT_BUFFER4))   return XA_CUT_BUFFER4;
135   if (EQ (sym, QCUT_BUFFER5))   return XA_CUT_BUFFER5;
136   if (EQ (sym, QCUT_BUFFER6))   return XA_CUT_BUFFER6;
137   if (EQ (sym, QCUT_BUFFER7))   return XA_CUT_BUFFER7;
138 #endif /* CUT_BUFFER_SUPPORT */
139
140   {
141     CONST char *nameext;
142     TO_EXTERNAL_FORMAT (LISP_STRING, Fsymbol_name (sym),
143                         C_STRING_ALLOCA, nameext,
144                         Qctext);
145     return XInternAtom (display, nameext, only_if_exists ? True : False);
146   }
147 }
148
149
150 /* This converts a server Atom to a Lisp symbol, avoiding server roundtrips
151    and calls to intern whenever possible.
152  */
153 static Lisp_Object
154 x_atom_to_symbol (struct device *d, Atom atom)
155 {
156   Display *display = DEVICE_X_DISPLAY (d);
157
158   if (! atom) return Qnil;
159   if (atom == XA_PRIMARY)       return QPRIMARY;
160   if (atom == XA_SECONDARY)     return QSECONDARY;
161   if (atom == XA_STRING)        return QSTRING;
162   if (atom == XA_INTEGER)       return QINTEGER;
163   if (atom == XA_ATOM)          return QATOM;
164   if (atom == DEVICE_XATOM_CLIPBOARD (d)) return QCLIPBOARD;
165   if (atom == DEVICE_XATOM_TIMESTAMP (d)) return QTIMESTAMP;
166   if (atom == DEVICE_XATOM_TEXT      (d)) return QTEXT;
167   if (atom == DEVICE_XATOM_DELETE    (d)) return QDELETE;
168   if (atom == DEVICE_XATOM_MULTIPLE  (d)) return QMULTIPLE;
169   if (atom == DEVICE_XATOM_INCR      (d)) return QINCR;
170   if (atom == DEVICE_XATOM_EMACS_TMP (d)) return QEMACS_TMP;
171   if (atom == DEVICE_XATOM_TARGETS   (d)) return QTARGETS;
172   if (atom == DEVICE_XATOM_NULL      (d)) return QNULL;
173   if (atom == DEVICE_XATOM_ATOM_PAIR (d)) return QATOM_PAIR;
174   if (atom == DEVICE_XATOM_COMPOUND_TEXT (d)) return QCOMPOUND_TEXT;
175
176 #ifdef CUT_BUFFER_SUPPORT
177   if (atom == XA_CUT_BUFFER0)   return QCUT_BUFFER0;
178   if (atom == XA_CUT_BUFFER1)   return QCUT_BUFFER1;
179   if (atom == XA_CUT_BUFFER2)   return QCUT_BUFFER2;
180   if (atom == XA_CUT_BUFFER3)   return QCUT_BUFFER3;
181   if (atom == XA_CUT_BUFFER4)   return QCUT_BUFFER4;
182   if (atom == XA_CUT_BUFFER5)   return QCUT_BUFFER5;
183   if (atom == XA_CUT_BUFFER6)   return QCUT_BUFFER6;
184   if (atom == XA_CUT_BUFFER7)   return QCUT_BUFFER7;
185 #endif
186
187   {
188     char *intstr;
189     char *str = XGetAtomName (display, atom);
190
191     if (! str) return Qnil;
192
193     TO_INTERNAL_FORMAT (C_STRING, str,
194                         C_STRING_ALLOCA, intstr,
195                         Qctext);
196     XFree (str);
197     return intern (intstr);
198   }
199 }
200
201 \f
202 /* Do protocol to assert ourself as a selection owner.
203    Update the Vselection_alist so that we can reply to later requests for
204    our selection.
205  */
206 static Lisp_Object
207 x_own_selection (Lisp_Object selection_name, Lisp_Object selection_value)
208 {
209   struct device *d = decode_x_device (Qnil);
210   Display *display = DEVICE_X_DISPLAY (d);
211   struct frame *sel_frame = selected_frame ();
212   Window selecting_window = XtWindow (FRAME_X_TEXT_WIDGET (sel_frame));
213   Lisp_Object selection_time;
214   /* Use the time of the last-read mouse or keyboard event.
215      For selection purposes, we use this as a sleazy way of knowing what the
216      current time is in server-time.  This assumes that the most recently read
217      mouse or keyboard event has something to do with the assertion of the
218      selection, which is probably true.
219      */
220   Time thyme = DEVICE_X_MOUSE_TIMESTAMP (d);
221   Atom selection_atom;
222
223   CHECK_SYMBOL (selection_name);
224   selection_atom = symbol_to_x_atom (d, selection_name, 0);
225
226   XSetSelectionOwner (display, selection_atom, selecting_window, thyme);
227
228   /* We do NOT use time_to_lisp() here any more, like we used to.
229      That assumed equivalence of time_t and Time, which is not
230      necessarily the case (e.g. under OSF on the Alphas, where
231      Time is a 64-bit quantity and time_t is a 32-bit quantity).
232      
233      Opaque pointers are the clean way to go here.
234   */
235   selection_time = make_opaque (&thyme, sizeof (thyme));
236
237 #ifdef MOTIF_CLIPBOARDS
238   hack_motif_clipboard_selection (selection_atom, selection_value,
239                                   thyme, display, selecting_window);
240 #endif
241   return selection_time;
242 }
243
244 #ifdef MOTIF_CLIPBOARDS /* Bend over baby.  Take it and like it. */
245
246 # ifdef MOTIF_INCREMENTAL_CLIPBOARDS_WORK
247 static void motif_clipboard_cb ();
248 # endif
249
250 static void
251 hack_motif_clipboard_selection (Atom selection_atom,
252                                 Lisp_Object selection_value,
253                                 Time thyme,
254                                 Display *display,
255                                                 Window selecting_window)
256      /*                         Bool owned_p)*/
257 {
258   struct device *d = get_device_from_display (display);
259   /* Those Motif wankers can't be bothered to follow the ICCCM, and do
260      their own non-Xlib non-Xt clipboard processing.  So we have to do
261      this so that linked-in Motif widgets don't get themselves wedged.
262    */
263   if (selection_atom == DEVICE_XATOM_CLIPBOARD (d)
264       && STRINGP (selection_value)
265
266       /* If we already own the clipboard, don't own it again in the Motif
267          way.  This might lose in some subtle way, since the timestamp won't
268          be current, but owning the selection on the Motif way does a
269          SHITLOAD of X protocol, and it makes killing text be incredibly
270          slow when using an X terminal.  ARRRRGGGHHH!!!!
271        */
272       /* No, this is no good, because then Motif text fields don't bother
273          to look up the new value, and you can't Copy from a buffer, Paste
274          into a text field, then Copy something else from the buffer and
275          paste it into the text field -- it pastes the first thing again. */
276 /*      && !owned_p */
277       )
278     {
279 #ifdef MOTIF_INCREMENTAL_CLIPBOARDS_WORK
280       Widget widget = FRAME_X_TEXT_WIDGET (selected_frame());
281 #endif
282       long itemid;
283 #if XmVersion >= 1002
284       long dataid;
285 #else
286       int dataid;       /* 1.2 wants long, but 1.1.5 wants int... */
287 #endif
288       XmString fmh;
289       String encoding = "STRING";
290       CONST Extbyte *data  = XSTRING_DATA (selection_value);
291       Extcount bytes = XSTRING_LENGTH (selection_value);
292
293 #ifdef MULE
294       {
295         enum { ASCII, LATIN_1, WORLD } chartypes = ASCII;
296         CONST Bufbyte *ptr = data, *end = ptr + bytes;
297         /* Optimize for the common ASCII case */
298         while (ptr <= end)
299           {
300             if (BYTE_ASCII_P (*ptr))
301               {
302                 ptr++;
303                 continue;
304               }
305
306             if ((*ptr) == LEADING_BYTE_LATIN_ISO8859_1 ||
307                 (*ptr) == LEADING_BYTE_CONTROL_1)
308               {
309                 chartypes = LATIN_1;
310                 ptr += 2;
311                 continue;
312               }
313
314             chartypes = WORLD;
315             break;
316           }
317
318         if (chartypes == LATIN_1)
319           TO_EXTERNAL_FORMAT (LISP_STRING, selection_value,
320                               ALLOCA, (data, bytes),
321                               Qbinary);
322         else if (chartypes == WORLD)
323           {
324             TO_EXTERNAL_FORMAT (LISP_STRING, selection_value,
325                                 ALLOCA, (data, bytes),
326                                 Qctext);
327             encoding = "COMPOUND_TEXT";
328           }
329       }
330 #endif /* MULE */
331
332       fmh = XmStringCreateLtoR ("Clipboard", XmSTRING_DEFAULT_CHARSET);
333       while (ClipboardSuccess !=
334              XmClipboardStartCopy (display, selecting_window, fmh, thyme,
335 #ifdef MOTIF_INCREMENTAL_CLIPBOARDS_WORK
336                                    widget, motif_clipboard_cb,
337 #else
338                                    0, NULL,
339 #endif
340                                    &itemid))
341         ;
342       XmStringFree (fmh);
343       while (ClipboardSuccess !=
344              XmClipboardCopy (display, selecting_window, itemid, encoding,
345 #ifdef MOTIF_INCREMENTAL_CLIPBOARDS_WORK
346                               /* O'Reilly examples say size can be 0,
347                                  but this clearly is not the case. */
348                               0, bytes, (int) selecting_window, /* private id */
349 #else /* !MOTIF_INCREMENTAL_CLIPBOARDS_WORK */
350                               (XtPointer) data, bytes, 0,
351 #endif /* !MOTIF_INCREMENTAL_CLIPBOARDS_WORK */
352                               &dataid))
353         ;
354       while (ClipboardSuccess !=
355              XmClipboardEndCopy (display, selecting_window, itemid))
356         ;
357     }
358 }
359
360 # ifdef MOTIF_INCREMENTAL_CLIPBOARDS_WORK
361 /* I tried to treat the clipboard like a real selection, and not send
362    the data until it was requested, but it looks like that just doesn't
363    work at all unless the selection owner and requestor are in different
364    processes.  From reading the Motif source, it looks like they never
365    even considered having two widgets in the same application transfer
366    data between each other using "by-name" clipboard values.  What a
367    bunch of fuckups.
368  */
369 static void
370 motif_clipboard_cb (Widget widget, int *data_id, int *private_id, int *reason)
371 {
372   switch (*reason)
373     {
374     case XmCR_CLIPBOARD_DATA_REQUEST:
375       {
376         Display *dpy = XtDisplay (widget);
377         Window window = (Window) *private_id;
378         Lisp_Object selection = assq_no_quit (QCLIPBOARD, Vselection_alist);
379         if (NILP (selection)) abort ();
380         selection = XCDR (selection);
381         if (!STRINGP (selection)) abort ();
382         XmClipboardCopyByName (dpy, window, *data_id,
383                                (char *) XSTRING_DATA (selection),
384                                XSTRING_LENGTH (selection) + 1,
385                                0);
386       }
387       break;
388     case XmCR_CLIPBOARD_DATA_DELETE:
389     default:
390       /* don't need to free anything */
391       break;
392     }
393 }
394 # endif /* MOTIF_INCREMENTAL_CLIPBOARDS_WORK */
395 #endif /* MOTIF_CLIPBOARDS */
396
397
398
399
400 /* Send a SelectionNotify event to the requestor with property=None, meaning
401    we were unable to do what they wanted.
402  */
403 static void
404 x_decline_selection_request (XSelectionRequestEvent *event)
405 {
406   XSelectionEvent reply;
407   reply.type      = SelectionNotify;
408   reply.display   = event->display;
409   reply.requestor = event->requestor;
410   reply.selection = event->selection;
411   reply.time      = event->time;
412   reply.target    = event->target;
413   reply.property  = None;
414
415   XSendEvent (reply.display, reply.requestor, False, 0L, (XEvent *) &reply);
416   XFlush (reply.display);
417 }
418
419
420 /* Used as an unwind-protect clause so that, if a selection-converter signals
421    an error, we tell the requestor that we were unable to do what they wanted
422    before we throw to top-level or go into the debugger or whatever.
423  */
424 static Lisp_Object
425 x_selection_request_lisp_error (Lisp_Object closure)
426 {
427   XSelectionRequestEvent *event = (XSelectionRequestEvent *)
428     get_opaque_ptr (closure);
429
430   free_opaque_ptr (closure);
431   if (event->type == 0) /* we set this to mean "completed normally" */
432     return Qnil;
433   x_decline_selection_request (event);
434   return Qnil;
435 }
436
437
438 /* Convert our selection to the requested type, and put that data where the
439    requestor wants it.  Then tell them whether we've succeeded.
440  */
441 static void
442 x_reply_selection_request (XSelectionRequestEvent *event, int format,
443                            unsigned char *data, int size, Atom type)
444 {
445   /* This function can GC */
446   XSelectionEvent reply;
447   Display *display = event->display;
448   struct device *d = get_device_from_display (display);
449   Window window = event->requestor;
450   int bytes_remaining;
451   int format_bytes = format/8;
452   int max_bytes = SELECTION_QUANTUM (display);
453   if (max_bytes > MAX_SELECTION_QUANTUM) max_bytes = MAX_SELECTION_QUANTUM;
454
455   reply.type      = SelectionNotify;
456   reply.display   = display;
457   reply.requestor = window;
458   reply.selection = event->selection;
459   reply.time      = event->time;
460   reply.target    = event->target;
461   reply.property  = (event->property == None ? event->target : event->property);
462
463   /* #### XChangeProperty can generate BadAlloc, and we must handle it! */
464
465   /* Store the data on the requested property.
466      If the selection is large, only store the first N bytes of it.
467    */
468   bytes_remaining = size * format_bytes;
469   if (bytes_remaining <= max_bytes)
470     {
471       /* Send all the data at once, with minimal handshaking. */
472 #if 0
473       stderr_out ("\nStoring all %d\n", bytes_remaining);
474 #endif
475       XChangeProperty (display, window, reply.property, type, format,
476                        PropModeReplace, data, size);
477       /* At this point, the selection was successfully stored; ack it. */
478       XSendEvent (display, window, False, 0L, (XEvent *) &reply);
479       XFlush (display);
480     }
481   else
482     {
483       /* Send an INCR selection. */
484       int prop_id;
485
486       if (x_window_to_frame (d, window)) /* #### debug */
487         error ("attempt to transfer an INCR to ourself!");
488 #if 0
489       stderr_out ("\nINCR %d\n", bytes_remaining);
490 #endif
491       prop_id = expect_property_change (display, window, reply.property,
492                                         PropertyDelete);
493
494       XChangeProperty (display, window, reply.property, DEVICE_XATOM_INCR (d),
495                        32, PropModeReplace, (unsigned char *)
496                        &bytes_remaining, 1);
497       XSelectInput (display, window, PropertyChangeMask);
498       /* Tell 'em the INCR data is there... */
499       XSendEvent (display, window, False, 0L, (XEvent *) &reply);
500       XFlush (display);
501
502       /* First, wait for the requestor to ack by deleting the property.
503          This can run random lisp code (process handlers) or signal.
504        */
505       wait_for_property_change (prop_id);
506
507       while (bytes_remaining)
508         {
509           int i = ((bytes_remaining < max_bytes)
510                    ? bytes_remaining
511                    : max_bytes);
512           prop_id = expect_property_change (display, window, reply.property,
513                                             PropertyDelete);
514 #if 0
515           stderr_out ("  INCR adding %d\n", i);
516 #endif
517           /* Append the next chunk of data to the property. */
518           XChangeProperty (display, window, reply.property, type, format,
519                            PropModeAppend, data, i / format_bytes);
520           bytes_remaining -= i;
521           data += i;
522
523           /* Now wait for the requestor to ack this chunk by deleting the
524              property.   This can run random lisp code or signal.
525            */
526           wait_for_property_change (prop_id);
527         }
528       /* Now write a zero-length chunk to the property to tell the requestor
529          that we're done. */
530 #if 0
531       stderr_out ("  INCR done\n");
532 #endif
533       if (! waiting_for_other_props_on_window (display, window))
534         XSelectInput (display, window, 0L);
535
536       XChangeProperty (display, window, reply.property, type, format,
537                        PropModeReplace, data, 0);
538     }
539 }
540
541
542
543 /* Called from the event-loop in response to a SelectionRequest event.
544  */
545 void
546 x_handle_selection_request (XSelectionRequestEvent *event)
547 {
548   /* This function can GC */
549   struct gcpro gcpro1, gcpro2, gcpro3;
550   Lisp_Object local_selection_data = Qnil;
551   Lisp_Object selection_symbol;
552   Lisp_Object target_symbol = Qnil;
553   Lisp_Object converted_selection = Qnil;
554   Time local_selection_time;
555   Lisp_Object successful_p = Qnil;
556   int count;
557   struct device *d = get_device_from_display (event->display);
558
559   GCPRO3 (local_selection_data, converted_selection, target_symbol);
560
561   selection_symbol = x_atom_to_symbol (d, event->selection);
562
563   local_selection_data = assq_no_quit (selection_symbol, Vselection_alist);
564
565 #if 0
566   /* This list isn't user-visible, so it can't "go bad." */
567   assert (CONSP (local_selection_data));
568   assert (CONSP (XCDR (local_selection_data)));
569   assert (CONSP (XCDR (XCDR (local_selection_data))));
570   assert (NILP  (XCDR (XCDR (XCDR (local_selection_data)))));
571   assert (CONSP (XCAR (XCDR (XCDR (local_selection_data)))));
572   assert (INTP  (XCAR (XCAR (XCDR (XCDR (local_selection_data))))));
573   assert (INTP  (XCDR (XCAR (XCDR (XCDR (local_selection_data))))));
574 #endif
575
576   if (NILP (local_selection_data))
577     {
578       /* Someone asked for the selection, but we don't have it any more. */
579       x_decline_selection_request (event);
580       goto DONE_LABEL;
581     }
582
583   local_selection_time =
584     * (Time *) XOPAQUE_DATA (XCAR (XCDR (XCDR (local_selection_data))));
585
586   if (event->time != CurrentTime &&
587       local_selection_time > event->time)
588     {
589       /* Someone asked for the selection, and we have one, but not the one
590          they're looking for. */
591       x_decline_selection_request (event);
592       goto DONE_LABEL;
593     }
594
595   count = specpdl_depth ();
596   record_unwind_protect (x_selection_request_lisp_error,
597                          make_opaque_ptr (event));
598   target_symbol = x_atom_to_symbol (d, event->target);
599
600 #if 0 /* #### MULTIPLE doesn't work yet */
601   if (EQ (target_symbol, QMULTIPLE))
602     target_symbol = fetch_multiple_target (event);
603 #endif
604
605   /* Convert lisp objects back into binary data */
606
607   converted_selection =
608     get_local_selection (selection_symbol, target_symbol);
609
610   if (! NILP (converted_selection))
611     {
612       unsigned char *data;
613       unsigned int size;
614       int format;
615       Atom type;
616       lisp_data_to_selection_data (d, converted_selection,
617                                    &data, &type, &size, &format);
618
619       x_reply_selection_request (event, format, data, size, type);
620       successful_p = Qt;
621       /* Tell x_selection_request_lisp_error() it's cool. */      event->type = 0;
622       xfree (data);
623     }
624   unbind_to (count, Qnil);
625
626  DONE_LABEL:
627
628   UNGCPRO;
629
630   /* Let random lisp code notice that the selection has been asked for. */
631   {
632     Lisp_Object rest;
633     Lisp_Object val = Vx_sent_selection_hooks;
634     if (!UNBOUNDP (val) && !NILP (val))
635       {
636         if (CONSP (val) && !EQ (XCAR (val), Qlambda))
637           for (rest = val; !NILP (rest); rest = Fcdr (rest))
638             call3 (Fcar(rest), selection_symbol, target_symbol,
639                    successful_p);
640         else
641           call3 (val, selection_symbol, target_symbol,
642                  successful_p);
643       }
644   }
645 }
646
647
648 /* Called from the event-loop in response to a SelectionClear event.
649  */
650 void
651 x_handle_selection_clear (XSelectionClearEvent *event)
652 {
653   Display *display = event->display;
654   struct device *d = get_device_from_display (display);
655   Atom selection = event->selection;
656   Time changed_owner_time = event->time;
657
658   Lisp_Object selection_symbol, local_selection_data;
659   Time local_selection_time;
660
661   selection_symbol = x_atom_to_symbol (d, selection);
662
663   local_selection_data = assq_no_quit (selection_symbol, Vselection_alist);
664
665   /* Well, we already believe that we don't own it, so that's just fine. */
666   if (NILP (local_selection_data)) return;
667
668   local_selection_time =
669     * (Time *) XOPAQUE_DATA (XCAR (XCDR (XCDR (local_selection_data))));
670
671   /* This SelectionClear is for a selection that we no longer own, so we can
672      disregard it.  (That is, we have reasserted the selection since this
673      request was generated.)
674    */
675   if (changed_owner_time != CurrentTime &&
676       local_selection_time > changed_owner_time)
677     return;
678   
679   handle_selection_clear (selection_symbol);
680 }
681
682 \f
683 /* This stuff is so that INCR selections are reentrant (that is, so we can
684    be servicing multiple INCR selection requests simultaneously).  I haven't
685    actually tested that yet.
686  */
687
688 static int prop_location_tick;
689
690 static struct prop_location {
691   int tick;
692   Display *display;
693   Window window;
694   Atom property;
695   int desired_state;
696   struct prop_location *next;
697 } *for_whom_the_bell_tolls;
698
699
700 static int
701 property_deleted_p (void *tick)
702 {
703   struct prop_location *rest = for_whom_the_bell_tolls;
704   while (rest)
705     if (rest->tick == (long) tick)
706       return 0;
707     else
708       rest = rest->next;
709   return 1;
710 }
711
712 static int
713 waiting_for_other_props_on_window (Display *display, Window window)
714 {
715   struct prop_location *rest = for_whom_the_bell_tolls;
716   while (rest)
717     if (rest->display == display && rest->window == window)
718       return 1;
719     else
720       rest = rest->next;
721   return 0;
722 }
723
724
725 static int
726 expect_property_change (Display *display, Window window,
727                         Atom property, int state)
728 {
729   struct prop_location *pl = xnew (struct prop_location);
730   pl->tick = ++prop_location_tick;
731   pl->display = display;
732   pl->window = window;
733   pl->property = property;
734   pl->desired_state = state;
735   pl->next = for_whom_the_bell_tolls;
736   for_whom_the_bell_tolls = pl;
737   return pl->tick;
738 }
739
740 static void
741 unexpect_property_change (int tick)
742 {
743   struct prop_location *prev = 0, *rest = for_whom_the_bell_tolls;
744   while (rest)
745     {
746       if (rest->tick == tick)
747         {
748           if (prev)
749             prev->next = rest->next;
750           else
751             for_whom_the_bell_tolls = rest->next;
752           xfree (rest);
753           return;
754         }
755       prev = rest;
756       rest = rest->next;
757     }
758 }
759
760 static void
761 wait_for_property_change (long tick)
762 {
763   /* This function can GC */
764   wait_delaying_user_input (property_deleted_p, (void *) tick);
765 }
766
767
768 /* Called from the event-loop in response to a PropertyNotify event.
769  */
770 void
771 x_handle_property_notify (XPropertyEvent *event)
772 {
773   struct prop_location *prev = 0, *rest = for_whom_the_bell_tolls;
774   while (rest)
775     {
776       if (rest->property == event->atom &&
777           rest->window == event->window &&
778           rest->display == event->display &&
779           rest->desired_state == event->state)
780         {
781 #if 0
782           stderr_out ("Saw expected prop-%s on %s\n",
783                    (event->state == PropertyDelete ? "delete" : "change"),
784                       (char *) string_data (XSYMBOL (x_atom_to_symbol (get_device_from_display (event->display), event->atom))->name);
785 #endif
786           if (prev)
787             prev->next = rest->next;
788           else
789             for_whom_the_bell_tolls = rest->next;
790           xfree (rest);
791           return;
792         }
793       prev = rest;
794       rest = rest->next;
795     }
796 #if 0
797   stderr_out ("Saw UNexpected prop-%s on %s\n",
798            (event->state == PropertyDelete ? "delete" : "change"),
799            (char *) string_data (XSYMBOL (x_atom_to_symbol (get_device_from_display (event->display), event->atom))->name));
800 #endif
801 }
802
803
804 \f
805 #if 0 /* #### MULTIPLE doesn't work yet */
806
807 static Lisp_Object
808 fetch_multiple_target (XSelectionRequestEvent *event)
809 {
810   /* This function can GC */
811   Display *display = event->display;
812   Window window = event->requestor;
813   Atom target = event->target;
814   Atom selection_atom = event->selection;
815   int result;
816
817   return
818     Fcons (QMULTIPLE,
819            x_get_window_property_as_lisp_data (display, window, target,
820                                                QMULTIPLE,
821                                                selection_atom));
822 }
823
824 static Lisp_Object
825 copy_multiple_data (Lisp_Object obj)
826 {
827   Lisp_Object vec;
828   int i;
829   int len;
830   if (CONSP (obj))
831     return Fcons (XCAR (obj), copy_multiple_data (XCDR (obj)));
832
833   CHECK_VECTOR (obj);
834   len = XVECTOR_LENGTH (obj);
835   vec = make_vector (len, Qnil);
836   for (i = 0; i < len; i++)
837     {
838       Lisp_Object vec2 = XVECTOR_DATA (obj) [i];
839       CHECK_VECTOR (vec2);
840       if (XVECTOR_LENGTH (vec2) != 2)
841         signal_error (Qerror, list2 (build_string
842                                      ("vectors must be of length 2"),
843                                      vec2));
844       XVECTOR_DATA (vec) [i] = make_vector (2, Qnil);
845       XVECTOR_DATA (XVECTOR_DATA (vec) [i]) [0] = XVECTOR_DATA (vec2) [0];
846       XVECTOR_DATA (XVECTOR_DATA (vec) [i]) [1] = XVECTOR_DATA (vec2) [1];
847     }
848   return vec;
849 }
850
851 #endif /* 0 */
852
853 \f
854 static Window reading_selection_reply;
855 static Atom reading_which_selection;
856 static int selection_reply_timed_out;
857
858 static int
859 selection_reply_done (void *ignore)
860 {
861   return !reading_selection_reply;
862 }
863
864 static Lisp_Object Qx_selection_reply_timeout_internal;
865
866 DEFUN ("x-selection-reply-timeout-internal", Fx_selection_reply_timeout_internal,
867        1, 1, 0, /*
868 */
869        (arg))
870 {
871   selection_reply_timed_out = 1;
872   reading_selection_reply = 0;
873   return Qnil;
874 }
875
876
877 /* Do protocol to read selection-data from the server.
878    Converts this to lisp data and returns it.
879  */
880 static Lisp_Object
881 x_get_foreign_selection (Lisp_Object selection_symbol, Lisp_Object target_type)
882 {
883   /* This function can GC */
884   struct device *d = decode_x_device (Qnil);
885   Display *display = DEVICE_X_DISPLAY (d);
886   struct frame *sel_frame = selected_frame ();
887   Window requestor_window = XtWindow (FRAME_X_TEXT_WIDGET (sel_frame));
888   Time requestor_time = DEVICE_X_MOUSE_TIMESTAMP (d);
889   Atom target_property = DEVICE_XATOM_EMACS_TMP (d);
890   Atom selection_atom = symbol_to_x_atom (d, selection_symbol, 0);
891   int speccount;
892   Atom type_atom = symbol_to_x_atom (d, (CONSP (target_type) ?
893                                          XCAR (target_type) : target_type), 0);
894
895   XConvertSelection (display, selection_atom, type_atom, target_property,
896                      requestor_window, requestor_time);
897
898   /* Block until the reply has been read. */
899   reading_selection_reply = requestor_window;
900   reading_which_selection = selection_atom;
901   selection_reply_timed_out = 0;
902
903   speccount = specpdl_depth ();
904
905   /* add a timeout handler */
906   if (x_selection_timeout > 0)
907     {
908       Lisp_Object id = Fadd_timeout (make_int (x_selection_timeout),
909                                      Qx_selection_reply_timeout_internal,
910                                      Qnil, Qnil);
911       record_unwind_protect (Fdisable_timeout, id);
912     }
913
914   /* This is ^Gable */
915   wait_delaying_user_input (selection_reply_done, 0);
916
917   if (selection_reply_timed_out)
918     error ("timed out waiting for reply from selection owner");
919
920   unbind_to (speccount, Qnil);
921
922   /* otherwise, the selection is waiting for us on the requested property. */
923   return
924     x_get_window_property_as_lisp_data (display, requestor_window,
925                                         target_property, target_type,
926                                         selection_atom);
927 }
928
929
930 static void
931 x_get_window_property (Display *display, Window window, Atom property,
932                        unsigned char **data_ret, int *bytes_ret,
933                        Atom *actual_type_ret, int *actual_format_ret,
934                        unsigned long *actual_size_ret, int delete_p)
935 {
936   int total_size;
937   unsigned long bytes_remaining;
938   int offset = 0;
939   unsigned char *tmp_data = 0;
940   int result;
941   int buffer_size = SELECTION_QUANTUM (display);
942   if (buffer_size > MAX_SELECTION_QUANTUM) buffer_size = MAX_SELECTION_QUANTUM;
943
944   /* First probe the thing to find out how big it is. */
945   result = XGetWindowProperty (display, window, property,
946                                0, 0, False, AnyPropertyType,
947                                actual_type_ret, actual_format_ret,
948                                actual_size_ret,
949                                &bytes_remaining, &tmp_data);
950   if (result != Success)
951     {
952       *data_ret = 0;
953       *bytes_ret = 0;
954       return;
955     }
956   XFree ((char *) tmp_data);
957
958   if (*actual_type_ret == None || *actual_format_ret == 0)
959     {
960       if (delete_p) XDeleteProperty (display, window, property);
961       *data_ret = 0;
962       *bytes_ret = 0;
963       return;
964     }
965
966   total_size = bytes_remaining + 1;
967   *data_ret = (unsigned char *) xmalloc (total_size);
968
969   /* Now read, until we've gotten it all. */
970   while (bytes_remaining)
971     {
972 #if 0
973       int last = bytes_remaining;
974 #endif
975       result =
976         XGetWindowProperty (display, window, property,
977                             offset/4, buffer_size/4,
978                             (delete_p ? True : False),
979                             AnyPropertyType,
980                             actual_type_ret, actual_format_ret,
981                             actual_size_ret, &bytes_remaining, &tmp_data);
982 #if 0
983       stderr_out ("<< read %d\n", last-bytes_remaining);
984 #endif
985       /* If this doesn't return Success at this point, it means that
986          some clod deleted the selection while we were in the midst of
987          reading it.  Deal with that, I guess....
988        */
989       if (result != Success) break;
990       *actual_size_ret *= *actual_format_ret / 8;
991       memcpy ((*data_ret) + offset, tmp_data, *actual_size_ret);
992       offset += *actual_size_ret;
993       XFree ((char *) tmp_data);
994     }
995   *bytes_ret = offset;
996 }
997
998
999 static void
1000 receive_incremental_selection (Display *display, Window window, Atom property,
1001                                /* this one is for error messages only */
1002                                Lisp_Object target_type,
1003                                unsigned int min_size_bytes,
1004                                unsigned char **data_ret, int *size_bytes_ret,
1005                                Atom *type_ret, int *format_ret,
1006                                unsigned long *size_ret)
1007 {
1008   /* This function can GC */
1009   int offset = 0;
1010   int prop_id;
1011   *size_bytes_ret = min_size_bytes;
1012   *data_ret = (unsigned char *) xmalloc (*size_bytes_ret);
1013 #if 0
1014   stderr_out ("\nread INCR %d\n", min_size_bytes);
1015 #endif
1016   /* At this point, we have read an INCR property, and deleted it (which
1017      is how we ack its receipt: the sending window will be selecting
1018      PropertyNotify events on our window to notice this).
1019
1020      Now, we must loop, waiting for the sending window to put a value on
1021      that property, then reading the property, then deleting it to ack.
1022      We are done when the sender places a property of length 0.
1023    */
1024   prop_id = expect_property_change (display, window, property,
1025                                     PropertyNewValue);
1026   while (1)
1027     {
1028       unsigned char *tmp_data;
1029       int tmp_size_bytes;
1030       wait_for_property_change (prop_id);
1031       /* expect it again immediately, because x_get_window_property may
1032          .. no it won't, I don't get it.
1033          .. Ok, I get it now, the Xt code that implements INCR is broken.
1034        */
1035       prop_id = expect_property_change (display, window, property,
1036                                         PropertyNewValue);
1037       x_get_window_property (display, window, property,
1038                              &tmp_data, &tmp_size_bytes,
1039                              type_ret, format_ret, size_ret, 1);
1040
1041       if (tmp_size_bytes == 0) /* we're done */
1042         {
1043 #if 0
1044           stderr_out ("  read INCR done\n");
1045 #endif
1046           unexpect_property_change (prop_id);
1047           if (tmp_data) xfree (tmp_data);
1048           break;
1049         }
1050 #if 0
1051       stderr_out ("  read INCR %d\n", tmp_size_bytes);
1052 #endif
1053       if (*size_bytes_ret < offset + tmp_size_bytes)
1054         {
1055 #if 0
1056           stderr_out ("  read INCR realloc %d -> %d\n",
1057                    *size_bytes_ret, offset + tmp_size_bytes);
1058 #endif
1059           *size_bytes_ret = offset + tmp_size_bytes;
1060           *data_ret = (unsigned char *) xrealloc (*data_ret, *size_bytes_ret);
1061         }
1062       memcpy ((*data_ret) + offset, tmp_data, tmp_size_bytes);
1063       offset += tmp_size_bytes;
1064       xfree (tmp_data);
1065     }
1066 }
1067
1068
1069 static Lisp_Object
1070 x_get_window_property_as_lisp_data (Display *display,
1071                                     Window window,
1072                                     Atom property,
1073                                     /* next two for error messages only */
1074                                     Lisp_Object target_type,
1075                                     Atom selection_atom)
1076 {
1077   /* This function can GC */
1078   Atom actual_type;
1079   int actual_format;
1080   unsigned long actual_size;
1081   unsigned char *data = NULL;
1082   int bytes = 0;
1083   Lisp_Object val;
1084   struct device *d = get_device_from_display (display);
1085
1086   x_get_window_property (display, window, property, &data, &bytes,
1087                          &actual_type, &actual_format, &actual_size, 1);
1088   if (! data)
1089     {
1090       if (XGetSelectionOwner (display, selection_atom))
1091         /* there is a selection owner */
1092         signal_error
1093           (Qselection_conversion_error,
1094            Fcons (build_string ("selection owner couldn't convert"),
1095                   Fcons (x_atom_to_symbol (d, selection_atom),
1096                          actual_type ?
1097                          list2 (target_type, x_atom_to_symbol (d, actual_type)) :
1098                          list1 (target_type))));
1099       else
1100         signal_error (Qerror,
1101                       list2 (build_string ("no selection"),
1102                              x_atom_to_symbol (d, selection_atom)));
1103     }
1104
1105   if (actual_type == DEVICE_XATOM_INCR (d))
1106     {
1107       /* Ok, that data wasn't *the* data, it was just the beginning. */
1108
1109       unsigned int min_size_bytes = * ((unsigned int *) data);
1110       xfree (data);
1111       receive_incremental_selection (display, window, property, target_type,
1112                                      min_size_bytes, &data, &bytes,
1113                                      &actual_type, &actual_format,
1114                                      &actual_size);
1115     }
1116
1117   /* It's been read.  Now convert it to a lisp object in some semi-rational
1118      manner. */
1119   val = selection_data_to_lisp_data (d, data, bytes,
1120                                      actual_type, actual_format);
1121
1122   xfree (data);
1123   return val;
1124 }
1125 \f
1126 /* These functions convert from the selection data read from the server into
1127    something that we can use from elisp, and vice versa.
1128
1129         Type:   Format: Size:           Elisp Type:
1130         -----   ------- -----           -----------
1131         *       8       *               String
1132         ATOM    32      1               Symbol
1133         ATOM    32      > 1             Vector of Symbols
1134         *       16      1               Integer
1135         *       16      > 1             Vector of Integers
1136         *       32      1               if <=16 bits: Integer
1137                                         if > 16 bits: Cons of top16, bot16
1138         *       32      > 1             Vector of the above
1139
1140    When converting a Lisp number to C, it is assumed to be of format 16 if
1141    it is an integer, and of format 32 if it is a cons of two integers.
1142
1143    When converting a vector of numbers from Elisp to C, it is assumed to be
1144    of format 16 if every element in the vector is an integer, and is assumed
1145    to be of format 32 if any element is a cons of two integers.
1146
1147    When converting an object to C, it may be of the form (SYMBOL . <data>)
1148    where SYMBOL is what we should claim that the type is.  Format and
1149    representation are as above.
1150
1151    NOTE: Under Mule, when someone shoves us a string without a type, we
1152    set the type to 'COMPOUND_TEXT and automatically convert to Compound
1153    Text.  If the string has a type, we assume that the user wants the
1154    data sent as-is so we just do "binary" conversion.
1155  */
1156
1157
1158 static Lisp_Object
1159 selection_data_to_lisp_data (struct device *d,
1160                              unsigned char *data,
1161                              size_t size,
1162                              Atom type,
1163                              int format)
1164 {
1165   if (type == DEVICE_XATOM_NULL (d))
1166     return QNULL;
1167
1168   /* Convert any 8-bit data to a string, for compactness. */
1169   else if (format == 8)
1170     return make_ext_string (data, size,
1171                             type == DEVICE_XATOM_TEXT (d) ||
1172                             type == DEVICE_XATOM_COMPOUND_TEXT (d)
1173                             ? Qctext : Qbinary);
1174
1175   /* Convert a single atom to a Lisp Symbol.
1176      Convert a set of atoms to a vector of symbols. */
1177   else if (type == XA_ATOM)
1178     {
1179       if (size == sizeof (Atom))
1180         return x_atom_to_symbol (d, *((Atom *) data));
1181       else
1182         {
1183           int i;
1184           int len = size / sizeof (Atom);
1185           Lisp_Object v = Fmake_vector (make_int (len), Qzero);
1186           for (i = 0; i < len; i++)
1187             Faset (v, make_int (i), x_atom_to_symbol (d, ((Atom *) data) [i]));
1188           return v;
1189         }
1190     }
1191
1192   /* Convert a single 16 or small 32 bit number to a Lisp Int.
1193      If the number is > 16 bits, convert it to a cons of integers,
1194      16 bits in each half.
1195    */
1196   else if (format == 32 && size == sizeof (long))
1197     return word_to_lisp (((unsigned long *) data) [0]);
1198   else if (format == 16 && size == sizeof (short))
1199     return make_int ((int) (((unsigned short *) data) [0]));
1200
1201   /* Convert any other kind of data to a vector of numbers, represented
1202      as above (as an integer, or a cons of two 16 bit integers).
1203
1204      #### Perhaps we should return the actual type to lisp as well.
1205
1206         (x-get-selection-internal 'PRIMARY 'LINE_NUMBER)
1207         ==> [4 4]
1208
1209      and perhaps it should be
1210
1211         (x-get-selection-internal 'PRIMARY 'LINE_NUMBER)
1212         ==> (SPAN . [4 4])
1213
1214      Right now the fact that the return type was SPAN is discarded before
1215      lisp code gets to see it.
1216    */
1217   else if (format == 16)
1218     {
1219       int i;
1220       Lisp_Object v = make_vector (size / 4, Qzero);
1221       for (i = 0; i < (int) size / 4; i++)
1222         {
1223           int j = (int) ((unsigned short *) data) [i];
1224           Faset (v, make_int (i), make_int (j));
1225         }
1226       return v;
1227     }
1228   else
1229     {
1230       int i;
1231       Lisp_Object v = make_vector (size / 4, Qzero);
1232       for (i = 0; i < (int) size / 4; i++)
1233         {
1234           unsigned long j = ((unsigned long *) data) [i];
1235           Faset (v, make_int (i), word_to_lisp (j));
1236         }
1237       return v;
1238     }
1239 }
1240
1241
1242 static void
1243 lisp_data_to_selection_data (struct device *d,
1244                              Lisp_Object obj,
1245                              unsigned char **data_ret,
1246                              Atom *type_ret,
1247                              unsigned int *size_ret,
1248                              int *format_ret)
1249 {
1250   Lisp_Object type = Qnil;
1251
1252   if (CONSP (obj) && SYMBOLP (XCAR (obj)))
1253     {
1254       type = XCAR (obj);
1255       obj = XCDR (obj);
1256       if (CONSP (obj) && NILP (XCDR (obj)))
1257         obj = XCAR (obj);
1258     }
1259
1260   if (EQ (obj, QNULL) || (EQ (type, QNULL)))
1261     {                           /* This is not the same as declining */
1262       *format_ret = 32;
1263       *size_ret = 0;
1264       *data_ret = 0;
1265       type = QNULL;
1266     }
1267   else if (STRINGP (obj))
1268     {
1269       CONST Extbyte *extval;
1270       Extcount extvallen;
1271
1272       TO_EXTERNAL_FORMAT (LISP_STRING, obj,
1273                           ALLOCA, (extval, extvallen),
1274                           (NILP (type) ? Qctext : Qbinary));
1275       *format_ret = 8;
1276       *size_ret = extvallen;
1277       *data_ret = (unsigned char *) xmalloc (*size_ret);
1278       memcpy (*data_ret, extval, *size_ret);
1279 #ifdef MULE
1280       if (NILP (type)) type = QCOMPOUND_TEXT;
1281 #else
1282       if (NILP (type)) type = QSTRING;
1283 #endif
1284     }
1285   else if (CHARP (obj))
1286     {
1287       Bufbyte buf[MAX_EMCHAR_LEN];
1288       Bytecount len;
1289       CONST Extbyte *extval;
1290       Extcount extvallen;
1291
1292       *format_ret = 8;
1293       len = set_charptr_emchar (buf, XCHAR (obj));
1294       TO_EXTERNAL_FORMAT (DATA, (buf, len),
1295                           ALLOCA, (extval, extvallen),
1296                           Qctext);
1297       *size_ret = extvallen;
1298       *data_ret = (unsigned char *) xmalloc (*size_ret);
1299       memcpy (*data_ret, extval, *size_ret);
1300 #ifdef MULE
1301       if (NILP (type)) type = QCOMPOUND_TEXT;
1302 #else
1303       if (NILP (type)) type = QSTRING;
1304 #endif
1305     }
1306   else if (SYMBOLP (obj))
1307     {
1308       *format_ret = 32;
1309       *size_ret = 1;
1310       *data_ret = (unsigned char *) xmalloc (sizeof (Atom) + 1);
1311       (*data_ret) [sizeof (Atom)] = 0;
1312       (*(Atom **) data_ret) [0] = symbol_to_x_atom (d, obj, 0);
1313       if (NILP (type)) type = QATOM;
1314     }
1315   else if (INTP (obj) &&
1316            XINT (obj) <= 0x7FFF &&
1317            XINT (obj) >= -0x8000)
1318     {
1319       *format_ret = 16;
1320       *size_ret = 1;
1321       *data_ret = (unsigned char *) xmalloc (sizeof (short) + 1);
1322       (*data_ret) [sizeof (short)] = 0;
1323       (*(short **) data_ret) [0] = (short) XINT (obj);
1324       if (NILP (type)) type = QINTEGER;
1325     }
1326   else if (INTP (obj) || CONSP (obj))
1327     {
1328       *format_ret = 32;
1329       *size_ret = 1;
1330       *data_ret = (unsigned char *) xmalloc (sizeof (long) + 1);
1331       (*data_ret) [sizeof (long)] = 0;
1332       (*(unsigned long **) data_ret) [0] = lisp_to_word (obj);
1333       if (NILP (type)) type = QINTEGER;
1334     }
1335   else if (VECTORP (obj))
1336     {
1337       /* Lisp Vectors may represent a set of ATOMs;
1338          a set of 16 or 32 bit INTEGERs;
1339          or a set of ATOM_PAIRs (represented as [[A1 A2] [A3 A4] ...]
1340        */
1341       int i;
1342
1343       if (SYMBOLP (XVECTOR_DATA (obj) [0]))
1344         /* This vector is an ATOM set */
1345         {
1346           if (NILP (type)) type = QATOM;
1347           *size_ret = XVECTOR_LENGTH (obj);
1348           *format_ret = 32;
1349           *data_ret = (unsigned char *) xmalloc ((*size_ret) * sizeof (Atom));
1350           for (i = 0; i < (int) (*size_ret); i++)
1351             if (SYMBOLP (XVECTOR_DATA (obj) [i]))
1352               (*(Atom **) data_ret) [i] =
1353                 symbol_to_x_atom (d, XVECTOR_DATA (obj) [i], 0);
1354             else
1355               signal_error (Qerror, /* Qselection_error */
1356                             list2 (build_string
1357                    ("all elements of the vector must be of the same type"),
1358                                    obj));
1359         }
1360 #if 0 /* #### MULTIPLE doesn't work yet */
1361       else if (VECTORP (XVECTOR_DATA (obj) [0]))
1362         /* This vector is an ATOM_PAIR set */
1363         {
1364           if (NILP (type)) type = QATOM_PAIR;
1365           *size_ret = XVECTOR_LENGTH (obj);
1366           *format_ret = 32;
1367           *data_ret = (unsigned char *)
1368             xmalloc ((*size_ret) * sizeof (Atom) * 2);
1369           for (i = 0; i < *size_ret; i++)
1370             if (VECTORP (XVECTOR_DATA (obj) [i]))
1371               {
1372                 Lisp_Object pair = XVECTOR_DATA (obj) [i];
1373                 if (XVECTOR_LENGTH (pair) != 2)
1374                   signal_error (Qerror,
1375                                 list2 (build_string
1376        ("elements of the vector must be vectors of exactly two elements"),
1377                                   pair));
1378
1379                 (*(Atom **) data_ret) [i * 2] =
1380                   symbol_to_x_atom (d, XVECTOR_DATA (pair) [0], 0);
1381                 (*(Atom **) data_ret) [(i * 2) + 1] =
1382                   symbol_to_x_atom (d, XVECTOR_DATA (pair) [1], 0);
1383               }
1384             else
1385               signal_error (Qerror,
1386                             list2 (build_string
1387                    ("all elements of the vector must be of the same type"),
1388                                    obj));
1389         }
1390 #endif
1391       else
1392         /* This vector is an INTEGER set, or something like it */
1393         {
1394           *size_ret = XVECTOR_LENGTH (obj);
1395           if (NILP (type)) type = QINTEGER;
1396           *format_ret = 16;
1397           for (i = 0; i < (int) (*size_ret); i++)
1398             if (CONSP (XVECTOR_DATA (obj) [i]))
1399               *format_ret = 32;
1400             else if (!INTP (XVECTOR_DATA (obj) [i]))
1401               signal_error (Qerror, /* Qselection_error */
1402                             list2 (build_string
1403         ("all elements of the vector must be integers or conses of integers"),
1404                                    obj));
1405
1406           *data_ret = (unsigned char *) xmalloc (*size_ret * (*format_ret/8));
1407           for (i = 0; i < (int) (*size_ret); i++)
1408             if (*format_ret == 32)
1409               (*((unsigned long **) data_ret)) [i] =
1410                 lisp_to_word (XVECTOR_DATA (obj) [i]);
1411             else
1412               (*((unsigned short **) data_ret)) [i] =
1413                 (unsigned short) lisp_to_word (XVECTOR_DATA (obj) [i]);
1414         }
1415     }
1416   else
1417     signal_error (Qerror, /* Qselection_error */
1418                   list2 (build_string ("unrecognized selection data"),
1419                          obj));
1420
1421   *type_ret = symbol_to_x_atom (d, type, 0);
1422 }
1423
1424
1425 \f
1426 /* Called from the event loop to handle SelectionNotify events.
1427    I don't think this needs to be reentrant.
1428  */
1429 void
1430 x_handle_selection_notify (XSelectionEvent *event)
1431 {
1432   if (! reading_selection_reply)
1433     message ("received an unexpected SelectionNotify event");
1434   else if (event->requestor != reading_selection_reply)
1435     message ("received a SelectionNotify event for the wrong window");
1436   else if (event->selection != reading_which_selection)
1437     message ("received the wrong selection type in SelectionNotify!");
1438   else
1439     reading_selection_reply = 0; /* we're done now. */
1440 }
1441
1442 static void
1443 x_disown_selection (Lisp_Object selection, Lisp_Object timeval)
1444 {
1445   struct device *d = decode_x_device (Qnil);
1446   Display *display = DEVICE_X_DISPLAY (d);
1447   Time timestamp;
1448   Atom selection_atom;
1449
1450   CHECK_SYMBOL (selection);
1451   if (NILP (timeval))
1452     timestamp = DEVICE_X_MOUSE_TIMESTAMP (d);
1453   else
1454     {
1455       /* #### This is bogus.  See the comment above about problems
1456          on OSF/1 and DEC Alphas.  Yet another reason why it sucks
1457          to have the implementation (i.e. cons of two 16-bit
1458          integers) exposed. */
1459       time_t the_time;
1460       lisp_to_time (timeval, &the_time);
1461       timestamp = (Time) the_time;
1462     }
1463
1464   selection_atom = symbol_to_x_atom (d, selection, 0);
1465
1466   XSetSelectionOwner (display, selection_atom, None, timestamp);
1467 }
1468
1469 static Lisp_Object
1470 x_selection_exists_p (Lisp_Object selection)
1471 {
1472   struct device *d = decode_x_device (Qnil);
1473   Display *dpy = DEVICE_X_DISPLAY (d);
1474   return XGetSelectionOwner (dpy, symbol_to_x_atom (d, selection, 0)) != None ?
1475     Qt : Qnil;
1476 }
1477
1478 \f
1479 #ifdef CUT_BUFFER_SUPPORT
1480
1481 static int cut_buffers_initialized; /* Whether we're sure they all exist */
1482
1483 /* Ensure that all 8 cut buffers exist.  ICCCM says we gotta... */
1484 static void
1485 initialize_cut_buffers (Display *display, Window window)
1486 {
1487   static unsigned CONST char * CONST data = (unsigned CONST char *) "";
1488 #define FROB(atom) XChangeProperty (display, window, atom, XA_STRING, 8, \
1489                                     PropModeAppend, data, 0)
1490   FROB (XA_CUT_BUFFER0);
1491   FROB (XA_CUT_BUFFER1);
1492   FROB (XA_CUT_BUFFER2);
1493   FROB (XA_CUT_BUFFER3);
1494   FROB (XA_CUT_BUFFER4);
1495   FROB (XA_CUT_BUFFER5);
1496   FROB (XA_CUT_BUFFER6);
1497   FROB (XA_CUT_BUFFER7);
1498 #undef FROB
1499   cut_buffers_initialized = 1;
1500 }
1501
1502 #define CHECK_CUTBUFFER(symbol) do {                            \
1503   CHECK_SYMBOL (symbol);                                        \
1504   if (! (EQ (symbol, QCUT_BUFFER0) ||                           \
1505          EQ (symbol, QCUT_BUFFER1) ||                           \
1506          EQ (symbol, QCUT_BUFFER2) ||                           \
1507          EQ (symbol, QCUT_BUFFER3) ||                           \
1508          EQ (symbol, QCUT_BUFFER4) ||                           \
1509          EQ (symbol, QCUT_BUFFER5) ||                           \
1510          EQ (symbol, QCUT_BUFFER6) ||                           \
1511          EQ (symbol, QCUT_BUFFER7)))                            \
1512     signal_simple_error ("Doesn't name a cutbuffer", symbol);   \
1513 } while (0)
1514
1515 DEFUN ("x-get-cutbuffer-internal", Fx_get_cutbuffer_internal, 1, 1, 0, /*
1516 Return the value of the named CUTBUFFER (typically CUT_BUFFER0).
1517 */
1518        (cutbuffer))
1519 {
1520   struct device *d = decode_x_device (Qnil);
1521   Display *display = DEVICE_X_DISPLAY (d);
1522   Window window = RootWindow (display, 0); /* Cutbuffers are on frame 0 */
1523   Atom cut_buffer_atom;
1524   unsigned char *data;
1525   int bytes;
1526   Atom type;
1527   int format;
1528   unsigned long size;
1529   Lisp_Object ret;
1530
1531   CHECK_CUTBUFFER (cutbuffer);
1532   cut_buffer_atom = symbol_to_x_atom (d, cutbuffer, 0);
1533
1534   x_get_window_property (display, window, cut_buffer_atom, &data, &bytes,
1535                          &type, &format, &size, 0);
1536   if (!data) return Qnil;
1537
1538   if (format != 8 || type != XA_STRING)
1539     signal_simple_error_2 ("Cut buffer doesn't contain 8-bit STRING data",
1540                            x_atom_to_symbol (d, type),
1541                            make_int (format));
1542
1543   /* We cheat - if the string contains an ESC character, that's
1544      technically not allowed in a STRING, so we assume it's
1545      COMPOUND_TEXT that we stored there ourselves earlier,
1546      in x-store-cutbuffer-internal  */
1547   ret = (bytes ?
1548          make_ext_string (data, bytes,
1549                           memchr (data, 0x1b, bytes) ?
1550                           Qctext : Qbinary)
1551          : Qnil);
1552   xfree (data);
1553   return ret;
1554 }
1555
1556
1557 DEFUN ("x-store-cutbuffer-internal", Fx_store_cutbuffer_internal, 2, 2, 0, /*
1558 Set the value of the named CUTBUFFER (typically CUT_BUFFER0) to STRING.
1559 */
1560        (cutbuffer, string))
1561 {
1562   struct device *d = decode_x_device (Qnil);
1563   Display *display = DEVICE_X_DISPLAY (d);
1564   Window window = RootWindow (display, 0); /* Cutbuffers are on frame 0 */
1565   Atom cut_buffer_atom;
1566   CONST Extbyte *data  = XSTRING_DATA (string);
1567   Extcount bytes = XSTRING_LENGTH (string);
1568   Extcount bytes_remaining;
1569   int max_bytes = SELECTION_QUANTUM (display);
1570 #ifdef MULE
1571   CONST Bufbyte *ptr, *end;
1572   enum { ASCII, LATIN_1, WORLD } chartypes = ASCII;
1573 #endif
1574
1575   if (max_bytes > MAX_SELECTION_QUANTUM)
1576     max_bytes = MAX_SELECTION_QUANTUM;
1577
1578   CHECK_CUTBUFFER (cutbuffer);
1579   CHECK_STRING (string);
1580   cut_buffer_atom = symbol_to_x_atom (d, cutbuffer, 0);
1581
1582   if (! cut_buffers_initialized)
1583     initialize_cut_buffers (display, window);
1584
1585   /* We use the STRING encoding (Latin-1 only) if we can, else COMPOUND_TEXT.
1586      We cheat and use type = `STRING' even when using COMPOUND_TEXT.
1587      The ICCCM requires that this be so, and other clients assume it,
1588      as we do ourselves in initialize_cut_buffers.  */
1589
1590 #ifdef MULE
1591   /* Optimize for the common ASCII case */
1592   for (ptr = data, end = ptr + bytes; ptr <= end; )
1593     {
1594       if (BYTE_ASCII_P (*ptr))
1595         {
1596           ptr++;
1597           continue;
1598         }
1599
1600       if ((*ptr) == LEADING_BYTE_LATIN_ISO8859_1 ||
1601           (*ptr) == LEADING_BYTE_CONTROL_1)
1602         {
1603           chartypes = LATIN_1;
1604           ptr += 2;
1605           continue;
1606         }
1607
1608       chartypes = WORLD;
1609       break;
1610     }
1611
1612   if (chartypes == LATIN_1)
1613     TO_EXTERNAL_FORMAT (LISP_STRING, string,
1614                         ALLOCA, (data, bytes),
1615                         Qbinary);
1616   else if (chartypes == WORLD)
1617     TO_EXTERNAL_FORMAT (LISP_STRING, string,
1618                         ALLOCA, (data, bytes),
1619                         Qctext);
1620 #endif /* MULE */
1621
1622   bytes_remaining = bytes;
1623
1624   while (bytes_remaining)
1625     {
1626       int chunk = bytes_remaining < max_bytes ? bytes_remaining : max_bytes;
1627       XChangeProperty (display, window, cut_buffer_atom, XA_STRING, 8,
1628                        (bytes_remaining == bytes
1629                         ? PropModeReplace : PropModeAppend),
1630                        data, chunk);
1631       data += chunk;
1632       bytes_remaining -= chunk;
1633     }
1634   return string;
1635 }
1636
1637
1638 DEFUN ("x-rotate-cutbuffers-internal", Fx_rotate_cutbuffers_internal, 1, 1, 0, /*
1639 Rotate the values of the cutbuffers by the given number of steps;
1640 positive means move values forward, negative means backward.
1641 */
1642        (n))
1643 {
1644   struct device *d = decode_x_device (Qnil);
1645   Display *display = DEVICE_X_DISPLAY (d);
1646   Window window = RootWindow (display, 0); /* Cutbuffers are on frame 0 */
1647   Atom props [8];
1648
1649   CHECK_INT (n);
1650   if (XINT (n) == 0)
1651     return n;
1652   if (! cut_buffers_initialized)
1653     initialize_cut_buffers (display, window);
1654   props[0] = XA_CUT_BUFFER0;
1655   props[1] = XA_CUT_BUFFER1;
1656   props[2] = XA_CUT_BUFFER2;
1657   props[3] = XA_CUT_BUFFER3;
1658   props[4] = XA_CUT_BUFFER4;
1659   props[5] = XA_CUT_BUFFER5;
1660   props[6] = XA_CUT_BUFFER6;
1661   props[7] = XA_CUT_BUFFER7;
1662   XRotateWindowProperties (display, window, props, 8, XINT (n));
1663   return n;
1664 }
1665
1666 #endif /* CUT_BUFFER_SUPPORT */
1667
1668
1669 \f
1670 /************************************************************************/
1671 /*                            initialization                            */
1672 /************************************************************************/
1673
1674 void
1675 syms_of_select_x (void)
1676 {
1677
1678 #ifdef CUT_BUFFER_SUPPORT
1679   DEFSUBR (Fx_get_cutbuffer_internal);
1680   DEFSUBR (Fx_store_cutbuffer_internal);
1681   DEFSUBR (Fx_rotate_cutbuffers_internal);
1682 #endif /* CUT_BUFFER_SUPPORT */
1683
1684   /* Unfortunately, timeout handlers must be lisp functions. */
1685   defsymbol (&Qx_selection_reply_timeout_internal,
1686              "x-selection-reply-timeout-internal");
1687   DEFSUBR (Fx_selection_reply_timeout_internal);
1688
1689 #ifdef CUT_BUFFER_SUPPORT
1690   defsymbol (&QCUT_BUFFER0, "CUT_BUFFER0");
1691   defsymbol (&QCUT_BUFFER1, "CUT_BUFFER1");
1692   defsymbol (&QCUT_BUFFER2, "CUT_BUFFER2");
1693   defsymbol (&QCUT_BUFFER3, "CUT_BUFFER3");
1694   defsymbol (&QCUT_BUFFER4, "CUT_BUFFER4");
1695   defsymbol (&QCUT_BUFFER5, "CUT_BUFFER5");
1696   defsymbol (&QCUT_BUFFER6, "CUT_BUFFER6");
1697   defsymbol (&QCUT_BUFFER7, "CUT_BUFFER7");
1698 #endif /* CUT_BUFFER_SUPPORT */
1699 }
1700
1701 void
1702 console_type_create_select_x (void)
1703 {
1704   CONSOLE_HAS_METHOD (x, own_selection);
1705   CONSOLE_HAS_METHOD (x, disown_selection);
1706   CONSOLE_HAS_METHOD (x, get_foreign_selection);
1707   CONSOLE_HAS_METHOD (x, selection_exists_p);
1708 }
1709
1710 void
1711 reinit_vars_of_select_x (void)
1712 {
1713   reading_selection_reply = 0;
1714   reading_which_selection = 0;
1715   selection_reply_timed_out = 0;
1716   for_whom_the_bell_tolls = 0;
1717   prop_location_tick = 0;
1718 }
1719
1720 void
1721 vars_of_select_x (void)
1722 {
1723   reinit_vars_of_select_x ();
1724
1725 #ifdef CUT_BUFFER_SUPPORT
1726   cut_buffers_initialized = 0;
1727   Fprovide (intern ("cut-buffer"));
1728 #endif
1729
1730   DEFVAR_LISP ("x-sent-selection-hooks", &Vx_sent_selection_hooks /*
1731 A function or functions to be called after we have responded to some
1732 other client's request for the value of a selection that we own.  The
1733 function(s) will be called with four arguments:
1734   - the name of the selection (typically PRIMARY, SECONDARY, or CLIPBOARD);
1735   - the name of the selection-type which we were requested to convert the
1736     selection into before sending (for example, STRING or LENGTH);
1737   - and whether we successfully transmitted the selection.
1738 We might have failed (and declined the request) for any number of reasons,
1739 including being asked for a selection that we no longer own, or being asked
1740 to convert into a type that we don't know about or that is inappropriate.
1741 This hook doesn't let you change the behavior of emacs's selection replies,
1742 it merely informs you that they have happened.
1743 */ );
1744   Vx_sent_selection_hooks = Qunbound;
1745
1746   DEFVAR_INT ("x-selection-timeout", &x_selection_timeout /*
1747 If the selection owner doesn't reply in this many seconds, we give up.
1748 A value of 0 means wait as long as necessary.  This is initialized from the
1749 \"*selectionTimeout\" resource (which is expressed in milliseconds).
1750 */ );
1751   x_selection_timeout = 0;
1752 }
1753
1754 void
1755 Xatoms_of_select_x (struct device *d)
1756 {
1757   Display *D = DEVICE_X_DISPLAY (d);
1758
1759   /* Non-predefined atoms that we might end up using a lot */
1760   DEVICE_XATOM_CLIPBOARD     (d) = XInternAtom (D, "CLIPBOARD",     False);
1761   DEVICE_XATOM_TIMESTAMP     (d) = XInternAtom (D, "TIMESTAMP",     False);
1762   DEVICE_XATOM_TEXT          (d) = XInternAtom (D, "TEXT",          False);
1763   DEVICE_XATOM_DELETE        (d) = XInternAtom (D, "DELETE",        False);
1764   DEVICE_XATOM_MULTIPLE      (d) = XInternAtom (D, "MULTIPLE",      False);
1765   DEVICE_XATOM_INCR          (d) = XInternAtom (D, "INCR",          False);
1766   DEVICE_XATOM_TARGETS       (d) = XInternAtom (D, "TARGETS",       False);
1767   DEVICE_XATOM_NULL          (d) = XInternAtom (D, "NULL",          False);
1768   DEVICE_XATOM_ATOM_PAIR     (d) = XInternAtom (D, "ATOM_PAIR",     False);
1769   DEVICE_XATOM_COMPOUND_TEXT (d) = XInternAtom (D, "COMPOUND_TEXT", False);
1770   DEVICE_XATOM_EMACS_TMP     (d) = XInternAtom (D, "_EMACS_TMP_",   False);
1771 }