Mercurial > emacs
annotate src/=xselect.c.old @ 1245:f8a5da3d18e8
Use frame-width instead of screen-width.
author | Richard M. Stallman <rms@gnu.org> |
---|---|
date | Mon, 28 Sep 1992 13:02:35 +0000 |
parents | a411429c4140 |
children | 39c6e9d28de2 |
rev | line source |
---|---|
159 | 1 /* X Selection processing for emacs |
648 | 2 Copyright (C) 1990, 1992 Free Software Foundation. |
159 | 3 |
4 This file is part of GNU Emacs. | |
5 | |
6 GNU Emacs is free software; you can redistribute it and/or modify | |
7 it under the terms of the GNU General Public License as published by | |
648 | 8 the Free Software Foundation; either version 2, or (at your option) |
159 | 9 any later version. |
10 | |
11 GNU Emacs is distributed in the hope that it will be useful, | |
12 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 GNU General Public License for more details. | |
15 | |
16 You should have received a copy of the GNU General Public License | |
17 along with GNU Emacs; see the file COPYING. If not, write to | |
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
19 | |
20 #include "config.h" | |
21 #include "lisp.h" | |
22 #include "xterm.h" | |
641 | 23 #include "buffer.h" |
771 | 24 #include "frame.h" |
159 | 25 |
26 #ifdef HAVE_X11 | |
27 | |
28 /* Macros for X Selections */ | |
641 | 29 #define MAX_SELECTION(dpy) (((dpy)->max_request_size << 2) - 100) |
30 #define SELECTION_LENGTH(len,format) ((len) * ((format) >> 2)) | |
159 | 31 |
708 | 32 /* The timestamp of the last input event we received from the X server. */ |
33 unsigned long last_event_timestamp; | |
648 | 34 |
159 | 35 /* t if a mouse button is depressed. */ |
36 extern Lisp_Object Vmouse_grabbed; | |
37 | |
38 /* When emacs became the PRIMARY selection owner. */ | |
39 Time x_begin_selection_own; | |
40 | |
641 | 41 /* When emacs became the SECONDARY selection owner. */ |
42 Time x_begin_secondary_selection_own; | |
43 | |
159 | 44 /* When emacs became the CLIPBOARD selection owner. */ |
45 Time x_begin_clipboard_own; | |
46 | |
47 /* The value of the current CLIPBOARD selection. */ | |
48 Lisp_Object Vx_clipboard_value; | |
49 | |
50 /* The value of the current PRIMARY selection. */ | |
51 Lisp_Object Vx_selection_value; | |
52 | |
641 | 53 /* The value of the current SECONDARY selection. */ |
54 Lisp_Object Vx_secondary_selection_value; | |
55 | |
708 | 56 /* Types of selections we may make. Note that Qcut_buffer0 isn't really |
57 a selection, but it acts like one for the sake of Fx_own_selection and | |
58 Fx_selection_value. */ | |
59 Lisp_Object Qprimary, Qsecondary, Qclipboard, Qcut_buffer0; | |
641 | 60 |
61 /* Emacs' selection property identifiers. */ | |
159 | 62 Atom Xatom_emacs_selection; |
641 | 63 Atom Xatom_emacs_secondary_selection; |
159 | 64 |
65 /* Clipboard selection atom. */ | |
66 Atom Xatom_clipboard_selection; | |
67 | |
68 /* Clipboard atom. */ | |
69 Atom Xatom_clipboard; | |
70 | |
71 /* Atom for indicating incremental selection transfer. */ | |
72 Atom Xatom_incremental; | |
73 | |
74 /* Atom for indicating multiple selection request list */ | |
75 Atom Xatom_multiple; | |
76 | |
77 /* Atom for what targets emacs handles. */ | |
78 Atom Xatom_targets; | |
79 | |
80 /* Atom for indicating timstamp selection request */ | |
81 Atom Xatom_timestamp; | |
82 | |
83 /* Atom requesting we delete our selection. */ | |
84 Atom Xatom_delete; | |
85 | |
86 /* Selection magic. */ | |
87 Atom Xatom_insert_selection; | |
88 | |
89 /* Type of property for INSERT_SELECTION. */ | |
90 Atom Xatom_pair; | |
91 | |
92 /* More selection magic. */ | |
93 Atom Xatom_insert_property; | |
94 | |
95 /* Atom for indicating property type TEXT */ | |
96 Atom Xatom_text; | |
97 | |
641 | 98 /* Kinds of protocol things we may receive. */ |
99 Atom Xatom_wm_take_focus; | |
100 Atom Xatom_wm_save_yourself; | |
101 Atom Xatom_wm_delete_window; | |
102 | |
103 /* Communication with window managers. */ | |
104 Atom Xatom_wm_protocols; | |
105 | |
159 | 106 /* These are to handle incremental selection transfer. */ |
107 Window incr_requestor; | |
108 Atom incr_property; | |
109 int incr_nbytes; | |
110 unsigned char *incr_value; | |
111 unsigned char *incr_ptr; | |
112 | |
113 /* SELECTION OWNER CODE */ | |
114 | |
641 | 115 |
116 /* Request selection ownership if we do not already have it. */ | |
117 | |
118 static int | |
119 own_selection (selection_type, time) | |
120 Atom selection_type; | |
121 Time time; | |
122 { | |
123 Window owner_window, selecting_window; | |
124 | |
125 if ((EQ (selection_type, Qprimary) && !NILP (Vx_selection_value)) | |
126 || ((EQ (selection_type, Qsecondary)) && !NILP (Vx_secondary_selection_value)) | |
127 || ((EQ (selection_type, Qclipboard)) && !NILP (Vx_clipboard_value))) | |
128 return 1; | |
129 | |
1053
a411429c4140
* xselect.c: Use the FRAME_X_WINDOW macro, for readability.
Jim Blandy <jimb@redhat.com>
parents:
847
diff
changeset
|
130 selecting_window = FRAME_X_WINDOW (selected_frame); |
641 | 131 XSetSelectionOwner (x_current_display, selection_type, |
132 selecting_window, time); | |
133 owner_window = XGetSelectionOwner (x_current_display, selection_type); | |
134 | |
648 | 135 if (owner_window != selecting_window) |
641 | 136 return 0; |
137 | |
138 return 1; | |
139 } | |
140 | |
159 | 141 /* Become the selection owner and make our data the selection value. |
142 If we are already the owner, merely change data and timestamp values. | |
143 This avoids generating SelectionClear events for ourselves. */ | |
144 | |
145 DEFUN ("x-own-selection", Fx_own_selection, Sx_own_selection, | |
641 | 146 1, 2, "", |
147 "Make STRING the selection value. Default is the primary selection,\n\ | |
708 | 148 but optional second argument TYPE may specify secondary or clipboard.\n\ |
149 \n\ | |
150 TYPE may also be cut-buffer0, indicating that Emacs should set the X\n\ | |
151 cut buffer 0 to STRING. This is for compatibility with older X\n\ | |
152 applications which still use the cut buffers; new applications should\n\ | |
153 use X selections.") | |
641 | 154 (string, type) |
155 register Lisp_Object string, type; | |
159 | 156 { |
641 | 157 Atom selection_type; |
158 Lisp_Object val; | |
708 | 159 Time event_time = last_event_timestamp; |
159 | 160 CHECK_STRING (string, 0); |
161 | |
839 | 162 val = Qnil; |
163 | |
641 | 164 if (NILP (type) || EQ (type, Qprimary)) |
159 | 165 { |
641 | 166 BLOCK_INPUT; |
167 if (own_selection (XA_PRIMARY, event_time)) | |
168 { | |
169 x_begin_selection_own = event_time; | |
170 val = Vx_selection_value = string; | |
171 } | |
708 | 172 UNBLOCK_INPUT; |
641 | 173 } |
174 else if (EQ (type, Qsecondary)) | |
175 { | |
176 BLOCK_INPUT; | |
177 if (own_selection (XA_SECONDARY, event_time)) | |
159 | 178 { |
641 | 179 x_begin_secondary_selection_own = event_time; |
180 val = Vx_secondary_selection_value = string; | |
159 | 181 } |
641 | 182 UNBLOCK_INPUT; |
159 | 183 } |
641 | 184 else if (EQ (type, Qclipboard)) |
185 { | |
186 BLOCK_INPUT; | |
187 if (own_selection (Xatom_clipboard, event_time)) | |
188 { | |
708 | 189 x_begin_clipboard_own = event_time; |
641 | 190 val = Vx_clipboard_value = string; |
191 } | |
708 | 192 UNBLOCK_INPUT; |
193 } | |
194 else if (EQ (type, Qcut_buffer0)) | |
195 { | |
847 | 196 /* DECwindows and some other servers don't seem to like setting |
197 properties to values larger than about 20k. For very large | |
198 values, they signal an error, but for intermediate values | |
199 they just seem to hang. | |
200 | |
201 We could just truncate the request, but it's better to let | |
202 the user know that the strategy he/she's using isn't going to | |
203 work than to have it work partially, but incorrectly. */ | |
708 | 204 BLOCK_INPUT; |
847 | 205 if (XSTRING (string)->size > MAX_SELECTION (x_current_display)) |
206 { | |
207 XStoreBytes (x_current_display, (char *) 0, 0); | |
208 val = Qnil; | |
209 } | |
210 else | |
211 { | |
212 XStoreBytes (x_current_display, | |
213 (char *) XSTRING (string)->data, | |
214 XSTRING (string)->size); | |
215 val = string; | |
216 } | |
708 | 217 UNBLOCK_INPUT; |
641 | 218 } |
219 else | |
220 error ("Invalid X selection type"); | |
159 | 221 |
641 | 222 return val; |
159 | 223 } |
224 | |
225 /* Clear our selection ownership data, as some other client has | |
226 become the owner. */ | |
227 | |
228 void | |
229 x_disown_selection (old_owner, selection, changed_owner_time) | |
230 Window *old_owner; | |
231 Atom selection; | |
232 Time changed_owner_time; | |
233 { | |
771 | 234 struct frame *s = x_window_to_frame (old_owner); |
159 | 235 |
236 if (s) /* We are the owner */ | |
237 { | |
238 if (selection == XA_PRIMARY) | |
239 { | |
240 x_begin_selection_own = 0; | |
241 Vx_selection_value = Qnil; | |
242 } | |
641 | 243 else if (selection == XA_SECONDARY) |
244 { | |
245 x_begin_secondary_selection_own = 0; | |
246 Vx_secondary_selection_value = Qnil; | |
247 } | |
159 | 248 else if (selection == Xatom_clipboard) |
249 { | |
250 x_begin_clipboard_own = 0; | |
251 Vx_clipboard_value = Qnil; | |
252 } | |
253 else | |
254 abort (); | |
255 } | |
256 else | |
257 abort (); /* Inconsistent state. */ | |
258 } | |
259 | |
260 int x_selection_alloc_error; | |
261 int x_converting_selection; | |
262 | |
263 /* Reply to some client's request for our selection data. Data is | |
708 | 264 placed in a property supplied by the requesting window. |
159 | 265 |
266 If the data exceeds the maximum amount the server can send, | |
267 then prepare to send it incrementally, and reply to the client with | |
268 the total size of the data. | |
269 | |
270 But first, check for all the other crufty stuff we could get. */ | |
271 | |
272 void | |
273 x_answer_selection_request (event) | |
274 XSelectionRequestEvent event; | |
275 { | |
276 Time emacs_own_time; | |
277 Lisp_Object selection_value; | |
278 XSelectionEvent evt; | |
279 int format = 8; /* We have only byte sized (text) data. */ | |
280 | |
281 evt.type = SelectionNotify; /* Construct reply event */ | |
282 evt.display = event.display; | |
283 evt.requestor = event.requestor; | |
284 evt.selection = event.selection; | |
285 evt.time = event.time; | |
286 evt.target = event.target; | |
287 | |
288 if (event.selection == XA_PRIMARY) | |
289 { | |
290 emacs_own_time = x_begin_selection_own; | |
291 selection_value = Vx_selection_value; | |
292 } | |
641 | 293 else if (event.selection == XA_SECONDARY) |
294 { | |
295 emacs_own_time = x_begin_secondary_selection_own; | |
296 selection_value = Vx_secondary_selection_value; | |
297 } | |
159 | 298 else if (event.selection == Xatom_clipboard) |
299 { | |
300 emacs_own_time = x_begin_clipboard_own; | |
301 selection_value = Vx_clipboard_value; | |
302 } | |
303 else | |
304 abort (); | |
305 | |
306 if (event.time != CurrentTime | |
307 && event.time < emacs_own_time) | |
308 evt.property = None; | |
309 else | |
310 { | |
311 if (event.property == None) /* obsolete client */ | |
312 evt.property = event.target; | |
313 else | |
314 evt.property = event.property; | |
315 } | |
316 | |
317 if (event.target == Xatom_targets) /* Send List of target atoms */ | |
318 { | |
319 } | |
320 else if (event.target == Xatom_multiple) /* Recvd list: <target, prop> */ | |
321 { | |
322 Atom type; | |
323 int return_format; | |
324 unsigned long items, bytes_left; | |
325 unsigned char *data; | |
326 int result, i; | |
327 | |
641 | 328 if (event.property == 0 /* 0 == NILP */ |
159 | 329 || event.property == None) |
330 return; | |
331 | |
332 result = XGetWindowProperty (event.display, event.requestor, | |
333 event.property, 0L, 10000000L, | |
334 True, Xatom_pair, &type, &return_format, | |
335 &items, &bytes_left, &data); | |
336 | |
337 if (result == Success && type == Xatom_pair) | |
338 for (i = items; i > 0; i--) | |
339 { | |
340 /* Convert each element of the list. */ | |
341 } | |
342 | |
343 (void) XSendEvent (x_current_display, evt.requestor, False, | |
344 0L, (XEvent *) &evt); | |
345 return; | |
346 } | |
347 else if (event.target == Xatom_timestamp) /* Send ownership timestamp */ | |
348 { | |
349 if (! emacs_own_time) | |
350 abort (); | |
351 | |
352 format = 32; | |
353 XChangeProperty (evt.display, evt.requestor, evt.property, | |
354 evt.target, format, PropModeReplace, | |
641 | 355 (unsigned char *) &emacs_own_time, 1); |
159 | 356 return; |
357 } | |
358 else if (event.target == Xatom_delete) /* Delete our selection. */ | |
359 { | |
360 if (EQ (Qnil, selection_value)) | |
361 abort (); | |
362 | |
363 x_disown_selection (event.owner, event.selection, event.time); | |
364 | |
641 | 365 /* Now return property of type NILP, length 0. */ |
159 | 366 XChangeProperty (event.display, event.requestor, event.property, |
367 0, format, PropModeReplace, (unsigned char *) 0, 0); | |
368 return; | |
369 } | |
370 else if (event.target == Xatom_insert_selection) | |
371 { | |
372 Atom type; | |
373 int return_format; | |
374 unsigned long items, bytes_left; | |
375 unsigned char *data; | |
376 int result = XGetWindowProperty (event.display, event.requestor, | |
377 event.property, 0L, 10000000L, | |
378 True, Xatom_pair, &type, &return_format, | |
379 &items, &bytes_left, &data); | |
380 if (result == Success && type == Xatom_pair) | |
381 { | |
382 /* Convert the first atom to (a selection) to the target | |
383 indicated by the second atom. */ | |
384 } | |
385 } | |
386 else if (event.target == Xatom_insert_property) | |
387 { | |
388 Atom type; | |
389 int return_format; | |
390 unsigned long items, bytes_left; | |
391 unsigned char *data; | |
392 int result = XGetWindowProperty (event.display, event.requestor, | |
393 event.property, 0L, 10000000L, | |
394 True, XA_STRING, &type, &return_format, | |
395 &items, &bytes_left, &data); | |
396 | |
397 if (result == Success && type == XA_STRING && return_format == 8) | |
398 { | |
399 if (event.selection == Xatom_emacs_selection) | |
400 Vx_selection_value = make_string (data); | |
641 | 401 else if (event.selection == Xatom_emacs_secondary_selection) |
402 Vx_secondary_selection_value = make_string (data); | |
159 | 403 else if (event.selection == Xatom_clipboard_selection) |
404 Vx_clipboard_value = make_string (data); | |
405 else | |
406 abort (); | |
407 } | |
408 | |
409 return; | |
410 } | |
411 else if ((event.target == Xatom_text | |
412 || event.target == XA_STRING)) | |
413 { | |
414 int size = XSTRING (selection_value)->size; | |
415 unsigned char *data = XSTRING (selection_value)->data; | |
416 | |
417 if (EQ (Qnil, selection_value)) | |
418 abort (); | |
419 | |
420 /* Place data on requestor window's property. */ | |
421 if (SELECTION_LENGTH (size, format) | |
422 <= MAX_SELECTION (x_current_display)) | |
423 { | |
424 x_converting_selection = 1; | |
425 XChangeProperty (evt.display, evt.requestor, evt.property, | |
426 evt.target, format, PropModeReplace, | |
427 data, size); | |
428 if (x_selection_alloc_error) | |
429 { | |
430 x_selection_alloc_error = 0; | |
431 abort (); | |
432 } | |
433 x_converting_selection = 0; | |
434 } | |
435 else /* Send incrementally */ | |
436 { | |
437 evt.target = Xatom_incremental; | |
438 incr_requestor = evt.requestor; | |
439 incr_property = evt.property; | |
440 x_converting_selection = 1; | |
441 | |
442 /* Need to handle Alloc errors on these requests. */ | |
443 XChangeProperty (evt.display, incr_requestor, incr_property, | |
444 Xatom_incremental, 32, | |
445 PropModeReplace, | |
446 (unsigned char *) &size, 1); | |
447 if (x_selection_alloc_error) | |
448 { | |
449 x_selection_alloc_error = 0; | |
450 x_converting_selection = 0; | |
451 abort (); | |
452 /* Now abort the send. */ | |
453 } | |
454 | |
455 incr_nbytes = size; | |
456 incr_value = data; | |
457 incr_ptr = data; | |
458 | |
459 /* Ask for notification when requestor deletes property. */ | |
460 XSelectInput (x_current_display, incr_requestor, PropertyChangeMask); | |
461 | |
462 /* If we're sending incrementally, perhaps block here | |
463 until all sent? */ | |
464 } | |
465 } | |
466 else | |
467 evt.property = None; | |
468 | |
469 /* Don't do this if there was an Alloc error: abort the transfer | |
470 by sending None. */ | |
471 (void) XSendEvent (x_current_display, evt.requestor, False, | |
472 0L, (XEvent *) &evt); | |
473 } | |
474 | |
475 /* Send an increment of selection data in response to a PropertyNotify event. | |
476 The increment is placed in a property on the requestor's window. | |
477 When the requestor has processed the increment, it deletes the property, | |
478 which sends us another PropertyNotify event. | |
479 | |
480 When there is no more data to send, we send a zero-length increment. */ | |
481 | |
482 void | |
483 x_send_incremental (event) | |
484 XPropertyEvent event; | |
485 { | |
486 if (incr_requestor | |
487 && incr_requestor == event.window | |
488 && incr_property == event.atom | |
489 && event.state == PropertyDelete) | |
490 { | |
491 int format = 8; | |
492 int length = MAX_SELECTION (x_current_display); | |
493 int bytes_left = (incr_nbytes - (incr_ptr - incr_value)); | |
494 | |
495 if (length > bytes_left) /* Also sends 0 len when finished. */ | |
496 length = bytes_left; | |
497 XChangeProperty (x_current_display, incr_requestor, | |
498 incr_property, XA_STRING, format, | |
499 PropModeAppend, incr_ptr, length); | |
500 if (x_selection_alloc_error) | |
501 { | |
502 x_selection_alloc_error = 0; | |
503 x_converting_selection = 0; | |
504 /* Abandon the transmission. */ | |
505 abort (); | |
506 } | |
507 if (length > 0) | |
508 incr_ptr += length; | |
509 else | |
510 { /* Everything's sent */ | |
511 XSelectInput (x_current_display, incr_requestor, 0L); | |
512 incr_requestor = (Window) 0; | |
513 incr_property = (Atom) 0; | |
514 incr_nbytes = 0; | |
515 incr_value = (unsigned char *) 0; | |
516 incr_ptr = (unsigned char *) 0; | |
517 x_converting_selection = 0; | |
518 } | |
519 } | |
520 } | |
521 | |
522 /* SELECTION REQUESTOR CODE */ | |
523 | |
524 /* Predicate function used to match a requested event. */ | |
525 | |
526 Bool | |
527 XCheckSelectionEvent (dpy, event, window) | |
528 Display *dpy; | |
529 XEvent *event; | |
530 char *window; | |
531 { | |
532 if (event->type == SelectionNotify) | |
533 if (event->xselection.requestor == (Window) window) | |
534 return True; | |
535 | |
536 return False; | |
537 } | |
538 | |
641 | 539 /* Request a selection value from its owner. This will block until |
540 all the data is arrived. */ | |
159 | 541 |
641 | 542 static Lisp_Object |
543 get_selection_value (type) | |
544 Atom type; | |
159 | 545 { |
546 XEvent event; | |
547 Lisp_Object val; | |
548 Time requestor_time; /* Timestamp of selection request. */ | |
549 Window requestor_window; | |
550 | |
551 BLOCK_INPUT; | |
708 | 552 requestor_time = last_event_timestamp; |
1053
a411429c4140
* xselect.c: Use the FRAME_X_WINDOW macro, for readability.
Jim Blandy <jimb@redhat.com>
parents:
847
diff
changeset
|
553 requestor_window = FRAME_X_WINDOW (selected_frame); |
641 | 554 XConvertSelection (x_current_display, type, XA_STRING, |
159 | 555 Xatom_emacs_selection, requestor_window, requestor_time); |
556 XIfEvent (x_current_display, | |
557 &event, | |
558 XCheckSelectionEvent, | |
559 (char *) requestor_window); | |
560 val = x_selection_arrival (&event, requestor_window, requestor_time); | |
561 UNBLOCK_INPUT; | |
562 | |
563 return val; | |
564 } | |
565 | |
641 | 566 /* Request a selection value from the owner. If we are the owner, |
567 simply return our selection value. If we are not the owner, this | |
568 will block until all of the data has arrived. */ | |
159 | 569 |
641 | 570 DEFUN ("x-selection-value", Fx_selection_value, Sx_selection_value, |
571 0, 1, "", | |
572 "Return the value of one of the selections. Default is the primary\n\ | |
573 selection, but optional argument TYPE may specify secondary or clipboard.") | |
574 (type) | |
575 register Lisp_Object type; | |
159 | 576 { |
641 | 577 Atom selection_type; |
578 | |
579 if (NILP (type) || EQ (type, Qprimary)) | |
580 { | |
581 if (!NILP (Vx_selection_value)) | |
648 | 582 return Vx_selection_value; |
159 | 583 |
641 | 584 return get_selection_value (XA_PRIMARY); |
585 } | |
586 else if (EQ (type, Qsecondary)) | |
587 { | |
588 if (!NILP (Vx_secondary_selection_value)) | |
589 return Vx_secondary_selection_value; | |
159 | 590 |
641 | 591 return get_selection_value (XA_SECONDARY); |
592 } | |
593 else if (EQ (type, Qclipboard)) | |
594 { | |
595 if (!NILP (Vx_clipboard_value)) | |
596 return Vx_clipboard_value; | |
159 | 597 |
641 | 598 return get_selection_value (Xatom_clipboard); |
599 } | |
708 | 600 else if (EQ (type, Qcut_buffer0)) |
601 { | |
602 char *data; | |
603 int size; | |
604 Lisp_Object string; | |
605 | |
606 BLOCK_INPUT; | |
607 data = XFetchBytes (x_current_display, &size); | |
608 if (data == 0) | |
609 string = Qnil; | |
610 else | |
611 string = make_string (data, size); | |
612 UNBLOCK_INPUT; | |
613 | |
614 return string; | |
615 } | |
641 | 616 else |
617 error ("Invalid X selection type"); | |
159 | 618 } |
619 | |
620 Lisp_Object | |
621 x_selection_arrival (event, requestor_window, requestor_time) | |
622 register XSelectionEvent *event; | |
623 Window requestor_window; | |
624 Time requestor_time; | |
625 { | |
626 int result; | |
627 Atom type, selection; | |
628 int format; | |
629 unsigned long items; | |
630 unsigned long bytes_left; | |
631 unsigned char *data = 0; | |
632 int offset = 0; | |
633 | |
634 if (event->selection == XA_PRIMARY) | |
635 selection = Xatom_emacs_selection; | |
641 | 636 else if (event->selection == XA_SECONDARY) |
637 selection = Xatom_emacs_secondary_selection; | |
159 | 638 else if (event->selection == Xatom_clipboard) |
639 selection = Xatom_clipboard_selection; | |
640 else | |
641 abort (); | |
642 | |
643 if (event->requestor == requestor_window | |
644 && event->time == requestor_time | |
645 && event->property != None) | |
646 if (event->target != Xatom_incremental) | |
647 { | |
648 unsigned char *return_string = | |
649 (unsigned char *) alloca (MAX_SELECTION (x_current_display)); | |
650 | |
651 do | |
652 { | |
641 | 653 result = XGetWindowProperty (x_current_display, requestor_window, |
159 | 654 event->property, 0L, |
655 10000000L, True, XA_STRING, | |
656 &type, &format, &items, | |
657 &bytes_left, &data); | |
658 if (result == Success && type == XA_STRING && format == 8 | |
659 && offset < MAX_SELECTION (x_current_display)) | |
660 { | |
661 bcopy (data, return_string + offset, items); | |
662 offset += items; | |
663 } | |
664 XFree ((char *) data); | |
665 } | |
666 while (bytes_left); | |
667 | |
668 return make_string (return_string, offset); | |
669 } | |
670 else /* Prepare incremental transfer. */ | |
671 { | |
672 unsigned char *increment_value; | |
673 unsigned char *increment_ptr; | |
674 int total_size; | |
675 int *increment_nbytes = 0; | |
676 | |
677 result = XGetWindowProperty (x_current_display, requestor_window, | |
678 selection, 0L, 10000000L, False, | |
679 event->property, &type, &format, | |
680 &items, &bytes_left, | |
681 (unsigned char **) &increment_nbytes); | |
682 if (result == Success) | |
683 { | |
684 XPropertyEvent property_event; | |
685 | |
686 total_size = *increment_nbytes; | |
687 increment_value = (unsigned char *) alloca (total_size); | |
688 increment_ptr = increment_value; | |
689 | |
690 XDeleteProperty (x_current_display, event->requestor, | |
691 event->property); | |
692 XFlush (x_current_display); | |
693 XFree ((char *) increment_nbytes); | |
694 | |
695 do | |
696 { /* NOTE: this blocks. */ | |
697 XWindowEvent (x_current_display, requestor_window, | |
698 PropertyChangeMask, | |
699 (XEvent *) &property_event); | |
700 | |
701 if (property_event.atom == selection | |
702 && property_event.state == PropertyNewValue) | |
703 do | |
704 { | |
705 result = XGetWindowProperty (x_current_display, | |
706 requestor_window, | |
707 selection, 0L, | |
708 10000000L, True, | |
709 AnyPropertyType, | |
710 &type, &format, | |
711 &items, &bytes_left, | |
712 &data); | |
713 if (result == Success && type == XA_STRING | |
714 && format == 8) | |
715 { | |
716 bcopy (data, increment_ptr, items); | |
717 increment_ptr += items; | |
718 } | |
719 } | |
720 while (bytes_left); | |
721 | |
722 } | |
723 while (increment_ptr < (increment_value + total_size)); | |
724 | |
725 return make_string (increment_value, | |
726 (increment_ptr - increment_value)); | |
727 } | |
728 } | |
729 | |
730 return Qnil; | |
731 } | |
732 | |
733 void | |
734 syms_of_xselect () | |
735 { | |
736 DEFVAR_LISP ("x-selection-value", &Vx_selection_value, | |
737 "The value of emacs' last cut-string."); | |
738 Vx_selection_value = Qnil; | |
739 | |
641 | 740 DEFVAR_LISP ("x-secondary-selection-value", &Vx_secondary_selection_value, |
741 "The value of emacs' last secondary cut-string."); | |
742 Vx_secondary_selection_value = Qnil; | |
743 | |
159 | 744 DEFVAR_LISP ("x-clipboard-value", &Vx_clipboard_value, |
745 "The string emacs last sent to the clipboard."); | |
746 Vx_clipboard_value = Qnil; | |
747 | |
641 | 748 Qprimary = intern ("primary"); |
749 staticpro (&Qprimary); | |
750 Qsecondary = intern ("secondary"); | |
751 staticpro (&Qsecondary); | |
752 Qclipboard = intern ("clipboard"); | |
753 staticpro (&Qclipboard); | |
708 | 754 Qcut_buffer0 = intern ("cut-buffer0"); |
755 staticpro (&Qcut_buffer0); | |
641 | 756 |
159 | 757 defsubr (&Sx_own_selection); |
641 | 758 defsubr (&Sx_selection_value); |
159 | 759 } |
760 #endif /* X11 */ |