1 /* X Selection processing for XEmacs
2 Copyright (C) 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
4 This file is part of XEmacs.
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
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
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. */
21 /* Synched up with: Not synched with FSF. */
23 /* Rewritten by jwz */
29 #include "console-x.h"
30 #include "objects-x.h"
37 int lisp_to_time (Lisp_Object, time_t *);
38 Lisp_Object time_to_lisp (time_t);
40 #ifdef LWLIB_USES_MOTIF
41 # define MOTIF_CLIPBOARDS
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,
53 #define CUT_BUFFER_SUPPORT
55 #ifdef CUT_BUFFER_SUPPORT
56 Lisp_Object QCUT_BUFFER0, QCUT_BUFFER1, QCUT_BUFFER2, QCUT_BUFFER3,
57 QCUT_BUFFER4, QCUT_BUFFER5, QCUT_BUFFER6, QCUT_BUFFER7;
60 Lisp_Object Vx_sent_selection_hooks;
62 /* If this is a smaller number than the max-request-size of the display,
63 emacs will use INCR selection transfer when the selection is larger
64 than this. The max-request-size is usually around 64k, so if you want
65 emacs to use incremental selection transfers when the selection is
66 smaller than that, set this. I added this mostly for debugging the
67 incremental transfer stuff, but it might improve server performance.
69 #define MAX_SELECTION_QUANTUM 0xFFFFFF
71 #define SELECTION_QUANTUM(dpy) ((XMaxRequestSize (dpy) << 2) - 100)
73 /* If the selection owner takes too long to reply to a selection request,
74 we give up on it. This is in seconds (0 = no timeout).
76 Fixnum x_selection_timeout;
78 /* Enable motif selection optimizations. */
79 int x_selection_strict_motif_ownership;
82 /* Utility functions */
84 static void lisp_data_to_selection_data (struct device *,
86 unsigned char **data_ret,
88 unsigned int *size_ret,
90 static Lisp_Object selection_data_to_lisp_data (struct device *,
95 static Lisp_Object x_get_window_property_as_lisp_data (Display *,
98 Lisp_Object target_type,
101 static int expect_property_change (Display *, Window, Atom prop, int state);
102 static void wait_for_property_change (long);
103 static void unexpect_property_change (int);
104 static int waiting_for_other_props_on_window (Display *, Window);
106 /* This converts a Lisp symbol to a server Atom, avoiding a server
107 roundtrip whenever possible.
110 symbol_to_x_atom (struct device *d, Lisp_Object sym, int only_if_exists)
112 Display *display = DEVICE_X_DISPLAY (d);
114 if (NILP (sym)) return XA_PRIMARY;
115 if (EQ (sym, Qt)) return XA_SECONDARY;
116 if (EQ (sym, QPRIMARY)) return XA_PRIMARY;
117 if (EQ (sym, QSECONDARY)) return XA_SECONDARY;
118 if (EQ (sym, QSTRING)) return XA_STRING;
119 if (EQ (sym, QINTEGER)) return XA_INTEGER;
120 if (EQ (sym, QATOM)) return XA_ATOM;
121 if (EQ (sym, QCLIPBOARD)) return DEVICE_XATOM_CLIPBOARD (d);
122 if (EQ (sym, QTIMESTAMP)) return DEVICE_XATOM_TIMESTAMP (d);
123 if (EQ (sym, QTEXT)) return DEVICE_XATOM_TEXT (d);
124 if (EQ (sym, QDELETE)) return DEVICE_XATOM_DELETE (d);
125 if (EQ (sym, QMULTIPLE)) return DEVICE_XATOM_MULTIPLE (d);
126 if (EQ (sym, QINCR)) return DEVICE_XATOM_INCR (d);
127 if (EQ (sym, QEMACS_TMP)) return DEVICE_XATOM_EMACS_TMP (d);
128 if (EQ (sym, QTARGETS)) return DEVICE_XATOM_TARGETS (d);
129 if (EQ (sym, QNULL)) return DEVICE_XATOM_NULL (d);
130 if (EQ (sym, QATOM_PAIR)) return DEVICE_XATOM_ATOM_PAIR (d);
131 if (EQ (sym, QCOMPOUND_TEXT)) return DEVICE_XATOM_COMPOUND_TEXT (d);
133 #ifdef CUT_BUFFER_SUPPORT
134 if (EQ (sym, QCUT_BUFFER0)) return XA_CUT_BUFFER0;
135 if (EQ (sym, QCUT_BUFFER1)) return XA_CUT_BUFFER1;
136 if (EQ (sym, QCUT_BUFFER2)) return XA_CUT_BUFFER2;
137 if (EQ (sym, QCUT_BUFFER3)) return XA_CUT_BUFFER3;
138 if (EQ (sym, QCUT_BUFFER4)) return XA_CUT_BUFFER4;
139 if (EQ (sym, QCUT_BUFFER5)) return XA_CUT_BUFFER5;
140 if (EQ (sym, QCUT_BUFFER6)) return XA_CUT_BUFFER6;
141 if (EQ (sym, QCUT_BUFFER7)) return XA_CUT_BUFFER7;
142 #endif /* CUT_BUFFER_SUPPORT */
146 LISP_STRING_TO_EXTERNAL (Fsymbol_name (sym), nameext, Qctext);
147 return XInternAtom (display, nameext, only_if_exists ? True : False);
152 /* This converts a server Atom to a Lisp symbol, avoiding server roundtrips
153 and calls to intern whenever possible.
156 x_atom_to_symbol (struct device *d, Atom atom)
158 Display *display = DEVICE_X_DISPLAY (d);
160 if (! atom) return Qnil;
161 if (atom == XA_PRIMARY) return QPRIMARY;
162 if (atom == XA_SECONDARY) return QSECONDARY;
163 if (atom == XA_STRING) return QSTRING;
164 if (atom == XA_INTEGER) return QINTEGER;
165 if (atom == XA_ATOM) return QATOM;
166 if (atom == DEVICE_XATOM_CLIPBOARD (d)) return QCLIPBOARD;
167 if (atom == DEVICE_XATOM_TIMESTAMP (d)) return QTIMESTAMP;
168 if (atom == DEVICE_XATOM_TEXT (d)) return QTEXT;
169 if (atom == DEVICE_XATOM_DELETE (d)) return QDELETE;
170 if (atom == DEVICE_XATOM_MULTIPLE (d)) return QMULTIPLE;
171 if (atom == DEVICE_XATOM_INCR (d)) return QINCR;
172 if (atom == DEVICE_XATOM_EMACS_TMP (d)) return QEMACS_TMP;
173 if (atom == DEVICE_XATOM_TARGETS (d)) return QTARGETS;
174 if (atom == DEVICE_XATOM_NULL (d)) return QNULL;
175 if (atom == DEVICE_XATOM_ATOM_PAIR (d)) return QATOM_PAIR;
176 if (atom == DEVICE_XATOM_COMPOUND_TEXT (d)) return QCOMPOUND_TEXT;
178 #ifdef CUT_BUFFER_SUPPORT
179 if (atom == XA_CUT_BUFFER0) return QCUT_BUFFER0;
180 if (atom == XA_CUT_BUFFER1) return QCUT_BUFFER1;
181 if (atom == XA_CUT_BUFFER2) return QCUT_BUFFER2;
182 if (atom == XA_CUT_BUFFER3) return QCUT_BUFFER3;
183 if (atom == XA_CUT_BUFFER4) return QCUT_BUFFER4;
184 if (atom == XA_CUT_BUFFER5) return QCUT_BUFFER5;
185 if (atom == XA_CUT_BUFFER6) return QCUT_BUFFER6;
186 if (atom == XA_CUT_BUFFER7) return QCUT_BUFFER7;
191 char *str = XGetAtomName (display, atom);
193 if (! str) return Qnil;
195 TO_INTERNAL_FORMAT (C_STRING, str,
196 C_STRING_ALLOCA, intstr,
199 return intern (intstr);
204 /* Do protocol to assert ourself as a selection owner.
207 x_own_selection (Lisp_Object selection_name, Lisp_Object selection_value,
208 Lisp_Object how_to_add, Lisp_Object selection_type,
211 struct device *d = decode_x_device (Qnil);
212 Display *display = DEVICE_X_DISPLAY (d);
213 struct frame *sel_frame = selected_frame ();
214 Window selecting_window = XtWindow (FRAME_X_TEXT_WIDGET (sel_frame));
215 Lisp_Object selection_time;
216 /* Use the time of the last-read mouse or keyboard event.
217 For selection purposes, we use this as a sleazy way of knowing what the
218 current time is in server-time. This assumes that the most recently read
219 mouse or keyboard event has something to do with the assertion of the
220 selection, which is probably true.
222 Time thyme = DEVICE_X_MOUSE_TIMESTAMP (d);
225 CHECK_SYMBOL (selection_name);
226 selection_atom = symbol_to_x_atom (d, selection_name, 0);
228 XSetSelectionOwner (display, selection_atom, selecting_window, thyme);
230 /* We do NOT use time_to_lisp() here any more, like we used to.
231 That assumed equivalence of time_t and Time, which is not
232 necessarily the case (e.g. under OSF on the Alphas, where
233 Time is a 64-bit quantity and time_t is a 32-bit quantity).
235 Opaque pointers are the clean way to go here.
237 selection_time = make_opaque (&thyme, sizeof (thyme));
239 #ifdef MOTIF_CLIPBOARDS
240 hack_motif_clipboard_selection (selection_atom, selection_value,
241 thyme, display, selecting_window, owned_p);
243 return selection_time;
246 #ifdef MOTIF_CLIPBOARDS /* Bend over baby. Take it and like it. */
248 # ifdef MOTIF_INCREMENTAL_CLIPBOARDS_WORK
249 static void motif_clipboard_cb ();
253 hack_motif_clipboard_selection (Atom selection_atom,
254 Lisp_Object selection_value,
257 Window selecting_window,
260 struct device *d = get_device_from_display (display);
261 /* Those Motif wankers can't be bothered to follow the ICCCM, and do
262 their own non-Xlib non-Xt clipboard processing. So we have to do
263 this so that linked-in Motif widgets don't get themselves wedged.
265 if (selection_atom == DEVICE_XATOM_CLIPBOARD (d)
266 && STRINGP (selection_value)
268 /* If we already own the clipboard, don't own it again in the Motif
269 way. This might lose in some subtle way, since the timestamp won't
270 be current, but owning the selection on the Motif way does a
271 SHITLOAD of X protocol, and it makes killing text be incredibly
272 slow when using an X terminal. ARRRRGGGHHH!!!!
274 /* No, this is no good, because then Motif text fields don't bother
275 to look up the new value, and you can't Copy from a buffer, Paste
276 into a text field, then Copy something else from the buffer and
277 paste it into the text field -- it pastes the first thing again. */
279 /* Selectively re-enable this because for most users its
280 just too painful - especially over a remote link. */
281 || x_selection_strict_motif_ownership)
284 #ifdef MOTIF_INCREMENTAL_CLIPBOARDS_WORK
285 Widget widget = FRAME_X_TEXT_WIDGET (selected_frame());
288 #if XmVersion >= 1002
291 int dataid; /* 1.2 wants long, but 1.1.5 wants int... */
294 String encoding = "STRING";
295 const Bufbyte *data = XSTRING_DATA (selection_value);
296 Bytecount bytes = XSTRING_LENGTH (selection_value);
300 enum { ASCII, LATIN_1, WORLD } chartypes = ASCII;
301 const Bufbyte *ptr = data, *end = ptr + bytes;
302 /* Optimize for the common ASCII case */
305 if (BYTE_ASCII_P (*ptr))
311 if ((*ptr) == LEADING_BYTE_LATIN_ISO8859_1 ||
312 (*ptr) == LEADING_BYTE_CONTROL_1)
323 if (chartypes == LATIN_1)
324 TO_EXTERNAL_FORMAT (LISP_STRING, selection_value,
325 ALLOCA, (data, bytes),
327 else if (chartypes == WORLD)
329 TO_EXTERNAL_FORMAT (LISP_STRING, selection_value,
330 ALLOCA, (data, bytes),
332 encoding = "COMPOUND_TEXT";
337 fmh = XmStringCreateLtoR ("Clipboard", XmSTRING_DEFAULT_CHARSET);
338 while (ClipboardSuccess !=
339 XmClipboardStartCopy (display, selecting_window, fmh, thyme,
340 #ifdef MOTIF_INCREMENTAL_CLIPBOARDS_WORK
341 widget, motif_clipboard_cb,
348 while (ClipboardSuccess !=
349 XmClipboardCopy (display, selecting_window, itemid, encoding,
350 #ifdef MOTIF_INCREMENTAL_CLIPBOARDS_WORK
351 /* O'Reilly examples say size can be 0,
352 but this clearly is not the case. */
353 0, bytes, (int) selecting_window, /* private id */
354 #else /* !MOTIF_INCREMENTAL_CLIPBOARDS_WORK */
355 (XtPointer) data, bytes, 0,
356 #endif /* !MOTIF_INCREMENTAL_CLIPBOARDS_WORK */
359 while (ClipboardSuccess !=
360 XmClipboardEndCopy (display, selecting_window, itemid))
365 # ifdef MOTIF_INCREMENTAL_CLIPBOARDS_WORK
366 /* I tried to treat the clipboard like a real selection, and not send
367 the data until it was requested, but it looks like that just doesn't
368 work at all unless the selection owner and requestor are in different
369 processes. From reading the Motif source, it looks like they never
370 even considered having two widgets in the same application transfer
371 data between each other using "by-name" clipboard values. What a
375 motif_clipboard_cb (Widget widget, int *data_id, int *private_id, int *reason)
379 case XmCR_CLIPBOARD_DATA_REQUEST:
381 Display *dpy = XtDisplay (widget);
382 Window window = (Window) *private_id;
383 Lisp_Object selection = select_convert_out (QCLIPBOARD, Qnil, Qnil);
385 /* Whichever lazy git wrote this originally just called ABORT()
386 when anything didn't go their way... */
388 /* Try some other text types */
389 if (NILP (selection))
390 selection = select_convert_out (QCLIPBOARD, QSTRING, Qnil);
391 if (NILP (selection))
392 selection = select_convert_out (QCLIPBOARD, QTEXT, Qnil);
393 if (NILP (selection))
394 selection = select_convert_out (QCLIPBOARD, QCOMPOUND_TEXT, Qnil);
396 if (CONSP (selection) && SYMBOLP (XCAR (selection))
397 && (EQ (XCAR (selection), QSTRING)
398 || EQ (XCAR (selection), QTEXT)
399 || EQ (XCAR (selection), QCOMPOUND_TEXT)))
400 selection = XCDR (selection);
402 if (NILP (selection))
403 signal_error (Qselection_conversion_error,
404 build_string ("no selection"));
406 if (!STRINGP (selection))
407 signal_error (Qselection_conversion_error,
408 build_string ("couldn't convert selection to string"));
411 XmClipboardCopyByName (dpy, window, *data_id,
412 (char *) XSTRING_DATA (selection),
413 XSTRING_LENGTH (selection) + 1,
417 case XmCR_CLIPBOARD_DATA_DELETE:
419 /* don't need to free anything */
423 # endif /* MOTIF_INCREMENTAL_CLIPBOARDS_WORK */
424 #endif /* MOTIF_CLIPBOARDS */
429 /* Send a SelectionNotify event to the requestor with property=None, meaning
430 we were unable to do what they wanted.
433 x_decline_selection_request (XSelectionRequestEvent *event)
435 XSelectionEvent reply;
436 reply.type = SelectionNotify;
437 reply.display = event->display;
438 reply.requestor = event->requestor;
439 reply.selection = event->selection;
440 reply.time = event->time;
441 reply.target = event->target;
442 reply.property = None;
444 XSendEvent (reply.display, reply.requestor, False, 0L, (XEvent *) &reply);
445 XFlush (reply.display);
449 /* Used as an unwind-protect clause so that, if a selection-converter signals
450 an error, we tell the requestor that we were unable to do what they wanted
451 before we throw to top-level or go into the debugger or whatever.
454 x_selection_request_lisp_error (Lisp_Object closure)
456 XSelectionRequestEvent *event = (XSelectionRequestEvent *)
457 get_opaque_ptr (closure);
459 free_opaque_ptr (closure);
460 if (event->type == 0) /* we set this to mean "completed normally" */
462 x_decline_selection_request (event);
467 /* Convert our selection to the requested type, and put that data where the
468 requestor wants it. Then tell them whether we've succeeded.
471 x_reply_selection_request (XSelectionRequestEvent *event, int format,
472 unsigned char *data, int size, Atom type)
474 /* This function can GC */
475 XSelectionEvent reply;
476 Display *display = event->display;
477 struct device *d = get_device_from_display (display);
478 Window window = event->requestor;
480 int format_bytes = format/8;
481 int max_bytes = SELECTION_QUANTUM (display);
482 if (max_bytes > MAX_SELECTION_QUANTUM) max_bytes = MAX_SELECTION_QUANTUM;
484 reply.type = SelectionNotify;
485 reply.display = display;
486 reply.requestor = window;
487 reply.selection = event->selection;
488 reply.time = event->time;
489 reply.target = event->target;
490 reply.property = (event->property == None ? event->target : event->property);
492 /* #### XChangeProperty can generate BadAlloc, and we must handle it! */
494 /* Store the data on the requested property.
495 If the selection is large, only store the first N bytes of it.
497 bytes_remaining = size * format_bytes;
498 if (bytes_remaining <= max_bytes)
500 /* Send all the data at once, with minimal handshaking. */
502 stderr_out ("\nStoring all %d\n", bytes_remaining);
504 XChangeProperty (display, window, reply.property, type, format,
505 PropModeReplace, data, size);
506 /* At this point, the selection was successfully stored; ack it. */
507 XSendEvent (display, window, False, 0L, (XEvent *) &reply);
512 /* Send an INCR selection. */
515 if (x_window_to_frame (d, window)) /* #### debug */
516 error ("attempt to transfer an INCR to ourself!");
518 stderr_out ("\nINCR %d\n", bytes_remaining);
520 prop_id = expect_property_change (display, window, reply.property,
523 XChangeProperty (display, window, reply.property, DEVICE_XATOM_INCR (d),
524 32, PropModeReplace, (unsigned char *)
525 &bytes_remaining, 1);
526 XSelectInput (display, window, PropertyChangeMask);
527 /* Tell 'em the INCR data is there... */
528 XSendEvent (display, window, False, 0L, (XEvent *) &reply);
531 /* First, wait for the requestor to ack by deleting the property.
532 This can run random lisp code (process handlers) or signal.
534 wait_for_property_change (prop_id);
536 while (bytes_remaining)
538 int i = ((bytes_remaining < max_bytes)
541 prop_id = expect_property_change (display, window, reply.property,
544 stderr_out (" INCR adding %d\n", i);
546 /* Append the next chunk of data to the property. */
547 XChangeProperty (display, window, reply.property, type, format,
548 PropModeAppend, data, i / format_bytes);
549 bytes_remaining -= i;
552 /* Now wait for the requestor to ack this chunk by deleting the
553 property. This can run random lisp code or signal.
555 wait_for_property_change (prop_id);
557 /* Now write a zero-length chunk to the property to tell the requestor
560 stderr_out (" INCR done\n");
562 if (! waiting_for_other_props_on_window (display, window))
563 XSelectInput (display, window, 0L);
565 XChangeProperty (display, window, reply.property, type, format,
566 PropModeReplace, data, 0);
572 /* Called from the event-loop in response to a SelectionRequest event.
575 x_handle_selection_request (XSelectionRequestEvent *event)
577 /* This function can GC */
578 struct gcpro gcpro1, gcpro2;
579 Lisp_Object temp_obj;
580 Lisp_Object selection_symbol;
581 Lisp_Object target_symbol = Qnil;
582 Lisp_Object converted_selection = Qnil;
583 Time local_selection_time;
584 Lisp_Object successful_p = Qnil;
586 struct device *d = get_device_from_display (event->display);
588 GCPRO2 (converted_selection, target_symbol);
590 selection_symbol = x_atom_to_symbol (d, event->selection);
591 target_symbol = x_atom_to_symbol (d, event->target);
593 #if 0 /* #### MULTIPLE doesn't work yet */
594 if (EQ (target_symbol, QMULTIPLE))
595 target_symbol = fetch_multiple_target (event);
598 temp_obj = Fget_selection_timestamp (selection_symbol);
602 /* We don't appear to have the selection. */
603 x_decline_selection_request (event);
608 local_selection_time = * (Time *) XOPAQUE_DATA (temp_obj);
610 if (event->time != CurrentTime &&
611 local_selection_time > event->time)
613 /* Someone asked for the selection, and we have one, but not the one
614 they're looking for. */
615 x_decline_selection_request (event);
619 converted_selection = select_convert_out (selection_symbol,
620 target_symbol, Qnil);
622 /* #### Is this the right thing to do? I'm no X expert. -- ajh */
623 if (NILP (converted_selection))
625 /* We don't appear to have a selection in that data type. */
626 x_decline_selection_request (event);
630 count = specpdl_depth ();
631 record_unwind_protect (x_selection_request_lisp_error,
632 make_opaque_ptr (event));
639 lisp_data_to_selection_data (d, converted_selection,
640 &data, &type, &size, &format);
642 x_reply_selection_request (event, format, data, size, type);
644 /* Tell x_selection_request_lisp_error() it's cool. */
649 unbind_to (count, Qnil);
655 /* Let random lisp code notice that the selection has been asked for. */
657 Lisp_Object val = Vx_sent_selection_hooks;
658 if (!UNBOUNDP (val) && !NILP (val))
661 if (CONSP (val) && !EQ (XCAR (val), Qlambda))
662 for (rest = val; !NILP (rest); rest = Fcdr (rest))
663 call3 (Fcar (rest), selection_symbol, target_symbol, successful_p);
665 call3 (val, selection_symbol, target_symbol, successful_p);
671 /* Called from the event-loop in response to a SelectionClear event.
674 x_handle_selection_clear (XSelectionClearEvent *event)
676 Display *display = event->display;
677 struct device *d = get_device_from_display (display);
678 Atom selection = event->selection;
679 Time changed_owner_time = event->time;
681 Lisp_Object selection_symbol, local_selection_time_lisp;
682 Time local_selection_time;
684 selection_symbol = x_atom_to_symbol (d, selection);
686 local_selection_time_lisp = Fget_selection_timestamp (selection_symbol);
688 /* We don't own the selection, so that's fine. */
689 if (NILP (local_selection_time_lisp))
692 local_selection_time = * (Time *) XOPAQUE_DATA (local_selection_time_lisp);
694 /* This SelectionClear is for a selection that we no longer own, so we can
695 disregard it. (That is, we have reasserted the selection since this
696 request was generated.)
698 if (changed_owner_time != CurrentTime &&
699 local_selection_time > changed_owner_time)
702 handle_selection_clear (selection_symbol);
706 /* This stuff is so that INCR selections are reentrant (that is, so we can
707 be servicing multiple INCR selection requests simultaneously). I haven't
708 actually tested that yet.
711 static int prop_location_tick;
713 static struct prop_location {
719 struct prop_location *next;
720 } *for_whom_the_bell_tolls;
724 property_deleted_p (void *tick)
726 struct prop_location *rest = for_whom_the_bell_tolls;
728 if (rest->tick == (long) tick)
736 waiting_for_other_props_on_window (Display *display, Window window)
738 struct prop_location *rest = for_whom_the_bell_tolls;
740 if (rest->display == display && rest->window == window)
749 expect_property_change (Display *display, Window window,
750 Atom property, int state)
752 struct prop_location *pl = xnew (struct prop_location);
753 pl->tick = ++prop_location_tick;
754 pl->display = display;
756 pl->property = property;
757 pl->desired_state = state;
758 pl->next = for_whom_the_bell_tolls;
759 for_whom_the_bell_tolls = pl;
764 unexpect_property_change (int tick)
766 struct prop_location *prev = 0, *rest = for_whom_the_bell_tolls;
769 if (rest->tick == tick)
772 prev->next = rest->next;
774 for_whom_the_bell_tolls = rest->next;
784 wait_for_property_change (long tick)
786 /* This function can GC */
787 wait_delaying_user_input (property_deleted_p, (void *) tick);
791 /* Called from the event-loop in response to a PropertyNotify event.
794 x_handle_property_notify (XPropertyEvent *event)
796 struct prop_location *prev = 0, *rest = for_whom_the_bell_tolls;
799 if (rest->property == event->atom &&
800 rest->window == event->window &&
801 rest->display == event->display &&
802 rest->desired_state == event->state)
805 stderr_out ("Saw expected prop-%s on %s\n",
806 (event->state == PropertyDelete ? "delete" : "change"),
807 (char *) string_data (XSYMBOL (x_atom_to_symbol (get_device_from_display (event->display), event->atom))->name);
810 prev->next = rest->next;
812 for_whom_the_bell_tolls = rest->next;
820 stderr_out ("Saw UNexpected prop-%s on %s\n",
821 (event->state == PropertyDelete ? "delete" : "change"),
822 (char *) string_data (XSYMBOL (x_atom_to_symbol (get_device_from_display (event->display), event->atom))->name));
828 #if 0 /* #### MULTIPLE doesn't work yet */
831 fetch_multiple_target (XSelectionRequestEvent *event)
833 /* This function can GC */
834 Display *display = event->display;
835 Window window = event->requestor;
836 Atom target = event->target;
837 Atom selection_atom = event->selection;
842 x_get_window_property_as_lisp_data (display, window, target,
848 copy_multiple_data (Lisp_Object obj)
854 return Fcons (XCAR (obj), copy_multiple_data (XCDR (obj)));
857 len = XVECTOR_LENGTH (obj);
858 vec = make_vector (len, Qnil);
859 for (i = 0; i < len; i++)
861 Lisp_Object vec2 = XVECTOR_DATA (obj) [i];
863 if (XVECTOR_LENGTH (vec2) != 2)
864 signal_error (Qerror, list2 (build_string
865 ("vectors must be of length 2"),
867 XVECTOR_DATA (vec) [i] = make_vector (2, Qnil);
868 XVECTOR_DATA (XVECTOR_DATA (vec) [i]) [0] = XVECTOR_DATA (vec2) [0];
869 XVECTOR_DATA (XVECTOR_DATA (vec) [i]) [1] = XVECTOR_DATA (vec2) [1];
877 static Window reading_selection_reply;
878 static Atom reading_which_selection;
879 static int selection_reply_timed_out;
882 selection_reply_done (void *ignore)
884 return !reading_selection_reply;
887 static Lisp_Object Qx_selection_reply_timeout_internal;
889 DEFUN ("x-selection-reply-timeout-internal", Fx_selection_reply_timeout_internal,
894 selection_reply_timed_out = 1;
895 reading_selection_reply = 0;
900 /* Do protocol to read selection-data from the server.
901 Converts this to lisp data and returns it.
904 x_get_foreign_selection (Lisp_Object selection_symbol, Lisp_Object target_type)
906 /* This function can GC */
907 struct device *d = decode_x_device (Qnil);
908 Display *display = DEVICE_X_DISPLAY (d);
909 struct frame *sel_frame = selected_frame ();
910 Window requestor_window = XtWindow (FRAME_X_TEXT_WIDGET (sel_frame));
911 Time requestor_time = DEVICE_X_MOUSE_TIMESTAMP (d);
912 Atom target_property = DEVICE_XATOM_EMACS_TMP (d);
913 Atom selection_atom = symbol_to_x_atom (d, selection_symbol, 0);
915 Atom type_atom = symbol_to_x_atom (d, (CONSP (target_type) ?
916 XCAR (target_type) : target_type), 0);
918 XConvertSelection (display, selection_atom, type_atom, target_property,
919 requestor_window, requestor_time);
921 /* Block until the reply has been read. */
922 reading_selection_reply = requestor_window;
923 reading_which_selection = selection_atom;
924 selection_reply_timed_out = 0;
926 speccount = specpdl_depth ();
928 /* add a timeout handler */
929 if (x_selection_timeout > 0)
931 Lisp_Object id = Fadd_timeout (make_int (x_selection_timeout),
932 Qx_selection_reply_timeout_internal,
934 record_unwind_protect (Fdisable_timeout, id);
938 wait_delaying_user_input (selection_reply_done, 0);
940 if (selection_reply_timed_out)
941 error ("timed out waiting for reply from selection owner");
943 unbind_to (speccount, Qnil);
945 /* otherwise, the selection is waiting for us on the requested property. */
947 return select_convert_in (selection_symbol,
949 x_get_window_property_as_lisp_data(display,
958 x_get_window_property (Display *display, Window window, Atom property,
959 Extbyte **data_ret, int *bytes_ret,
960 Atom *actual_type_ret, int *actual_format_ret,
961 unsigned long *actual_size_ret, int delete_p)
964 unsigned long bytes_remaining;
966 unsigned char *tmp_data = 0;
968 int buffer_size = SELECTION_QUANTUM (display);
969 if (buffer_size > MAX_SELECTION_QUANTUM) buffer_size = MAX_SELECTION_QUANTUM;
971 /* First probe the thing to find out how big it is. */
972 result = XGetWindowProperty (display, window, property,
973 0, 0, False, AnyPropertyType,
974 actual_type_ret, actual_format_ret,
976 &bytes_remaining, &tmp_data);
977 if (result != Success)
983 XFree ((char *) tmp_data);
985 if (*actual_type_ret == None || *actual_format_ret == 0)
987 if (delete_p) XDeleteProperty (display, window, property);
993 total_size = bytes_remaining + 1;
994 *data_ret = (Extbyte *) xmalloc (total_size);
996 /* Now read, until we've gotten it all. */
997 while (bytes_remaining)
1000 int last = bytes_remaining;
1003 XGetWindowProperty (display, window, property,
1004 offset/4, buffer_size/4,
1005 (delete_p ? True : False),
1007 actual_type_ret, actual_format_ret,
1008 actual_size_ret, &bytes_remaining, &tmp_data);
1010 stderr_out ("<< read %d\n", last-bytes_remaining);
1012 /* If this doesn't return Success at this point, it means that
1013 some clod deleted the selection while we were in the midst of
1014 reading it. Deal with that, I guess....
1016 if (result != Success) break;
1017 *actual_size_ret *= *actual_format_ret / 8;
1018 memcpy ((*data_ret) + offset, tmp_data, *actual_size_ret);
1019 offset += *actual_size_ret;
1020 XFree ((char *) tmp_data);
1022 *bytes_ret = offset;
1027 receive_incremental_selection (Display *display, Window window, Atom property,
1028 /* this one is for error messages only */
1029 Lisp_Object target_type,
1030 unsigned int min_size_bytes,
1031 Extbyte **data_ret, int *size_bytes_ret,
1032 Atom *type_ret, int *format_ret,
1033 unsigned long *size_ret)
1035 /* This function can GC */
1038 *size_bytes_ret = min_size_bytes;
1039 *data_ret = (Extbyte *) xmalloc (*size_bytes_ret);
1041 stderr_out ("\nread INCR %d\n", min_size_bytes);
1043 /* At this point, we have read an INCR property, and deleted it (which
1044 is how we ack its receipt: the sending window will be selecting
1045 PropertyNotify events on our window to notice this).
1047 Now, we must loop, waiting for the sending window to put a value on
1048 that property, then reading the property, then deleting it to ack.
1049 We are done when the sender places a property of length 0.
1051 prop_id = expect_property_change (display, window, property,
1057 wait_for_property_change (prop_id);
1058 /* expect it again immediately, because x_get_window_property may
1059 .. no it won't, I don't get it.
1060 .. Ok, I get it now, the Xt code that implements INCR is broken.
1062 prop_id = expect_property_change (display, window, property,
1064 x_get_window_property (display, window, property,
1065 &tmp_data, &tmp_size_bytes,
1066 type_ret, format_ret, size_ret, 1);
1068 if (tmp_size_bytes == 0) /* we're done */
1071 stderr_out (" read INCR done\n");
1073 unexpect_property_change (prop_id);
1074 if (tmp_data) xfree (tmp_data);
1078 stderr_out (" read INCR %d\n", tmp_size_bytes);
1080 if (*size_bytes_ret < offset + tmp_size_bytes)
1083 stderr_out (" read INCR realloc %d -> %d\n",
1084 *size_bytes_ret, offset + tmp_size_bytes);
1086 *size_bytes_ret = offset + tmp_size_bytes;
1087 *data_ret = (Extbyte *) xrealloc (*data_ret, *size_bytes_ret);
1089 memcpy ((*data_ret) + offset, tmp_data, tmp_size_bytes);
1090 offset += tmp_size_bytes;
1097 x_get_window_property_as_lisp_data (Display *display,
1100 /* next two for error messages only */
1101 Lisp_Object target_type,
1102 Atom selection_atom)
1104 /* This function can GC */
1107 unsigned long actual_size;
1108 Extbyte *data = NULL;
1111 struct device *d = get_device_from_display (display);
1113 x_get_window_property (display, window, property, &data, &bytes,
1114 &actual_type, &actual_format, &actual_size, 1);
1117 if (XGetSelectionOwner (display, selection_atom))
1118 /* there is a selection owner */
1120 (Qselection_conversion_error,
1121 Fcons (build_string ("selection owner couldn't convert"),
1122 Fcons (x_atom_to_symbol (d, selection_atom),
1124 list2 (target_type, x_atom_to_symbol (d, actual_type)) :
1125 list1 (target_type))));
1127 signal_error (Qerror,
1128 list2 (build_string ("no selection"),
1129 x_atom_to_symbol (d, selection_atom)));
1132 if (actual_type == DEVICE_XATOM_INCR (d))
1134 /* Ok, that data wasn't *the* data, it was just the beginning. */
1136 unsigned int min_size_bytes = * ((unsigned int *) data);
1138 receive_incremental_selection (display, window, property, target_type,
1139 min_size_bytes, &data, &bytes,
1140 &actual_type, &actual_format,
1144 /* It's been read. Now convert it to a lisp object in some semi-rational
1146 val = selection_data_to_lisp_data (d, data, bytes,
1147 actual_type, actual_format);
1153 /* #### These are going to move into Lisp code(!) with the aid of
1154 some new functions I'm working on - ajh */
1156 /* These functions convert from the selection data read from the server into
1157 something that we can use from elisp, and vice versa.
1159 Type: Format: Size: Elisp Type:
1160 ----- ------- ----- -----------
1163 ATOM 32 > 1 Vector of Symbols
1165 * 16 > 1 Vector of Integers
1166 * 32 1 if <=16 bits: Integer
1167 if > 16 bits: Cons of top16, bot16
1168 * 32 > 1 Vector of the above
1170 When converting a Lisp number to C, it is assumed to be of format 16 if
1171 it is an integer, and of format 32 if it is a cons of two integers.
1173 When converting a vector of numbers from Elisp to C, it is assumed to be
1174 of format 16 if every element in the vector is an integer, and is assumed
1175 to be of format 32 if any element is a cons of two integers.
1177 When converting an object to C, it may be of the form (SYMBOL . <data>)
1178 where SYMBOL is what we should claim that the type is. Format and
1179 representation are as above.
1181 NOTE: Under Mule, when someone shoves us a string without a type, we
1182 set the type to 'COMPOUND_TEXT and automatically convert to Compound
1183 Text. If the string has a type, we assume that the user wants the
1184 data sent as-is so we just do "binary" conversion.
1189 selection_data_to_lisp_data (struct device *d,
1195 if (type == DEVICE_XATOM_NULL (d))
1198 /* Convert any 8-bit data to a string, for compactness. */
1199 else if (format == 8)
1200 return make_ext_string (data, size,
1201 type == DEVICE_XATOM_TEXT (d) ||
1202 type == DEVICE_XATOM_COMPOUND_TEXT (d)
1203 ? Qctext : Qbinary);
1205 /* Convert a single atom to a Lisp Symbol.
1206 Convert a set of atoms to a vector of symbols. */
1207 else if (type == XA_ATOM)
1209 if (size == sizeof (Atom))
1210 return x_atom_to_symbol (d, *((Atom *) data));
1214 int len = size / sizeof (Atom);
1215 Lisp_Object v = Fmake_vector (make_int (len), Qzero);
1216 for (i = 0; i < len; i++)
1217 Faset (v, make_int (i), x_atom_to_symbol (d, ((Atom *) data) [i]));
1222 /* Convert a single 16 or small 32 bit number to a Lisp Int.
1223 If the number is > 16 bits, convert it to a cons of integers,
1224 16 bits in each half.
1226 else if (format == 32 && size == sizeof (long))
1227 return word_to_lisp (((unsigned long *) data) [0]);
1228 else if (format == 16 && size == sizeof (short))
1229 return make_int ((int) (((unsigned short *) data) [0]));
1231 /* Convert any other kind of data to a vector of numbers, represented
1232 as above (as an integer, or a cons of two 16 bit integers).
1234 #### Perhaps we should return the actual type to lisp as well.
1236 (x-get-selection-internal 'PRIMARY 'LINE_NUMBER)
1239 and perhaps it should be
1241 (x-get-selection-internal 'PRIMARY 'LINE_NUMBER)
1244 Right now the fact that the return type was SPAN is discarded before
1245 lisp code gets to see it.
1247 else if (format == 16)
1250 Lisp_Object v = make_vector (size / 4, Qzero);
1251 for (i = 0; i < (int) size / 4; i++)
1253 int j = (int) ((unsigned short *) data) [i];
1254 Faset (v, make_int (i), make_int (j));
1261 Lisp_Object v = make_vector (size / 4, Qzero);
1262 for (i = 0; i < (int) size / 4; i++)
1264 unsigned long j = ((unsigned long *) data) [i];
1265 Faset (v, make_int (i), word_to_lisp (j));
1273 lisp_data_to_selection_data (struct device *d,
1275 unsigned char **data_ret,
1277 unsigned int *size_ret,
1280 Lisp_Object type = Qnil;
1282 if (CONSP (obj) && SYMBOLP (XCAR (obj)))
1286 if (CONSP (obj) && NILP (XCDR (obj)))
1290 if (EQ (obj, QNULL) || (EQ (type, QNULL)))
1291 { /* This is not the same as declining */
1297 else if (STRINGP (obj))
1299 const Extbyte *extval;
1302 TO_EXTERNAL_FORMAT (LISP_STRING, obj,
1303 ALLOCA, (extval, extvallen),
1304 (NILP (type) ? Qctext : Qbinary));
1306 *size_ret = extvallen;
1307 *data_ret = (unsigned char *) xmalloc (*size_ret);
1308 memcpy (*data_ret, extval, *size_ret);
1310 if (NILP (type)) type = QCOMPOUND_TEXT;
1312 if (NILP (type)) type = QSTRING;
1315 else if (CHARP (obj))
1317 Bufbyte buf[MAX_EMCHAR_LEN];
1319 const Extbyte *extval;
1323 len = set_charptr_emchar (buf, XCHAR (obj));
1324 TO_EXTERNAL_FORMAT (DATA, (buf, len),
1325 ALLOCA, (extval, extvallen),
1327 *size_ret = extvallen;
1328 *data_ret = (unsigned char *) xmalloc (*size_ret);
1329 memcpy (*data_ret, extval, *size_ret);
1331 if (NILP (type)) type = QCOMPOUND_TEXT;
1333 if (NILP (type)) type = QSTRING;
1336 else if (SYMBOLP (obj))
1340 *data_ret = (unsigned char *) xmalloc (sizeof (Atom) + 1);
1341 (*data_ret) [sizeof (Atom)] = 0;
1342 (*(Atom **) data_ret) [0] = symbol_to_x_atom (d, obj, 0);
1343 if (NILP (type)) type = QATOM;
1345 else if (INTP (obj) &&
1346 XINT (obj) <= 0x7FFF &&
1347 XINT (obj) >= -0x8000)
1351 *data_ret = (unsigned char *) xmalloc (sizeof (short) + 1);
1352 (*data_ret) [sizeof (short)] = 0;
1353 (*(short **) data_ret) [0] = (short) XINT (obj);
1354 if (NILP (type)) type = QINTEGER;
1356 else if (INTP (obj) || CONSP (obj))
1360 *data_ret = (unsigned char *) xmalloc (sizeof (long) + 1);
1361 (*data_ret) [sizeof (long)] = 0;
1362 (*(unsigned long **) data_ret) [0] = lisp_to_word (obj);
1363 if (NILP (type)) type = QINTEGER;
1365 else if (VECTORP (obj))
1367 /* Lisp Vectors may represent a set of ATOMs;
1368 a set of 16 or 32 bit INTEGERs;
1369 or a set of ATOM_PAIRs (represented as [[A1 A2] [A3 A4] ...]
1373 if (SYMBOLP (XVECTOR_DATA (obj) [0]))
1374 /* This vector is an ATOM set */
1376 if (NILP (type)) type = QATOM;
1377 *size_ret = XVECTOR_LENGTH (obj);
1379 *data_ret = (unsigned char *) xmalloc ((*size_ret) * sizeof (Atom));
1380 for (i = 0; i < (int) (*size_ret); i++)
1381 if (SYMBOLP (XVECTOR_DATA (obj) [i]))
1382 (*(Atom **) data_ret) [i] =
1383 symbol_to_x_atom (d, XVECTOR_DATA (obj) [i], 0);
1385 signal_error (Qerror, /* Qselection_error */
1387 ("all elements of the vector must be of the same type"),
1390 #if 0 /* #### MULTIPLE doesn't work yet */
1391 else if (VECTORP (XVECTOR_DATA (obj) [0]))
1392 /* This vector is an ATOM_PAIR set */
1394 if (NILP (type)) type = QATOM_PAIR;
1395 *size_ret = XVECTOR_LENGTH (obj);
1397 *data_ret = (unsigned char *)
1398 xmalloc ((*size_ret) * sizeof (Atom) * 2);
1399 for (i = 0; i < *size_ret; i++)
1400 if (VECTORP (XVECTOR_DATA (obj) [i]))
1402 Lisp_Object pair = XVECTOR_DATA (obj) [i];
1403 if (XVECTOR_LENGTH (pair) != 2)
1404 signal_error (Qerror,
1406 ("elements of the vector must be vectors of exactly two elements"),
1409 (*(Atom **) data_ret) [i * 2] =
1410 symbol_to_x_atom (d, XVECTOR_DATA (pair) [0], 0);
1411 (*(Atom **) data_ret) [(i * 2) + 1] =
1412 symbol_to_x_atom (d, XVECTOR_DATA (pair) [1], 0);
1415 signal_error (Qerror,
1417 ("all elements of the vector must be of the same type"),
1422 /* This vector is an INTEGER set, or something like it */
1424 *size_ret = XVECTOR_LENGTH (obj);
1425 if (NILP (type)) type = QINTEGER;
1427 for (i = 0; i < (int) (*size_ret); i++)
1428 if (CONSP (XVECTOR_DATA (obj) [i]))
1430 else if (!INTP (XVECTOR_DATA (obj) [i]))
1431 signal_error (Qerror, /* Qselection_error */
1433 ("all elements of the vector must be integers or conses of integers"),
1436 *data_ret = (unsigned char *) xmalloc (*size_ret * (*format_ret/8));
1437 for (i = 0; i < (int) (*size_ret); i++)
1438 if (*format_ret == 32)
1439 (*((unsigned long **) data_ret)) [i] =
1440 lisp_to_word (XVECTOR_DATA (obj) [i]);
1442 (*((unsigned short **) data_ret)) [i] =
1443 (unsigned short) lisp_to_word (XVECTOR_DATA (obj) [i]);
1447 signal_error (Qerror, /* Qselection_error */
1448 list2 (build_string ("unrecognized selection data"),
1451 *type_ret = symbol_to_x_atom (d, type, 0);
1456 /* Called from the event loop to handle SelectionNotify events.
1457 I don't think this needs to be reentrant.
1460 x_handle_selection_notify (XSelectionEvent *event)
1462 if (! reading_selection_reply)
1463 message ("received an unexpected SelectionNotify event");
1464 else if (event->requestor != reading_selection_reply)
1465 message ("received a SelectionNotify event for the wrong window");
1466 else if (event->selection != reading_which_selection)
1467 message ("received the wrong selection type in SelectionNotify!");
1469 reading_selection_reply = 0; /* we're done now. */
1473 x_disown_selection (Lisp_Object selection, Lisp_Object timeval)
1475 struct device *d = decode_x_device (Qnil);
1476 Display *display = DEVICE_X_DISPLAY (d);
1478 Atom selection_atom;
1480 CHECK_SYMBOL (selection);
1482 timestamp = DEVICE_X_MOUSE_TIMESTAMP (d);
1485 /* #### This is bogus. See the comment above about problems
1486 on OSF/1 and DEC Alphas. Yet another reason why it sucks
1487 to have the implementation (i.e. cons of two 16-bit
1488 integers) exposed. */
1490 lisp_to_time (timeval, &the_time);
1491 timestamp = (Time) the_time;
1494 selection_atom = symbol_to_x_atom (d, selection, 0);
1496 XSetSelectionOwner (display, selection_atom, None, timestamp);
1500 x_selection_exists_p (Lisp_Object selection,
1501 Lisp_Object selection_type)
1503 struct device *d = decode_x_device (Qnil);
1504 Display *dpy = DEVICE_X_DISPLAY (d);
1505 return XGetSelectionOwner (dpy, symbol_to_x_atom (d, selection, 0)) != None ?
1510 #ifdef CUT_BUFFER_SUPPORT
1512 static int cut_buffers_initialized; /* Whether we're sure they all exist */
1514 /* Ensure that all 8 cut buffers exist. ICCCM says we gotta... */
1516 initialize_cut_buffers (Display *display, Window window)
1518 static unsigned const char * const data = (unsigned const char *) "";
1519 #define FROB(atom) XChangeProperty (display, window, atom, XA_STRING, 8, \
1520 PropModeAppend, data, 0)
1521 FROB (XA_CUT_BUFFER0);
1522 FROB (XA_CUT_BUFFER1);
1523 FROB (XA_CUT_BUFFER2);
1524 FROB (XA_CUT_BUFFER3);
1525 FROB (XA_CUT_BUFFER4);
1526 FROB (XA_CUT_BUFFER5);
1527 FROB (XA_CUT_BUFFER6);
1528 FROB (XA_CUT_BUFFER7);
1530 cut_buffers_initialized = 1;
1533 #define CHECK_CUTBUFFER(symbol) do { \
1534 CHECK_SYMBOL (symbol); \
1535 if (! (EQ (symbol, QCUT_BUFFER0) || \
1536 EQ (symbol, QCUT_BUFFER1) || \
1537 EQ (symbol, QCUT_BUFFER2) || \
1538 EQ (symbol, QCUT_BUFFER3) || \
1539 EQ (symbol, QCUT_BUFFER4) || \
1540 EQ (symbol, QCUT_BUFFER5) || \
1541 EQ (symbol, QCUT_BUFFER6) || \
1542 EQ (symbol, QCUT_BUFFER7))) \
1543 signal_simple_error ("Doesn't name a cutbuffer", symbol); \
1546 DEFUN ("x-get-cutbuffer-internal", Fx_get_cutbuffer_internal, 1, 1, 0, /*
1547 Return the value of the named CUTBUFFER (typically CUT_BUFFER0).
1551 struct device *d = decode_x_device (Qnil);
1552 Display *display = DEVICE_X_DISPLAY (d);
1553 Window window = RootWindow (display, 0); /* Cutbuffers are on frame 0 */
1554 Atom cut_buffer_atom;
1562 CHECK_CUTBUFFER (cutbuffer);
1563 cut_buffer_atom = symbol_to_x_atom (d, cutbuffer, 0);
1565 x_get_window_property (display, window, cut_buffer_atom, &data, &bytes,
1566 &type, &format, &size, 0);
1567 if (!data) return Qnil;
1569 if (format != 8 || type != XA_STRING)
1570 signal_simple_error_2 ("Cut buffer doesn't contain 8-bit STRING data",
1571 x_atom_to_symbol (d, type),
1574 /* We cheat - if the string contains an ESC character, that's
1575 technically not allowed in a STRING, so we assume it's
1576 COMPOUND_TEXT that we stored there ourselves earlier,
1577 in x-store-cutbuffer-internal */
1579 make_ext_string (data, bytes,
1580 memchr (data, 0x1b, bytes) ?
1588 DEFUN ("x-store-cutbuffer-internal", Fx_store_cutbuffer_internal, 2, 2, 0, /*
1589 Set the value of the named CUTBUFFER (typically CUT_BUFFER0) to STRING.
1591 (cutbuffer, string))
1593 struct device *d = decode_x_device (Qnil);
1594 Display *display = DEVICE_X_DISPLAY (d);
1595 Window window = RootWindow (display, 0); /* Cutbuffers are on frame 0 */
1596 Atom cut_buffer_atom;
1597 const Bufbyte *data = XSTRING_DATA (string);
1598 Bytecount bytes = XSTRING_LENGTH (string);
1599 Bytecount bytes_remaining;
1600 int max_bytes = SELECTION_QUANTUM (display);
1602 const Bufbyte *ptr, *end;
1603 enum { ASCII, LATIN_1, WORLD } chartypes = ASCII;
1606 if (max_bytes > MAX_SELECTION_QUANTUM)
1607 max_bytes = MAX_SELECTION_QUANTUM;
1609 CHECK_CUTBUFFER (cutbuffer);
1610 CHECK_STRING (string);
1611 cut_buffer_atom = symbol_to_x_atom (d, cutbuffer, 0);
1613 if (! cut_buffers_initialized)
1614 initialize_cut_buffers (display, window);
1616 /* We use the STRING encoding (Latin-1 only) if we can, else COMPOUND_TEXT.
1617 We cheat and use type = `STRING' even when using COMPOUND_TEXT.
1618 The ICCCM requires that this be so, and other clients assume it,
1619 as we do ourselves in initialize_cut_buffers. */
1622 /* Optimize for the common ASCII case */
1623 for (ptr = data, end = ptr + bytes; ptr <= end; )
1625 if (BYTE_ASCII_P (*ptr))
1634 chartypes = LATIN_1;
1639 if ((*ptr) == LEADING_BYTE_LATIN_ISO8859_1 ||
1640 (*ptr) == LEADING_BYTE_CONTROL_1)
1642 chartypes = LATIN_1;
1652 if (chartypes == LATIN_1)
1653 TO_EXTERNAL_FORMAT (LISP_STRING, string,
1654 ALLOCA, (data, bytes),
1656 else if (chartypes == WORLD)
1657 TO_EXTERNAL_FORMAT (LISP_STRING, string,
1658 ALLOCA, (data, bytes),
1662 bytes_remaining = bytes;
1664 while (bytes_remaining)
1666 int chunk = bytes_remaining < max_bytes ? bytes_remaining : max_bytes;
1667 XChangeProperty (display, window, cut_buffer_atom, XA_STRING, 8,
1668 (bytes_remaining == bytes
1669 ? PropModeReplace : PropModeAppend),
1672 bytes_remaining -= chunk;
1678 DEFUN ("x-rotate-cutbuffers-internal", Fx_rotate_cutbuffers_internal, 1, 1, 0, /*
1679 Rotate the values of the cutbuffers by the given number of steps;
1680 positive means move values forward, negative means backward.
1684 struct device *d = decode_x_device (Qnil);
1685 Display *display = DEVICE_X_DISPLAY (d);
1686 Window window = RootWindow (display, 0); /* Cutbuffers are on frame 0 */
1692 if (! cut_buffers_initialized)
1693 initialize_cut_buffers (display, window);
1694 props[0] = XA_CUT_BUFFER0;
1695 props[1] = XA_CUT_BUFFER1;
1696 props[2] = XA_CUT_BUFFER2;
1697 props[3] = XA_CUT_BUFFER3;
1698 props[4] = XA_CUT_BUFFER4;
1699 props[5] = XA_CUT_BUFFER5;
1700 props[6] = XA_CUT_BUFFER6;
1701 props[7] = XA_CUT_BUFFER7;
1702 XRotateWindowProperties (display, window, props, 8, XINT (n));
1706 #endif /* CUT_BUFFER_SUPPORT */
1710 /************************************************************************/
1711 /* initialization */
1712 /************************************************************************/
1715 syms_of_select_x (void)
1718 #ifdef CUT_BUFFER_SUPPORT
1719 DEFSUBR (Fx_get_cutbuffer_internal);
1720 DEFSUBR (Fx_store_cutbuffer_internal);
1721 DEFSUBR (Fx_rotate_cutbuffers_internal);
1722 #endif /* CUT_BUFFER_SUPPORT */
1724 /* Unfortunately, timeout handlers must be lisp functions. */
1725 defsymbol (&Qx_selection_reply_timeout_internal,
1726 "x-selection-reply-timeout-internal");
1727 DEFSUBR (Fx_selection_reply_timeout_internal);
1729 #ifdef CUT_BUFFER_SUPPORT
1730 defsymbol (&QCUT_BUFFER0, "CUT_BUFFER0");
1731 defsymbol (&QCUT_BUFFER1, "CUT_BUFFER1");
1732 defsymbol (&QCUT_BUFFER2, "CUT_BUFFER2");
1733 defsymbol (&QCUT_BUFFER3, "CUT_BUFFER3");
1734 defsymbol (&QCUT_BUFFER4, "CUT_BUFFER4");
1735 defsymbol (&QCUT_BUFFER5, "CUT_BUFFER5");
1736 defsymbol (&QCUT_BUFFER6, "CUT_BUFFER6");
1737 defsymbol (&QCUT_BUFFER7, "CUT_BUFFER7");
1738 #endif /* CUT_BUFFER_SUPPORT */
1742 console_type_create_select_x (void)
1744 CONSOLE_HAS_METHOD (x, own_selection);
1745 CONSOLE_HAS_METHOD (x, disown_selection);
1746 CONSOLE_HAS_METHOD (x, get_foreign_selection);
1747 CONSOLE_HAS_METHOD (x, selection_exists_p);
1751 reinit_vars_of_select_x (void)
1753 reading_selection_reply = 0;
1754 reading_which_selection = 0;
1755 selection_reply_timed_out = 0;
1756 for_whom_the_bell_tolls = 0;
1757 prop_location_tick = 0;
1761 vars_of_select_x (void)
1763 reinit_vars_of_select_x ();
1765 #ifdef CUT_BUFFER_SUPPORT
1766 cut_buffers_initialized = 0;
1767 Fprovide (intern ("cut-buffer"));
1770 DEFVAR_LISP ("x-sent-selection-hooks", &Vx_sent_selection_hooks /*
1771 A function or functions to be called after we have responded to some
1772 other client's request for the value of a selection that we own. The
1773 function(s) will be called with four arguments:
1774 - the name of the selection (typically PRIMARY, SECONDARY, or CLIPBOARD);
1775 - the name of the selection-type which we were requested to convert the
1776 selection into before sending (for example, STRING or LENGTH);
1777 - and whether we successfully transmitted the selection.
1778 We might have failed (and declined the request) for any number of reasons,
1779 including being asked for a selection that we no longer own, or being asked
1780 to convert into a type that we don't know about or that is inappropriate.
1781 This hook doesn't let you change the behavior of emacs's selection replies,
1782 it merely informs you that they have happened.
1784 Vx_sent_selection_hooks = Qunbound;
1786 DEFVAR_INT ("x-selection-timeout", &x_selection_timeout /*
1787 If the selection owner doesn't reply in this many seconds, we give up.
1788 A value of 0 means wait as long as necessary. This is initialized from the
1789 \"*selectionTimeout\" resource (which is expressed in milliseconds).
1791 x_selection_timeout = 0;
1793 DEFVAR_BOOL ("x-selection-strict-motif-ownership", &x_selection_strict_motif_ownership /*
1794 *If nil and XEmacs already owns the clipboard, don't own it again in the
1795 Motif way. Owning the selection on the Motif way does a huge amount of
1796 X protocol, and it makes killing text incredibly slow when using an
1797 X terminal. However, when enabled Motif text fields don't bother to look up
1798 the new value, and you can't Copy from a buffer, Paste into a text
1799 field, then Copy something else from the buffer and paste it into the
1800 text field; it pastes the first thing again.
1802 x_selection_strict_motif_ownership = 1;
1806 Xatoms_of_select_x (struct device *d)
1808 Display *D = DEVICE_X_DISPLAY (d);
1810 /* Non-predefined atoms that we might end up using a lot */
1811 DEVICE_XATOM_CLIPBOARD (d) = XInternAtom (D, "CLIPBOARD", False);
1812 DEVICE_XATOM_TIMESTAMP (d) = XInternAtom (D, "TIMESTAMP", False);
1813 DEVICE_XATOM_TEXT (d) = XInternAtom (D, "TEXT", False);
1814 DEVICE_XATOM_DELETE (d) = XInternAtom (D, "DELETE", False);
1815 DEVICE_XATOM_MULTIPLE (d) = XInternAtom (D, "MULTIPLE", False);
1816 DEVICE_XATOM_INCR (d) = XInternAtom (D, "INCR", False);
1817 DEVICE_XATOM_TARGETS (d) = XInternAtom (D, "TARGETS", False);
1818 DEVICE_XATOM_NULL (d) = XInternAtom (D, "NULL", False);
1819 DEVICE_XATOM_ATOM_PAIR (d) = XInternAtom (D, "ATOM_PAIR", False);
1820 DEVICE_XATOM_COMPOUND_TEXT (d) = XInternAtom (D, "COMPOUND_TEXT", False);
1822 /* #### I don't like the looks of this... what is it for? - ajh */
1823 DEVICE_XATOM_EMACS_TMP (d) = XInternAtom (D, "_EMACS_TMP_", False);