diff options
| author | Jim Blandy | 1992-09-29 18:30:35 +0000 |
|---|---|---|
| committer | Jim Blandy | 1992-09-29 18:30:35 +0000 |
| commit | 234a804bca326994adc2d83f01d064ee642228f9 (patch) | |
| tree | 55701983e116c0000419416934cc4ef1ebb9d107 /src | |
| parent | 72e609d0db47631ae8d140c6da099bbe8cf36c96 (diff) | |
| download | emacs-234a804bca326994adc2d83f01d064ee642228f9.tar.gz emacs-234a804bca326994adc2d83f01d064ee642228f9.zip | |
* xselect.c (Qcut_buffer0): Symbol removed; we're using a new
interface to the cut buffer now.
(NUM_CUT_BUFFERS, cut_buffer_atom, cut_buffer_value,
cut_buffer_cached, cut_buffer_just_set): New variables.
(Fx_own_selection, Fx_selection_value): Dike out the code to
handle CUT_BUFFER0 requests.
(Fx_get_cut_buffer, Fx_set_cut_buffer, x_watch_cut_buffer_cache,
x_invalidate_cut_buffer_cache): New functions.
(syms_of_xselect): Don't bother to initialize Qcut_buffer0.
Initialize and staticpro cut_buffer_value, and defsubr
Sx_get_cut_buffer and Sx_set_cut_buffer.
* xterm.c (XTread_socket): Pass PropertyNotify events from the
root window to x_invalidate_cut_buffer_cache.
(x_term_init): Call x_watch_cut_buffer_cache here.
Diffstat (limited to 'src')
| -rw-r--r-- | src/xselect.c.old | 219 |
1 files changed, 208 insertions, 11 deletions
diff --git a/src/xselect.c.old b/src/xselect.c.old index 81cdd755e8b..6adedd96cf3 100644 --- a/src/xselect.c.old +++ b/src/xselect.c.old | |||
| @@ -53,10 +53,8 @@ Lisp_Object Vx_selection_value; | |||
| 53 | /* The value of the current SECONDARY selection. */ | 53 | /* The value of the current SECONDARY selection. */ |
| 54 | Lisp_Object Vx_secondary_selection_value; | 54 | Lisp_Object Vx_secondary_selection_value; |
| 55 | 55 | ||
| 56 | /* Types of selections we may make. Note that Qcut_buffer0 isn't really | 56 | /* Types of selections we may make. */ |
| 57 | a selection, but it acts like one for the sake of Fx_own_selection and | 57 | Lisp_Object Qprimary, Qsecondary, Qclipboard; |
| 58 | Fx_selection_value. */ | ||
| 59 | Lisp_Object Qprimary, Qsecondary, Qclipboard, Qcut_buffer0; | ||
| 60 | 58 | ||
| 61 | /* Emacs' selection property identifiers. */ | 59 | /* Emacs' selection property identifiers. */ |
| 62 | Atom Xatom_emacs_selection; | 60 | Atom Xatom_emacs_selection; |
| @@ -110,7 +108,52 @@ int incr_nbytes; | |||
| 110 | unsigned char *incr_value; | 108 | unsigned char *incr_value; |
| 111 | unsigned char *incr_ptr; | 109 | unsigned char *incr_ptr; |
| 112 | 110 | ||
| 113 | /* SELECTION OWNER CODE */ | 111 | /* Declarations for handling cut buffers. |
| 112 | |||
| 113 | Whenever we set a cut buffer or read a cut buffer's value, we cache | ||
| 114 | it in cut_buffer_value. We look for PropertyNotify events about | ||
| 115 | the CUT_BUFFER properties, and invalidate our cache accordingly. | ||
| 116 | We ignore PropertyNotify events that we suspect were caused by our | ||
| 117 | own changes to the cut buffers, so we can keep the cache valid | ||
| 118 | longer. | ||
| 119 | |||
| 120 | IS ALL THIS HAIR WORTH IT? Well, these functions get called every | ||
| 121 | time an element goes into or is retrieved from the kill ring, and | ||
| 122 | those ought to be quick. It's not fun in time or space to wait for | ||
| 123 | 50k cut buffers to fly back and forth across the net. */ | ||
| 124 | |||
| 125 | /* The number of CUT_BUFFER properties defined under X. */ | ||
| 126 | #define NUM_CUT_BUFFERS (8) | ||
| 127 | |||
| 128 | /* cut_buffer_atom[n] is the atom naming the nth cut buffer. */ | ||
| 129 | static Atom cut_buffer_atom[NUM_CUT_BUFFERS] = { | ||
| 130 | XA_CUT_BUFFER0, XA_CUT_BUFFER1, XA_CUT_BUFFER2, XA_CUT_BUFFER3, | ||
| 131 | XA_CUT_BUFFER4, XA_CUT_BUFFER5, XA_CUT_BUFFER6, XA_CUT_BUFFER7 | ||
| 132 | }; | ||
| 133 | |||
| 134 | /* cut_buffer_value is an eight-element vector; | ||
| 135 | (aref cut_buffer_value n) is the cached value of cut buffer n, or | ||
| 136 | Qnil if cut buffer n is unset. */ | ||
| 137 | static Lisp_Object cut_buffer_value; | ||
| 138 | |||
| 139 | /* Bit N of cut_buffer_cached is true if (aref cut_buffer_value n) is | ||
| 140 | known to be valid. This is cleared by PropertyNotify events | ||
| 141 | handled by x_invalidate_cut_buffer_cache. It would be wonderful if | ||
| 142 | that routine could just set the appropriate element of | ||
| 143 | cut_buffer_value to some special value meaning "uncached", but that | ||
| 144 | would lose if a GC happened to be in progress. | ||
| 145 | |||
| 146 | Bit N of cut_buffer_just_set is true if cut buffer N has been set since | ||
| 147 | the last PropertyNotify event; since we get an event even when we set | ||
| 148 | the property ourselves, we should ignore one event after setting | ||
| 149 | a cut buffer, so we don't have to throw away our cache. */ | ||
| 150 | #ifdef __STDC__ | ||
| 151 | volatile | ||
| 152 | #endif | ||
| 153 | static cut_buffer_cached, cut_buffer_just_set; | ||
| 154 | |||
| 155 | |||
| 156 | /* Acquiring ownership of a selection. */ | ||
| 114 | 157 | ||
| 115 | 158 | ||
| 116 | /* Request selection ownership if we do not already have it. */ | 159 | /* Request selection ownership if we do not already have it. */ |
| @@ -191,6 +234,7 @@ use X selections.") | |||
| 191 | } | 234 | } |
| 192 | UNBLOCK_INPUT; | 235 | UNBLOCK_INPUT; |
| 193 | } | 236 | } |
| 237 | #if 0 | ||
| 194 | else if (EQ (type, Qcut_buffer0)) | 238 | else if (EQ (type, Qcut_buffer0)) |
| 195 | { | 239 | { |
| 196 | /* DECwindows and some other servers don't seem to like setting | 240 | /* DECwindows and some other servers don't seem to like setting |
| @@ -216,6 +260,7 @@ use X selections.") | |||
| 216 | } | 260 | } |
| 217 | UNBLOCK_INPUT; | 261 | UNBLOCK_INPUT; |
| 218 | } | 262 | } |
| 263 | #endif | ||
| 219 | else | 264 | else |
| 220 | error ("Invalid X selection type"); | 265 | error ("Invalid X selection type"); |
| 221 | 266 | ||
| @@ -257,11 +302,14 @@ x_disown_selection (old_owner, selection, changed_owner_time) | |||
| 257 | abort (); /* Inconsistent state. */ | 302 | abort (); /* Inconsistent state. */ |
| 258 | } | 303 | } |
| 259 | 304 | ||
| 305 | |||
| 306 | /* Answering selection requests. */ | ||
| 307 | |||
| 260 | int x_selection_alloc_error; | 308 | int x_selection_alloc_error; |
| 261 | int x_converting_selection; | 309 | int x_converting_selection; |
| 262 | 310 | ||
| 263 | /* Reply to some client's request for our selection data. Data is | 311 | /* Reply to some client's request for our selection data. |
| 264 | placed in a property supplied by the requesting window. | 312 | Data is placed in a property supplied by the requesting window. |
| 265 | 313 | ||
| 266 | If the data exceeds the maximum amount the server can send, | 314 | If the data exceeds the maximum amount the server can send, |
| 267 | then prepare to send it incrementally, and reply to the client with | 315 | then prepare to send it incrementally, and reply to the client with |
| @@ -519,7 +567,8 @@ x_send_incremental (event) | |||
| 519 | } | 567 | } |
| 520 | } | 568 | } |
| 521 | 569 | ||
| 522 | /* SELECTION REQUESTOR CODE */ | 570 | |
| 571 | /* Requesting the value of a selection. */ | ||
| 523 | 572 | ||
| 524 | /* Predicate function used to match a requested event. */ | 573 | /* Predicate function used to match a requested event. */ |
| 525 | 574 | ||
| @@ -579,7 +628,7 @@ selection, but optional argument TYPE may specify secondary or clipboard.") | |||
| 579 | if (NILP (type) || EQ (type, Qprimary)) | 628 | if (NILP (type) || EQ (type, Qprimary)) |
| 580 | { | 629 | { |
| 581 | if (!NILP (Vx_selection_value)) | 630 | if (!NILP (Vx_selection_value)) |
| 582 | return Vx_selection_value; | 631 | return Vx_selection_value; |
| 583 | 632 | ||
| 584 | return get_selection_value (XA_PRIMARY); | 633 | return get_selection_value (XA_PRIMARY); |
| 585 | } | 634 | } |
| @@ -597,6 +646,7 @@ selection, but optional argument TYPE may specify secondary or clipboard.") | |||
| 597 | 646 | ||
| 598 | return get_selection_value (Xatom_clipboard); | 647 | return get_selection_value (Xatom_clipboard); |
| 599 | } | 648 | } |
| 649 | #if 0 | ||
| 600 | else if (EQ (type, Qcut_buffer0)) | 650 | else if (EQ (type, Qcut_buffer0)) |
| 601 | { | 651 | { |
| 602 | char *data; | 652 | char *data; |
| @@ -613,6 +663,7 @@ selection, but optional argument TYPE may specify secondary or clipboard.") | |||
| 613 | 663 | ||
| 614 | return string; | 664 | return string; |
| 615 | } | 665 | } |
| 666 | #endif | ||
| 616 | else | 667 | else |
| 617 | error ("Invalid X selection type"); | 668 | error ("Invalid X selection type"); |
| 618 | } | 669 | } |
| @@ -730,6 +781,148 @@ x_selection_arrival (event, requestor_window, requestor_time) | |||
| 730 | return Qnil; | 781 | return Qnil; |
| 731 | } | 782 | } |
| 732 | 783 | ||
| 784 | |||
| 785 | /* Cut buffer management. */ | ||
| 786 | |||
| 787 | DEFUN ("x-get-cut-buffer", Fx_get_cut_buffer, Sx_get_cut_buffer, 0, 1, "", | ||
| 788 | "Return the value of cut buffer N, or nil if it is unset.\n\ | ||
| 789 | If N is omitted, it defaults to zero.\n\ | ||
| 790 | Note that cut buffers have some problems that selections don't; try to\n\ | ||
| 791 | write your code to use cut buffers only for backward compatibility,\n\ | ||
| 792 | and use selections for the serious work.") | ||
| 793 | (n) | ||
| 794 | Lisp_Object n; | ||
| 795 | { | ||
| 796 | int buf_num; | ||
| 797 | |||
| 798 | if (NILP (n)) | ||
| 799 | buf_num = 0; | ||
| 800 | else | ||
| 801 | { | ||
| 802 | CHECK_NUMBER (n, 0); | ||
| 803 | buf_num = XINT (n); | ||
| 804 | } | ||
| 805 | |||
| 806 | if (buf_num < 0 && buf_num > NUM_CUT_BUFFERS) | ||
| 807 | error ("cut buffer numbers must be from zero to seven."); | ||
| 808 | |||
| 809 | { | ||
| 810 | Lisp_Object value; | ||
| 811 | |||
| 812 | /* Note that no PropertyNotify events will be processed while | ||
| 813 | input is blocked. */ | ||
| 814 | BLOCK_INPUT; | ||
| 815 | |||
| 816 | if (cut_buffer_cached & (1 << buf_num)) | ||
| 817 | value = XVECTOR (cut_buffer_value)->contents[buf_num]; | ||
| 818 | else | ||
| 819 | { | ||
| 820 | /* Our cache is invalid; retrieve the property's value from | ||
| 821 | the server. */ | ||
| 822 | int buf_len; | ||
| 823 | char *buf = XFetchBuffer (x_current_display, &buf_len, buf_num); | ||
| 824 | |||
| 825 | if (buf_len == 0) | ||
| 826 | value = Qnil; | ||
| 827 | else | ||
| 828 | value = make_string (buf, buf_len); | ||
| 829 | |||
| 830 | XVECTOR (cut_buffer_value)->contents[buf_num] = value; | ||
| 831 | cut_buffer_cached |= (1 << buf_num); | ||
| 832 | |||
| 833 | XFree (buf); | ||
| 834 | } | ||
| 835 | |||
| 836 | UNBLOCK_INPUT; | ||
| 837 | |||
| 838 | return value; | ||
| 839 | } | ||
| 840 | } | ||
| 841 | |||
| 842 | DEFUN ("x-set-cut-buffer", Fx_set_cut_buffer, Sx_set_cut_buffer, 2, 2, "", | ||
| 843 | "Set the value of cut buffer N to STRING.\n\ | ||
| 844 | Note that cut buffers have some problems that selections don't; try to\n\ | ||
| 845 | write your code to use cut buffers only for backward compatibility,\n\ | ||
| 846 | and use selections for the serious work.") | ||
| 847 | (n, string) | ||
| 848 | Lisp_Object n, string; | ||
| 849 | { | ||
| 850 | int buf_num; | ||
| 851 | |||
| 852 | CHECK_NUMBER (n, 0); | ||
| 853 | CHECK_STRING (string, 1); | ||
| 854 | |||
| 855 | buf_num = XINT (n); | ||
| 856 | |||
| 857 | if (buf_num < 0 || buf_num > 7) | ||
| 858 | error ("cut buffer numbers must be from zero to seven."); | ||
| 859 | |||
| 860 | BLOCK_INPUT; | ||
| 861 | |||
| 862 | /* DECwindows and some other servers don't seem to like setting | ||
| 863 | properties to values larger than about 20k. For very large | ||
| 864 | values, they signal an error, but for intermediate values they | ||
| 865 | just seem to hang. | ||
| 866 | |||
| 867 | We could just truncate the request, but it's better to let the | ||
| 868 | user know that the strategy he/she's using isn't going to work | ||
| 869 | than to have it work partially, but incorrectly. */ | ||
| 870 | |||
| 871 | if (XSTRING (string)->size == 0 | ||
| 872 | || XSTRING (string)->size > MAX_SELECTION (x_current_display)) | ||
| 873 | { | ||
| 874 | XStoreBuffer (x_current_display, (char *) 0, 0, buf_num); | ||
| 875 | string = Qnil; | ||
| 876 | } | ||
| 877 | else | ||
| 878 | { | ||
| 879 | XStoreBuffer (x_current_display, | ||
| 880 | (char *) XSTRING (string)->data, XSTRING (string)->size, | ||
| 881 | buf_num); | ||
| 882 | } | ||
| 883 | |||
| 884 | XVECTOR (cut_buffer_value)->contents[buf_num] = string; | ||
| 885 | cut_buffer_cached |= (1 << buf_num); | ||
| 886 | cut_buffer_just_set |= (1 << buf_num); | ||
| 887 | |||
| 888 | UNBLOCK_INPUT; | ||
| 889 | |||
| 890 | return string; | ||
| 891 | } | ||
| 892 | |||
| 893 | /* Ask the server to send us an event if any cut buffer is modified. */ | ||
| 894 | |||
| 895 | void | ||
| 896 | x_watch_cut_buffer_cache () | ||
| 897 | { | ||
| 898 | XSelectInput (x_current_display, ROOT_WINDOW, PropertyChangeMask); | ||
| 899 | } | ||
| 900 | |||
| 901 | /* The server has told us that a cut buffer has been modified; deal with that. | ||
| 902 | Note that this function is called at interrupt level. */ | ||
| 903 | void | ||
| 904 | x_invalidate_cut_buffer_cache (XPropertyEvent *event) | ||
| 905 | { | ||
| 906 | int i; | ||
| 907 | |||
| 908 | /* See which cut buffer this is about, if any. */ | ||
| 909 | for (i = 0; i < NUM_CUT_BUFFERS; i++) | ||
| 910 | if (event->atom == cut_buffer_atom[i]) | ||
| 911 | { | ||
| 912 | int mask = (1 << i); | ||
| 913 | |||
| 914 | if (cut_buffer_just_set & mask) | ||
| 915 | cut_buffer_just_set &= ~mask; | ||
| 916 | else | ||
| 917 | cut_buffer_cached &= ~mask; | ||
| 918 | |||
| 919 | break; | ||
| 920 | } | ||
| 921 | } | ||
| 922 | |||
| 923 | |||
| 924 | /* Bureaucracy. */ | ||
| 925 | |||
| 733 | void | 926 | void |
| 734 | syms_of_xselect () | 927 | syms_of_xselect () |
| 735 | { | 928 | { |
| @@ -751,10 +944,14 @@ syms_of_xselect () | |||
| 751 | staticpro (&Qsecondary); | 944 | staticpro (&Qsecondary); |
| 752 | Qclipboard = intern ("clipboard"); | 945 | Qclipboard = intern ("clipboard"); |
| 753 | staticpro (&Qclipboard); | 946 | staticpro (&Qclipboard); |
| 754 | Qcut_buffer0 = intern ("cut-buffer0"); | ||
| 755 | staticpro (&Qcut_buffer0); | ||
| 756 | 947 | ||
| 757 | defsubr (&Sx_own_selection); | 948 | defsubr (&Sx_own_selection); |
| 758 | defsubr (&Sx_selection_value); | 949 | defsubr (&Sx_selection_value); |
| 950 | |||
| 951 | cut_buffer_value = Fmake_vector (make_number (NUM_CUT_BUFFERS), Qnil); | ||
| 952 | staticpro (&cut_buffer_value); | ||
| 953 | |||
| 954 | defsubr (&Sx_get_cut_buffer); | ||
| 955 | defsubr (&Sx_set_cut_buffer); | ||
| 759 | } | 956 | } |
| 760 | #endif /* X11 */ | 957 | #endif /* X11 */ |