aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorChong Yidong2011-05-26 13:42:32 -0400
committerChong Yidong2011-05-26 13:42:32 -0400
commite067f0c10d0c717d7505d3ccd44bc2f906af7180 (patch)
tree18917237d1fcedb1d90e495cf286e8bd5cca19dc /src
parent2d3ba9e768fe3b96c5ea98c900677bed1ccdeffe (diff)
downloademacs-e067f0c10d0c717d7505d3ccd44bc2f906af7180.tar.gz
emacs-e067f0c10d0c717d7505d3ccd44bc2f906af7180.zip
* src/xselect.c: ICCCM-compliant handling of MULTIPLE targets.
(converted_selections, conversion_fail_tag): New global variables. (x_selection_request_lisp_error): Free the above. (x_get_local_selection): Remove unnecessary code. (x_reply_selection_request): Args changed; handle arbitrary array of converted selections stored in converted_selections. Separate the XChangeProperty and SelectionNotify steps. (x_handle_selection_request): Rewrite to handle MULTIPLE target. (x_convert_selection): New function. (x_handle_selection_event): Simplify. (x_get_foreign_selection): Don't ignore incoming requests while waiting for an answer; this will fail when we implement SAVE_TARGETS, and seems unnecessary anyway. (selection_data_to_lisp_data): Recognize ATOM_PAIR type. (Vx_sent_selection_functions): Doc fix.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog18
-rw-r--r--src/xselect.c654
2 files changed, 329 insertions, 343 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index c4f5ef4b920..85ea8a86e7b 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,21 @@
12011-05-26 Chong Yidong <cyd@stupidchicken.com>
2
3 * xselect.c: ICCCM-compliant handling of MULTIPLE targets.
4 (converted_selections, conversion_fail_tag): New global variables.
5 (x_selection_request_lisp_error): Free the above.
6 (x_get_local_selection): Remove unnecessary code.
7 (x_reply_selection_request): Args changed; handle arbitrary array
8 of converted selections stored in converted_selections. Separate
9 the XChangeProperty and SelectionNotify steps.
10 (x_handle_selection_request): Rewrite to handle MULTIPLE target.
11 (x_convert_selection): New function.
12 (x_handle_selection_event): Simplify.
13 (x_get_foreign_selection): Don't ignore incoming requests while
14 waiting for an answer; this will fail when we implement
15 SAVE_TARGETS, and seems unnecessary anyway.
16 (selection_data_to_lisp_data): Recognize ATOM_PAIR type.
17 (Vx_sent_selection_functions): Doc fix.
18
12011-05-26 Leo Liu <sdl.web@gmail.com> 192011-05-26 Leo Liu <sdl.web@gmail.com>
2 20
3 * editfns.c (Ftranspose_regions): Allow empty regions. (Bug#8699) 21 * editfns.c (Ftranspose_regions): Allow empty regions. (Bug#8699)
diff --git a/src/xselect.c b/src/xselect.c
index c4e9fbf9ff7..4c9a402e36e 100644
--- a/src/xselect.c
+++ b/src/xselect.c
@@ -43,6 +43,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
43#include <X11/Xproto.h> 43#include <X11/Xproto.h>
44 44
45struct prop_location; 45struct prop_location;
46struct selection_data;
46 47
47static Lisp_Object x_atom_to_symbol (Display *dpy, Atom atom); 48static Lisp_Object x_atom_to_symbol (Display *dpy, Atom atom);
48static Atom symbol_to_x_atom (struct x_display_info *, Display *, 49static Atom symbol_to_x_atom (struct x_display_info *, Display *,
@@ -54,8 +55,9 @@ static Lisp_Object x_selection_request_lisp_error (Lisp_Object);
54static Lisp_Object queue_selection_requests_unwind (Lisp_Object); 55static Lisp_Object queue_selection_requests_unwind (Lisp_Object);
55static Lisp_Object some_frame_on_display (struct x_display_info *); 56static Lisp_Object some_frame_on_display (struct x_display_info *);
56static Lisp_Object x_catch_errors_unwind (Lisp_Object); 57static Lisp_Object x_catch_errors_unwind (Lisp_Object);
57static void x_reply_selection_request (struct input_event *, int, 58static void x_reply_selection_request (struct input_event *, struct x_display_info *);
58 unsigned char *, int, Atom); 59static int x_convert_selection (struct input_event *, Lisp_Object, Lisp_Object,
60 Atom, int);
59static int waiting_for_other_props_on_window (Display *, Window); 61static int waiting_for_other_props_on_window (Display *, Window);
60static struct prop_location *expect_property_change (Display *, Window, 62static struct prop_location *expect_property_change (Display *, Window,
61 Atom, int); 63 Atom, int);
@@ -401,32 +403,6 @@ x_get_local_selection (Lisp_Object selection_symbol, Lisp_Object target_type, in
401 handler_fn = Qnil; 403 handler_fn = Qnil;
402 value = XCAR (XCDR (XCDR (local_value))); 404 value = XCAR (XCDR (XCDR (local_value)));
403 } 405 }
404#if 0 /* #### MULTIPLE doesn't work yet */
405 else if (CONSP (target_type)
406 && XCAR (target_type) == QMULTIPLE)
407 {
408 Lisp_Object pairs;
409 int size;
410 int i;
411 pairs = XCDR (target_type);
412 size = ASIZE (pairs);
413 /* If the target is MULTIPLE, then target_type looks like
414 (MULTIPLE . [[SELECTION1 TARGET1] [SELECTION2 TARGET2] ... ])
415 We modify the second element of each pair in the vector and
416 return it as [[SELECTION1 <value1>] [SELECTION2 <value2>] ... ]
417 */
418 for (i = 0; i < size; i++)
419 {
420 Lisp_Object pair;
421 pair = XVECTOR (pairs)->contents [i];
422 XVECTOR (pair)->contents [1]
423 = x_get_local_selection (XVECTOR (pair)->contents [0],
424 XVECTOR (pair)->contents [1],
425 local_request);
426 }
427 return pairs;
428 }
429#endif
430 else 406 else
431 { 407 {
432 /* Don't allow a quit within the converter. 408 /* Don't allow a quit within the converter.
@@ -514,6 +490,30 @@ static struct input_event *x_selection_current_request;
514 490
515static struct x_display_info *selection_request_dpyinfo; 491static struct x_display_info *selection_request_dpyinfo;
516 492
493/* Raw selection data, for sending to a requestor window. */
494
495struct selection_data
496{
497 unsigned char *data;
498 unsigned int size;
499 int format;
500 Atom type;
501 int nofree;
502 Atom property;
503 /* This can be set to non-NULL during x_reply_selection_request, if
504 the selection is waiting for an INCR transfer to complete. Don't
505 free these; that's done by unexpect_property_change. */
506 struct prop_location *wait_object;
507 struct selection_data *next;
508};
509
510/* Linked list of the above (in support of MULTIPLE targets). */
511
512struct selection_data *converted_selections;
513
514/* "Data" to send a requestor for a failed MULTIPLE subtarget. */
515Atom conversion_fail_tag;
516
517/* Used as an unwind-protect clause so that, if a selection-converter signals 517/* Used as an unwind-protect clause so that, if a selection-converter signals
518 an error, we tell the requester that we were unable to do what they wanted 518 an error, we tell the requester that we were unable to do what they wanted
519 before we throw to top-level or go into the debugger or whatever. */ 519 before we throw to top-level or go into the debugger or whatever. */
@@ -521,6 +521,17 @@ static struct x_display_info *selection_request_dpyinfo;
521static Lisp_Object 521static Lisp_Object
522x_selection_request_lisp_error (Lisp_Object ignore) 522x_selection_request_lisp_error (Lisp_Object ignore)
523{ 523{
524 struct selection_data *cs, *next;
525
526 for (cs = converted_selections; cs; cs = next)
527 {
528 next = cs->next;
529 if (cs->nofree == 0 && cs->data)
530 xfree (cs->data);
531 xfree (cs);
532 }
533 converted_selections = NULL;
534
524 if (x_selection_current_request != 0 535 if (x_selection_current_request != 0
525 && selection_request_dpyinfo->display) 536 && selection_request_dpyinfo->display)
526 x_decline_selection_request (x_selection_current_request); 537 x_decline_selection_request (x_selection_current_request);
@@ -592,27 +603,23 @@ some_frame_on_display (struct x_display_info *dpyinfo)
592 return Qnil; 603 return Qnil;
593} 604}
594 605
595/* Send the reply to a selection request event EVENT. 606/* Send the reply to a selection request event EVENT. */
596 TYPE is the type of selection data requested.
597 DATA and SIZE describe the data to send, already converted.
598 FORMAT is the unit-size (in bits) of the data to be transmitted. */
599 607
600#ifdef TRACE_SELECTION 608#ifdef TRACE_SELECTION
601static int x_reply_selection_request_cnt; 609static int x_reply_selection_request_cnt;
602#endif /* TRACE_SELECTION */ 610#endif /* TRACE_SELECTION */
603 611
604static void 612static void
605x_reply_selection_request (struct input_event *event, int format, unsigned char *data, int size, Atom type) 613x_reply_selection_request (struct input_event *event, struct x_display_info *dpyinfo)
606{ 614{
607 XEvent reply_base; 615 XEvent reply_base;
608 XSelectionEvent *reply = &(reply_base.xselection); 616 XSelectionEvent *reply = &(reply_base.xselection);
609 Display *display = SELECTION_EVENT_DISPLAY (event); 617 Display *display = SELECTION_EVENT_DISPLAY (event);
610 Window window = SELECTION_EVENT_REQUESTOR (event); 618 Window window = SELECTION_EVENT_REQUESTOR (event);
611 int bytes_remaining; 619 int bytes_remaining;
612 int format_bytes = format/8;
613 int max_bytes = SELECTION_QUANTUM (display); 620 int max_bytes = SELECTION_QUANTUM (display);
614 struct x_display_info *dpyinfo = x_display_info_for_display (display);
615 int count = SPECPDL_INDEX (); 621 int count = SPECPDL_INDEX ();
622 struct selection_data *cs;
616 623
617 if (max_bytes > MAX_SELECTION_QUANTUM) 624 if (max_bytes > MAX_SELECTION_QUANTUM)
618 max_bytes = MAX_SELECTION_QUANTUM; 625 max_bytes = MAX_SELECTION_QUANTUM;
@@ -634,142 +641,132 @@ x_reply_selection_request (struct input_event *event, int format, unsigned char
634 record_unwind_protect (x_catch_errors_unwind, Qnil); 641 record_unwind_protect (x_catch_errors_unwind, Qnil);
635 x_catch_errors (display); 642 x_catch_errors (display);
636 643
644 /* Loop over converted selections, storing them in the requested
645 properties. If data is large, only store the first N bytes
646 (section 2.7.2 of ICCCM). Note that we store the data for a
647 MULTIPLE request in the opposite order; the ICCM says only that
648 the conversion itself must be done in the same order. */
649 for (cs = converted_selections; cs; cs = cs->next)
650 {
651 if (cs->property != None)
652 {
653 bytes_remaining = cs->size * (cs->format / 8);
654 if (bytes_remaining <= max_bytes)
655 {
656 /* Send all the data at once, with minimal handshaking. */
657 TRACE1 ("Sending all %d bytes", bytes_remaining);
658 XChangeProperty (display, window, cs->property,
659 cs->type, cs->format, PropModeReplace,
660 cs->data, cs->size);
661 }
662 else
663 {
664 /* Send an INCR tag to initiate incremental transfer. */
665 long value[1];
666
667 TRACE2 ("Start sending %d bytes incrementally (%s)",
668 bytes_remaining, XGetAtomName (display, cs->property));
669 cs->wait_object
670 = expect_property_change (display, window, cs->property,
671 PropertyDelete);
672
673 /* XChangeProperty expects an array of long even if long
674 is more than 32 bits. */
675 value[0] = bytes_remaining;
676 XChangeProperty (display, window, cs->property,
677 dpyinfo->Xatom_INCR, 32, PropModeReplace,
678 (unsigned char *) value, 1);
679 XSelectInput (display, window, PropertyChangeMask);
680 }
681 }
682 }
683
684 /* Now issue the SelectionNotify event. */
685 XSendEvent (display, window, False, 0L, &reply_base);
686 XFlush (display);
687
637#ifdef TRACE_SELECTION 688#ifdef TRACE_SELECTION
638 { 689 {
639 char *sel = XGetAtomName (display, reply->selection); 690 char *sel = XGetAtomName (display, reply->selection);
640 char *tgt = XGetAtomName (display, reply->target); 691 char *tgt = XGetAtomName (display, reply->target);
641 TRACE3 ("%s, target %s (%d)", sel, tgt, ++x_reply_selection_request_cnt); 692 TRACE3 ("Sent SelectionNotify: %s, target %s (%d)",
693 sel, tgt, ++x_reply_selection_request_cnt);
642 if (sel) XFree (sel); 694 if (sel) XFree (sel);
643 if (tgt) XFree (tgt); 695 if (tgt) XFree (tgt);
644 } 696 }
645#endif /* TRACE_SELECTION */ 697#endif /* TRACE_SELECTION */
646 698
647 /* Store the data on the requested property. 699 /* Finish sending the rest of each of the INCR values. This should
648 If the selection is large, only store the first N bytes of it. 700 be improved; there's a chance of deadlock if more than one
649 */ 701 subtarget in a MULTIPLE selection requires an INCR transfer, and
650 bytes_remaining = size * format_bytes; 702 the requestor and Emacs loop waiting on different transfers. */
651 if (bytes_remaining <= max_bytes) 703 for (cs = converted_selections; cs; cs = cs->next)
652 { 704 if (cs->wait_object)
653 /* Send all the data at once, with minimal handshaking. */
654 TRACE1 ("Sending all %d bytes", bytes_remaining);
655 XChangeProperty (display, window, reply->property, type, format,
656 PropModeReplace, data, size);
657 /* At this point, the selection was successfully stored; ack it. */
658 XSendEvent (display, window, False, 0L, &reply_base);
659 }
660 else
661 {
662 /* Send an INCR selection. */
663 struct prop_location *wait_object;
664 int had_errors;
665 Lisp_Object frame;
666
667 frame = some_frame_on_display (dpyinfo);
668
669 /* If the display no longer has frames, we can't expect
670 to get many more selection requests from it, so don't
671 bother trying to queue them. */
672 if (!NILP (frame))
673 {
674 x_start_queuing_selection_requests ();
675
676 record_unwind_protect (queue_selection_requests_unwind,
677 Qnil);
678 }
679
680 if (x_window_to_frame (dpyinfo, window)) /* #### debug */
681 error ("Attempt to transfer an INCR to ourself!");
682
683 TRACE2 ("Start sending %d bytes incrementally (%s)",
684 bytes_remaining, XGetAtomName (display, reply->property));
685 wait_object = expect_property_change (display, window, reply->property,
686 PropertyDelete);
687
688 TRACE1 ("Set %s to number of bytes to send",
689 XGetAtomName (display, reply->property));
690 { 705 {
691 /* XChangeProperty expects an array of long even if long is more than 706 int format_bytes = cs->format / 8;
692 32 bits. */ 707 int had_errors = x_had_errors_p (display);
693 long value[1]; 708 UNBLOCK_INPUT;
694
695 value[0] = bytes_remaining;
696 XChangeProperty (display, window, reply->property, dpyinfo->Xatom_INCR,
697 32, PropModeReplace,
698 (unsigned char *) value, 1);
699 }
700
701 XSelectInput (display, window, PropertyChangeMask);
702 709
703 /* Tell 'em the INCR data is there... */ 710 bytes_remaining = cs->size * format_bytes;
704 TRACE0 ("Send SelectionNotify event");
705 XSendEvent (display, window, False, 0L, &reply_base);
706 XFlush (display);
707
708 had_errors = x_had_errors_p (display);
709 UNBLOCK_INPUT;
710 711
711 /* First, wait for the requester to ack by deleting the property. 712 /* Wait for the requester to ack by deleting the property.
712 This can run random lisp code (process handlers) or signal. */ 713 This can run Lisp code (process handlers) or signal. */
713 if (! had_errors) 714 if (! had_errors)
714 { 715 {
715 TRACE1 ("Waiting for ACK (deletion of %s)", 716 TRACE1 ("Waiting for ACK (deletion of %s)",
716 XGetAtomName (display, reply->property)); 717 XGetAtomName (display, cs->property));
717 wait_for_property_change (wait_object); 718 wait_for_property_change (cs->wait_object);
718 } 719 }
719 else 720 else
720 unexpect_property_change (wait_object); 721 unexpect_property_change (cs->wait_object);
721 722
722 TRACE0 ("Got ACK"); 723 while (bytes_remaining)
723 while (bytes_remaining) 724 {
724 { 725 int i = ((bytes_remaining < max_bytes)
725 int i = ((bytes_remaining < max_bytes) 726 ? bytes_remaining
726 ? bytes_remaining 727 : max_bytes) / format_bytes;
727 : max_bytes) / format_bytes; 728 BLOCK_INPUT;
728 729
729 BLOCK_INPUT; 730 cs->wait_object
730 731 = expect_property_change (display, window, cs->property,
731 wait_object 732 PropertyDelete);
732 = expect_property_change (display, window, reply->property, 733
733 PropertyDelete); 734 TRACE1 ("Sending increment of %d elements", i);
734 735 TRACE1 ("Set %s to increment data",
735 TRACE1 ("Sending increment of %d elements", i); 736 XGetAtomName (display, cs->property));
736 TRACE1 ("Set %s to increment data", 737
737 XGetAtomName (display, reply->property)); 738 /* Append the next chunk of data to the property. */
738 739 XChangeProperty (display, window, cs->property,
739 /* Append the next chunk of data to the property. */ 740 cs->type, cs->format, PropModeAppend,
740 XChangeProperty (display, window, reply->property, type, format, 741 cs->data, i);
741 PropModeAppend, data, i); 742 bytes_remaining -= i * format_bytes;
742 bytes_remaining -= i * format_bytes; 743 cs->data += i * ((cs->format == 32) ? sizeof (long) : format_bytes);
743 if (format == 32) 744 XFlush (display);
744 data += i * sizeof (long); 745 had_errors = x_had_errors_p (display);
745 else 746 UNBLOCK_INPUT;
746 data += i * format_bytes;
747 XFlush (display);
748 had_errors = x_had_errors_p (display);
749 UNBLOCK_INPUT;
750 747
751 if (had_errors) 748 if (had_errors) break;
752 break;
753 749
754 /* Now wait for the requester to ack this chunk by deleting the 750 /* Wait for the requester to ack this chunk by deleting
755 property. This can run random lisp code or signal. */ 751 the property. This can run Lisp code or signal. */
756 TRACE1 ("Waiting for increment ACK (deletion of %s)", 752 TRACE1 ("Waiting for increment ACK (deletion of %s)",
757 XGetAtomName (display, reply->property)); 753 XGetAtomName (display, cs->property));
758 wait_for_property_change (wait_object); 754 wait_for_property_change (cs->wait_object);
759 } 755 }
760 756
761 /* Now write a zero-length chunk to the property to tell the 757 /* Now write a zero-length chunk to the property to tell the
762 requester that we're done. */ 758 requester that we're done. */
763 BLOCK_INPUT; 759 BLOCK_INPUT;
764 if (! waiting_for_other_props_on_window (display, window)) 760 if (! waiting_for_other_props_on_window (display, window))
765 XSelectInput (display, window, 0L); 761 XSelectInput (display, window, 0L);
766 762
767 TRACE1 ("Set %s to a 0-length chunk to indicate EOF", 763 TRACE1 ("Set %s to a 0-length chunk to indicate EOF",
768 XGetAtomName (display, reply->property)); 764 XGetAtomName (display, cs->property));
769 XChangeProperty (display, window, reply->property, type, format, 765 XChangeProperty (display, window, cs->property,
770 PropModeReplace, data, 0); 766 cs->type, cs->format, PropModeReplace,
771 TRACE0 ("Done sending incrementally"); 767 cs->data, 0);
772 } 768 TRACE0 ("Done sending incrementally");
769 }
773 770
774 /* rms, 2003-01-03: I think I have fixed this bug. */ 771 /* rms, 2003-01-03: I think I have fixed this bug. */
775 /* The window we're communicating with may have been deleted 772 /* The window we're communicating with may have been deleted
@@ -798,117 +795,165 @@ x_reply_selection_request (struct input_event *event, int format, unsigned char
798static void 795static void
799x_handle_selection_request (struct input_event *event) 796x_handle_selection_request (struct input_event *event)
800{ 797{
801 struct gcpro gcpro1, gcpro2, gcpro3; 798 struct gcpro gcpro1, gcpro2;
802 Lisp_Object local_selection_data;
803 Lisp_Object selection_symbol;
804 Lisp_Object target_symbol;
805 Lisp_Object converted_selection;
806 Time local_selection_time; 799 Time local_selection_time;
807 Lisp_Object successful_p; 800
808 int count; 801 Display *display = SELECTION_EVENT_DISPLAY (event);
809 struct x_display_info *dpyinfo 802 struct x_display_info *dpyinfo = x_display_info_for_display (display);
810 = x_display_info_for_display (SELECTION_EVENT_DISPLAY (event)); 803
804 Atom selection = SELECTION_EVENT_SELECTION (event);
805 Lisp_Object selection_symbol = x_atom_to_symbol (display, selection);
806 Atom target = SELECTION_EVENT_TARGET (event);
807 Lisp_Object target_symbol = x_atom_to_symbol (display, target);
808 Atom property = SELECTION_EVENT_PROPERTY (event);
809 Lisp_Object local_selection_data
810 = assq_no_quit (selection_symbol, Vselection_alist);
811 int success = 0;
812 int count = SPECPDL_INDEX ();
811 813
812 TRACE2 ("x_handle_selection_request, from=0x%08lx time=%lu", 814 TRACE2 ("x_handle_selection_request, from=0x%08lx time=%lu",
813 (unsigned long) SELECTION_EVENT_REQUESTOR (event), 815 (unsigned long) SELECTION_EVENT_REQUESTOR (event),
814 (unsigned long) SELECTION_EVENT_TIME (event)); 816 (unsigned long) SELECTION_EVENT_TIME (event));
815 817
816 local_selection_data = Qnil; 818 GCPRO2 (local_selection_data, target_symbol);
817 target_symbol = Qnil;
818 converted_selection = Qnil;
819 successful_p = Qnil;
820
821 GCPRO3 (local_selection_data, converted_selection, target_symbol);
822
823 selection_symbol = x_atom_to_symbol (SELECTION_EVENT_DISPLAY (event),
824 SELECTION_EVENT_SELECTION (event));
825
826 local_selection_data = assq_no_quit (selection_symbol, Vselection_alist);
827 819
828 if (NILP (local_selection_data)) 820 /* Decline if we don't own any selections. */
829 { 821 if (NILP (local_selection_data)) goto DONE;
830 /* Someone asked for the selection, but we don't have it any more.
831 */
832 x_decline_selection_request (event);
833 goto DONE;
834 }
835
836 local_selection_time = (Time)
837 cons_to_long (XCAR (XCDR (XCDR (local_selection_data))));
838 822
823 /* Decline requests issued prior to our acquiring the selection. */
824 local_selection_time
825 = (Time) cons_to_long (XCAR (XCDR (XCDR (local_selection_data))));
839 if (SELECTION_EVENT_TIME (event) != CurrentTime 826 if (SELECTION_EVENT_TIME (event) != CurrentTime
840 && local_selection_time > SELECTION_EVENT_TIME (event)) 827 && local_selection_time > SELECTION_EVENT_TIME (event))
841 { 828 goto DONE;
842 /* Someone asked for the selection, and we have one, but not the one
843 they're looking for.
844 */
845 x_decline_selection_request (event);
846 goto DONE;
847 }
848 829
849 x_selection_current_request = event; 830 x_selection_current_request = event;
850 count = SPECPDL_INDEX ();
851 selection_request_dpyinfo = dpyinfo; 831 selection_request_dpyinfo = dpyinfo;
852 record_unwind_protect (x_selection_request_lisp_error, Qnil); 832 record_unwind_protect (x_selection_request_lisp_error, Qnil);
853 833
854 target_symbol = x_atom_to_symbol (SELECTION_EVENT_DISPLAY (event), 834 /* We might be able to handle nested x_handle_selection_requests,
855 SELECTION_EVENT_TARGET (event)); 835 but this is difficult to test, and seems unimportant. */
836 x_start_queuing_selection_requests ();
837 record_unwind_protect (queue_selection_requests_unwind, Qnil);
856 838
857#if 0 /* #### MULTIPLE doesn't work yet */
858 if (EQ (target_symbol, QMULTIPLE)) 839 if (EQ (target_symbol, QMULTIPLE))
859 target_symbol = fetch_multiple_target (event); 840 {
860#endif 841 /* For MULTIPLE targets, the event property names a list of atom
842 pairs; the first atom names a target and the second names a
843 non-None property. */
844 Window requestor = SELECTION_EVENT_REQUESTOR (event);
845 Lisp_Object multprop;
846 int j, nselections;
847
848 if (property == None) goto DONE;
849 multprop = x_get_window_property_as_lisp_data (display, requestor, property,
850 QMULTIPLE, selection);
851
852 if (!VECTORP (multprop) || !(ASIZE (multprop) % 2))
853 goto DONE;
854
855 nselections = ASIZE (multprop) / 2;
856 /* Perform conversions. This can signal. */
857 for (j = 0; j < nselections; j++)
858 {
859 struct selection_data *cs = converted_selections + j;
860 Lisp_Object subtarget = AREF (multprop, 2*j);
861 Atom subproperty = symbol_to_x_atom (dpyinfo, display,
862 AREF (multprop, 2*j+1));
863
864 if (subproperty != None)
865 x_convert_selection (event, selection_symbol, subtarget,
866 subproperty, 1);
867 }
868 success = 1;
869 }
870 else
871 {
872 if (property == None)
873 property = SELECTION_EVENT_TARGET (event);
874 success = x_convert_selection (event, selection_symbol,
875 target_symbol, property, 0);
876 }
861 877
862 /* Convert lisp objects back into binary data */ 878 DONE:
863 879
864 converted_selection 880 if (success)
865 = x_get_local_selection (selection_symbol, target_symbol, 0); 881 x_reply_selection_request (event, dpyinfo);
882 else
883 x_decline_selection_request (event);
884 x_selection_current_request = 0;
866 885
867 if (! NILP (converted_selection)) 886 /* Run the `x-sent-selection-functions' abnormal hook. */
887 if (!NILP (Vx_sent_selection_functions)
888 && !EQ (Vx_sent_selection_functions, Qunbound))
868 { 889 {
869 unsigned char *data; 890 Lisp_Object args[4];
870 unsigned int size; 891 args[0] = Vx_sent_selection_functions;
871 int format; 892 args[1] = selection_symbol;
872 Atom type; 893 args[2] = target_symbol;
873 int nofree; 894 args[3] = success ? Qt : Qnil;
874 895 Frun_hook_with_args (4, args);
875 if (CONSP (converted_selection) && NILP (XCDR (converted_selection))) 896 }
876 {
877 x_decline_selection_request (event);
878 goto DONE2;
879 }
880 897
881 lisp_data_to_selection_data (SELECTION_EVENT_DISPLAY (event), 898 unbind_to (count, Qnil);
882 converted_selection, 899 UNGCPRO;
883 &data, &type, &size, &format, &nofree); 900}
884 901
885 x_reply_selection_request (event, format, data, size, type); 902/* Perform the requested selection conversion, and write the data to
886 successful_p = Qt; 903 the converted_selections linked list, where it can be accessed by
904 x_reply_selection_request. If FOR_MULTIPLE is non-zero, write out
905 the data even if conversion fails, using conversion_fail_tag.
887 906
888 /* Indicate we have successfully processed this event. */ 907 Return 0 if the selection failed to convert, 1 otherwise. */
889 x_selection_current_request = 0;
890 908
891 /* Use xfree, not XFree, because lisp_data_to_selection_data 909static int
892 calls xmalloc itself. */ 910x_convert_selection (struct input_event *event,
893 if (!nofree) 911 Lisp_Object selection_symbol,
894 xfree (data); 912 Lisp_Object target_symbol,
895 } 913 Atom property, int for_multiple)
914{
915 struct gcpro gcpro1;
916 Lisp_Object lisp_selection;
917 struct selection_data *cs;
918 GCPRO1 (lisp_selection);
896 919
897 DONE2: 920 lisp_selection
898 unbind_to (count, Qnil); 921 = x_get_local_selection (selection_symbol, target_symbol, 0);
899 922
900 DONE: 923 /* A nil return value means we can't perform the conversion. */
924 if (NILP (lisp_selection)
925 || (CONSP (lisp_selection) && NILP (XCDR (lisp_selection))))
926 {
927 if (for_multiple)
928 {
929 cs = xmalloc (sizeof (struct selection_data));
930 cs->data = (unsigned char *) &conversion_fail_tag;
931 cs->size = 1;
932 cs->format = 32;
933 cs->type = XA_ATOM;
934 cs->nofree = 1;
935 cs->property = property;
936 cs->wait_object = NULL;
937 cs->next = converted_selections;
938 converted_selections = cs;
939 }
901 940
902 /* Let random lisp code notice that the selection has been asked for. */ 941 RETURN_UNGCPRO (0);
903 { 942 }
904 Lisp_Object rest;
905 rest = Vx_sent_selection_functions;
906 if (!EQ (rest, Qunbound))
907 for (; CONSP (rest); rest = Fcdr (rest))
908 call3 (Fcar (rest), selection_symbol, target_symbol, successful_p);
909 }
910 943
911 UNGCPRO; 944 /* Otherwise, record the converted selection to binary. */
945 cs = xmalloc (sizeof (struct selection_data));
946 cs->nofree = 1;
947 cs->property = property;
948 cs->wait_object = NULL;
949 cs->next = converted_selections;
950 converted_selections = cs;
951 lisp_data_to_selection_data (SELECTION_EVENT_DISPLAY (event),
952 lisp_selection,
953 &(cs->data), &(cs->type),
954 &(cs->size), &(cs->format),
955 &(cs->nofree));
956 RETURN_UNGCPRO (1);
912} 957}
913 958
914/* Handle a SelectionClear event EVENT, which indicates that some 959/* Handle a SelectionClear event EVENT, which indicates that some
@@ -1001,16 +1046,12 @@ void
1001x_handle_selection_event (struct input_event *event) 1046x_handle_selection_event (struct input_event *event)
1002{ 1047{
1003 TRACE0 ("x_handle_selection_event"); 1048 TRACE0 ("x_handle_selection_event");
1004 1049 if (event->kind != SELECTION_REQUEST_EVENT)
1005 if (event->kind == SELECTION_REQUEST_EVENT)
1006 {
1007 if (x_queue_selection_requests)
1008 x_queue_event (event);
1009 else
1010 x_handle_selection_request (event);
1011 }
1012 else
1013 x_handle_selection_clear (event); 1050 x_handle_selection_clear (event);
1051 else if (x_queue_selection_requests)
1052 x_queue_event (event);
1053 else
1054 x_handle_selection_request (event);
1014} 1055}
1015 1056
1016 1057
@@ -1218,55 +1259,6 @@ x_handle_property_notify (XPropertyEvent *event)
1218 1259
1219 1260
1220 1261
1221#if 0 /* #### MULTIPLE doesn't work yet */
1222
1223static Lisp_Object
1224fetch_multiple_target (event)
1225 XSelectionRequestEvent *event;
1226{
1227 Display *display = event->display;
1228 Window window = event->requestor;
1229 Atom target = event->target;
1230 Atom selection_atom = event->selection;
1231 int result;
1232
1233 return
1234 Fcons (QMULTIPLE,
1235 x_get_window_property_as_lisp_data (display, window, target,
1236 QMULTIPLE, selection_atom));
1237}
1238
1239static Lisp_Object
1240copy_multiple_data (obj)
1241 Lisp_Object obj;
1242{
1243 Lisp_Object vec;
1244 int i;
1245 int size;
1246 if (CONSP (obj))
1247 return Fcons (XCAR (obj), copy_multiple_data (XCDR (obj)));
1248
1249 CHECK_VECTOR (obj);
1250 vec = Fmake_vector (size = ASIZE (obj), Qnil);
1251 for (i = 0; i < size; i++)
1252 {
1253 Lisp_Object vec2 = XVECTOR (obj)->contents [i];
1254 CHECK_VECTOR (vec2);
1255 if (ASIZE (vec2) != 2)
1256 /* ??? Confusing error message */
1257 signal_error ("Vectors must be of length 2", vec2);
1258 XVECTOR (vec)->contents [i] = Fmake_vector (2, Qnil);
1259 XVECTOR (XVECTOR (vec)->contents [i])->contents [0]
1260 = XVECTOR (vec2)->contents [0];
1261 XVECTOR (XVECTOR (vec)->contents [i])->contents [1]
1262 = XVECTOR (vec2)->contents [1];
1263 }
1264 return vec;
1265}
1266
1267#endif
1268
1269
1270/* Variables for communication with x_handle_selection_notify. */ 1262/* Variables for communication with x_handle_selection_notify. */
1271static Atom reading_which_selection; 1263static Atom reading_which_selection;
1272static Lisp_Object reading_selection_reply; 1264static Lisp_Object reading_selection_reply;
@@ -1339,16 +1331,18 @@ x_get_foreign_selection (Lisp_Object selection_symbol, Lisp_Object target_type,
1339 1331
1340 frame = some_frame_on_display (dpyinfo); 1332 frame = some_frame_on_display (dpyinfo);
1341 1333
1342 /* If the display no longer has frames, we can't expect 1334 /* It should not be necessary to stop handling selection requests
1343 to get many more selection requests from it, so don't 1335 during this time. In fact, the SAVE_TARGETS mechanism requires
1344 bother trying to queue them. */ 1336 us to handle a clipboard manager's requests before it returns
1337 SelectionNotify. */
1338#if 0
1345 if (!NILP (frame)) 1339 if (!NILP (frame))
1346 { 1340 {
1347 x_start_queuing_selection_requests (); 1341 x_start_queuing_selection_requests ();
1348 1342 record_unwind_protect (queue_selection_requests_unwind, Qnil);
1349 record_unwind_protect (queue_selection_requests_unwind,
1350 Qnil);
1351 } 1343 }
1344#endif
1345
1352 UNBLOCK_INPUT; 1346 UNBLOCK_INPUT;
1353 1347
1354 /* This allows quits. Also, don't wait forever. */ 1348 /* This allows quits. Also, don't wait forever. */
@@ -1583,9 +1577,9 @@ receive_incremental_selection (Display *display, Window window, Atom property,
1583} 1577}
1584 1578
1585 1579
1586/* Once a requested selection is "ready" (we got a SelectionNotify event), 1580/* Fetch a value from property PROPERTY of X window WINDOW on display
1587 fetch value from property PROPERTY of X window WINDOW on display DISPLAY. 1581 DISPLAY. TARGET_TYPE and SELECTION_ATOM are used in error message
1588 TARGET_TYPE and SELECTION_ATOM are used in error message if this fails. */ 1582 if this fails. */
1589 1583
1590static Lisp_Object 1584static Lisp_Object
1591x_get_window_property_as_lisp_data (Display *display, Window window, 1585x_get_window_property_as_lisp_data (Display *display, Window window,
@@ -1717,9 +1711,10 @@ selection_data_to_lisp_data (Display *display, const unsigned char *data,
1717 return str; 1711 return str;
1718 } 1712 }
1719 /* Convert a single atom to a Lisp_Symbol. Convert a set of atoms to 1713 /* Convert a single atom to a Lisp_Symbol. Convert a set of atoms to
1720 a vector of symbols. 1714 a vector of symbols. */
1721 */ 1715 else if (type == XA_ATOM
1722 else if (type == XA_ATOM) 1716 /* Treat ATOM_PAIR type similar to list of atoms. */
1717 || type == dpyinfo->Xatom_ATOM_PAIR)
1723 { 1718 {
1724 int i; 1719 int i;
1725 /* On a 64 bit machine sizeof(Atom) == sizeof(long) == 8. 1720 /* On a 64 bit machine sizeof(Atom) == sizeof(long) == 8.
@@ -1866,45 +1861,15 @@ lisp_data_to_selection_data (Display *display, Lisp_Object obj,
1866 if (NILP (type)) type = QATOM; 1861 if (NILP (type)) type = QATOM;
1867 *size_ret = ASIZE (obj); 1862 *size_ret = ASIZE (obj);
1868 *format_ret = 32; 1863 *format_ret = 32;
1869 *data_ret = (unsigned char *) xmalloc ((*size_ret) * sizeof (Atom));
1870 for (i = 0; i < *size_ret; i++) 1864 for (i = 0; i < *size_ret; i++)
1871 if (SYMBOLP (XVECTOR (obj)->contents [i])) 1865 if (!SYMBOLP (XVECTOR (obj)->contents [i]))
1872 (*(Atom **) data_ret) [i]
1873 = symbol_to_x_atom (dpyinfo, display, XVECTOR (obj)->contents [i]);
1874 else
1875 signal_error ("All elements of selection vector must have same type", obj); 1866 signal_error ("All elements of selection vector must have same type", obj);
1876 }
1877#if 0 /* #### MULTIPLE doesn't work yet */
1878 else if (VECTORP (XVECTOR (obj)->contents [0]))
1879 /* This vector is an ATOM_PAIR set */
1880 {
1881 if (NILP (type)) type = QATOM_PAIR;
1882 *size_ret = ASIZE (obj);
1883 *format_ret = 32;
1884 *data_ret = (unsigned char *)
1885 xmalloc ((*size_ret) * sizeof (Atom) * 2);
1886 for (i = 0; i < *size_ret; i++)
1887 if (VECTORP (XVECTOR (obj)->contents [i]))
1888 {
1889 Lisp_Object pair = XVECTOR (obj)->contents [i];
1890 if (ASIZE (pair) != 2)
1891 signal_error (
1892 "Elements of the vector must be vectors of exactly two elements",
1893 pair);
1894
1895 (*(Atom **) data_ret) [i * 2]
1896 = symbol_to_x_atom (dpyinfo, display,
1897 XVECTOR (pair)->contents [0]);
1898 (*(Atom **) data_ret) [(i * 2) + 1]
1899 = symbol_to_x_atom (dpyinfo, display,
1900 XVECTOR (pair)->contents [1]);
1901 }
1902 else
1903 signal_error ("All elements of the vector must be of the same type",
1904 obj);
1905 1867
1868 *data_ret = (unsigned char *) xmalloc ((*size_ret) * sizeof (Atom));
1869 for (i = 0; i < *size_ret; i++)
1870 (*(Atom **) data_ret) [i]
1871 = symbol_to_x_atom (dpyinfo, display, XVECTOR (obj)->contents [i]);
1906 } 1872 }
1907#endif
1908 else 1873 else
1909 /* This vector is an INTEGER set, or something like it */ 1874 /* This vector is an INTEGER set, or something like it */
1910 { 1875 {
@@ -2590,6 +2555,9 @@ syms_of_xselect (void)
2590 Vselection_alist = Qnil; 2555 Vselection_alist = Qnil;
2591 staticpro (&Vselection_alist); 2556 staticpro (&Vselection_alist);
2592 2557
2558 converted_selections = NULL;
2559 conversion_fail_tag = None;
2560
2593 DEFVAR_LISP ("selection-converter-alist", Vselection_converter_alist, 2561 DEFVAR_LISP ("selection-converter-alist", Vselection_converter_alist,
2594 doc: /* An alist associating X Windows selection-types with functions. 2562 doc: /* An alist associating X Windows selection-types with functions.
2595These functions are called to convert the selection, with three args: 2563These functions are called to convert the selection, with three args:
@@ -2615,7 +2583,7 @@ The functions are called with one argument, the selection type
2615 2583
2616 DEFVAR_LISP ("x-sent-selection-functions", Vx_sent_selection_functions, 2584 DEFVAR_LISP ("x-sent-selection-functions", Vx_sent_selection_functions,
2617 doc: /* A list of functions to be called when Emacs answers a selection request. 2585 doc: /* A list of functions to be called when Emacs answers a selection request.
2618The functions are called with four arguments: 2586The functions are called with three arguments:
2619 - the selection name (typically `PRIMARY', `SECONDARY', or `CLIPBOARD'); 2587 - the selection name (typically `PRIMARY', `SECONDARY', or `CLIPBOARD');
2620 - the selection-type which Emacs was asked to convert the 2588 - the selection-type which Emacs was asked to convert the
2621 selection into before sending (for example, `STRING' or `LENGTH'); 2589 selection into before sending (for example, `STRING' or `LENGTH');