diff options
| author | Richard M. Stallman | 1993-08-14 23:02:58 +0000 |
|---|---|---|
| committer | Richard M. Stallman | 1993-08-14 23:02:58 +0000 |
| commit | d1f21a66c48c44b9ad01f419cfc59f022aabd4c2 (patch) | |
| tree | 454838a88a699491eeb8dabee94d33b9a5cb1d6a /src | |
| parent | b90d9e804346d2202de60678656b361f331d1c40 (diff) | |
| download | emacs-d1f21a66c48c44b9ad01f419cfc59f022aabd4c2.tar.gz emacs-d1f21a66c48c44b9ad01f419cfc59f022aabd4c2.zip | |
(struct property_change): New field `arrived'.
(expect_property_change): Return struct property_change *.
Clear `arrived'.
(unexpect_property_change): Take one as argument.
(wait_for_property_change): Take one as argument.
If `arrived' is set, don't wait.
(wait_for_property_change_unwind): Corresponding changes.
(receive_incremental_selection): Corresponding changes.
(x_reply_selection_request): Corresponding changes.
(property_deleted_p): Function deleted.
(x_handle_selection_clear): Redisplay.
Diffstat (limited to 'src')
| -rw-r--r-- | src/xselect.c | 153 |
1 files changed, 79 insertions, 74 deletions
diff --git a/src/xselect.c b/src/xselect.c index 9f083b8b1a7..7b6a1164e3c 100644 --- a/src/xselect.c +++ b/src/xselect.c | |||
| @@ -106,11 +106,6 @@ static void lisp_data_to_selection_data (); | |||
| 106 | static Lisp_Object selection_data_to_lisp_data (); | 106 | static Lisp_Object selection_data_to_lisp_data (); |
| 107 | static Lisp_Object x_get_window_property_as_lisp_data (); | 107 | static Lisp_Object x_get_window_property_as_lisp_data (); |
| 108 | 108 | ||
| 109 | static int expect_property_change (); | ||
| 110 | static void wait_for_property_change (); | ||
| 111 | static void unexpect_property_change (); | ||
| 112 | static int waiting_for_other_props_on_window (); | ||
| 113 | |||
| 114 | /* This converts a Lisp symbol to a server Atom, avoiding a server | 109 | /* This converts a Lisp symbol to a server Atom, avoiding a server |
| 115 | roundtrip whenever possible. */ | 110 | roundtrip whenever possible. */ |
| 116 | 111 | ||
| @@ -437,6 +432,37 @@ x_selection_request_lisp_error (ignore) | |||
| 437 | return Qnil; | 432 | return Qnil; |
| 438 | } | 433 | } |
| 439 | 434 | ||
| 435 | |||
| 436 | /* This stuff is so that INCR selections are reentrant (that is, so we can | ||
| 437 | be servicing multiple INCR selection requests simultaneously.) I haven't | ||
| 438 | actually tested that yet. */ | ||
| 439 | |||
| 440 | /* Keep a list of the property changes that are awaited. */ | ||
| 441 | |||
| 442 | struct prop_location | ||
| 443 | { | ||
| 444 | int identifier; | ||
| 445 | Display *display; | ||
| 446 | Window window; | ||
| 447 | Atom property; | ||
| 448 | int desired_state; | ||
| 449 | int arrived; | ||
| 450 | struct prop_location *next; | ||
| 451 | }; | ||
| 452 | |||
| 453 | static struct prop_location *expect_property_change (); | ||
| 454 | static void wait_for_property_change (); | ||
| 455 | static void unexpect_property_change (); | ||
| 456 | static int waiting_for_other_props_on_window (); | ||
| 457 | |||
| 458 | static int prop_location_identifier; | ||
| 459 | |||
| 460 | static Lisp_Object property_change_reply; | ||
| 461 | |||
| 462 | static struct prop_location *property_change_reply_object; | ||
| 463 | |||
| 464 | static struct prop_location *property_change_wait_list; | ||
| 465 | |||
| 440 | /* Send the reply to a selection request event EVENT. | 466 | /* Send the reply to a selection request event EVENT. |
| 441 | TYPE is the type of selection data requested. | 467 | TYPE is the type of selection data requested. |
| 442 | DATA and SIZE describe the data to send, already converted. | 468 | DATA and SIZE describe the data to send, already converted. |
| @@ -492,7 +518,7 @@ x_reply_selection_request (event, format, data, size, type) | |||
| 492 | else | 518 | else |
| 493 | { | 519 | { |
| 494 | /* Send an INCR selection. */ | 520 | /* Send an INCR selection. */ |
| 495 | int prop_id; | 521 | struct prop_location *wait_object; |
| 496 | 522 | ||
| 497 | BLOCK_INPUT; | 523 | BLOCK_INPUT; |
| 498 | 524 | ||
| @@ -501,8 +527,8 @@ x_reply_selection_request (event, format, data, size, type) | |||
| 501 | #if 0 | 527 | #if 0 |
| 502 | fprintf (stderr, "\nINCR %d\n", bytes_remaining); | 528 | fprintf (stderr, "\nINCR %d\n", bytes_remaining); |
| 503 | #endif | 529 | #endif |
| 504 | prop_id = expect_property_change (display, window, reply.property, | 530 | wait_object = expect_property_change (display, window, reply.property, |
| 505 | PropertyDelete); | 531 | PropertyDelete); |
| 506 | 532 | ||
| 507 | XChangeProperty (display, window, reply.property, Xatom_INCR, | 533 | XChangeProperty (display, window, reply.property, Xatom_INCR, |
| 508 | 32, PropModeReplace, (unsigned char *) | 534 | 32, PropModeReplace, (unsigned char *) |
| @@ -515,7 +541,7 @@ x_reply_selection_request (event, format, data, size, type) | |||
| 515 | 541 | ||
| 516 | /* First, wait for the requestor to ack by deleting the property. | 542 | /* First, wait for the requestor to ack by deleting the property. |
| 517 | This can run random lisp code (process handlers) or signal. */ | 543 | This can run random lisp code (process handlers) or signal. */ |
| 518 | wait_for_property_change (prop_id); | 544 | wait_for_property_change (wait_object); |
| 519 | 545 | ||
| 520 | while (bytes_remaining) | 546 | while (bytes_remaining) |
| 521 | { | 547 | { |
| @@ -525,8 +551,9 @@ x_reply_selection_request (event, format, data, size, type) | |||
| 525 | 551 | ||
| 526 | BLOCK_INPUT; | 552 | BLOCK_INPUT; |
| 527 | 553 | ||
| 528 | prop_id = expect_property_change (display, window, reply.property, | 554 | wait_object |
| 529 | PropertyDelete); | 555 | = expect_property_change (display, window, reply.property, |
| 556 | PropertyDelete); | ||
| 530 | #if 0 | 557 | #if 0 |
| 531 | fprintf (stderr," INCR adding %d\n", i); | 558 | fprintf (stderr," INCR adding %d\n", i); |
| 532 | #endif | 559 | #endif |
| @@ -541,7 +568,7 @@ x_reply_selection_request (event, format, data, size, type) | |||
| 541 | /* Now wait for the requestor to ack this chunk by deleting the | 568 | /* Now wait for the requestor to ack this chunk by deleting the |
| 542 | property. This can run random lisp code or signal. | 569 | property. This can run random lisp code or signal. |
| 543 | */ | 570 | */ |
| 544 | wait_for_property_change (prop_id); | 571 | wait_for_property_change (wait_object); |
| 545 | } | 572 | } |
| 546 | /* Now write a zero-length chunk to the property to tell the requestor | 573 | /* Now write a zero-length chunk to the property to tell the requestor |
| 547 | that we're done. */ | 574 | that we're done. */ |
| @@ -708,50 +735,18 @@ x_handle_selection_clear (event) | |||
| 708 | /* Let random lisp code notice that the selection has been stolen. */ | 735 | /* Let random lisp code notice that the selection has been stolen. */ |
| 709 | 736 | ||
| 710 | { | 737 | { |
| 711 | Lisp_Object rest = Vx_lost_selection_hooks; | 738 | Lisp_Object rest; |
| 739 | rest = Vx_lost_selection_hooks; | ||
| 712 | if (!EQ (rest, Qunbound)) | 740 | if (!EQ (rest, Qunbound)) |
| 713 | for (; CONSP (rest); rest = Fcdr (rest)) | 741 | { |
| 714 | call1 (Fcar (rest), selection_symbol); | 742 | for (; CONSP (rest); rest = Fcdr (rest)) |
| 743 | call1 (Fcar (rest), selection_symbol); | ||
| 744 | redisplay_preserve_echo_area (); | ||
| 745 | } | ||
| 715 | } | 746 | } |
| 716 | } | 747 | } |
| 717 | 748 | ||
| 718 | 749 | ||
| 719 | /* This stuff is so that INCR selections are reentrant (that is, so we can | ||
| 720 | be servicing multiple INCR selection requests simultaneously.) I haven't | ||
| 721 | actually tested that yet. */ | ||
| 722 | |||
| 723 | static int prop_location_identifier; | ||
| 724 | |||
| 725 | static Lisp_Object property_change_reply; | ||
| 726 | static int property_change_reply_identifier; | ||
| 727 | |||
| 728 | /* Keep a list of the property changes that are awaited. */ | ||
| 729 | |||
| 730 | struct prop_location | ||
| 731 | { | ||
| 732 | int identifier; | ||
| 733 | Display *display; | ||
| 734 | Window window; | ||
| 735 | Atom property; | ||
| 736 | int desired_state; | ||
| 737 | struct prop_location *next; | ||
| 738 | }; | ||
| 739 | |||
| 740 | static struct prop_location *property_change_wait_list; | ||
| 741 | |||
| 742 | static int | ||
| 743 | property_deleted_p (identifier) | ||
| 744 | void *identifier; | ||
| 745 | { | ||
| 746 | struct prop_location *rest = property_change_wait_list; | ||
| 747 | while (rest) | ||
| 748 | if (rest->identifier == (int) identifier) | ||
| 749 | return 0; | ||
| 750 | else | ||
| 751 | rest = rest->next; | ||
| 752 | return 1; | ||
| 753 | } | ||
| 754 | |||
| 755 | /* Nonzero if any properties for DISPLAY and WINDOW | 750 | /* Nonzero if any properties for DISPLAY and WINDOW |
| 756 | are on the list of what we are waiting for. */ | 751 | are on the list of what we are waiting for. */ |
| 757 | 752 | ||
| @@ -774,7 +769,7 @@ waiting_for_other_props_on_window (display, window) | |||
| 774 | The return value is a number that uniquely identifies | 769 | The return value is a number that uniquely identifies |
| 775 | this awaited property change. */ | 770 | this awaited property change. */ |
| 776 | 771 | ||
| 777 | static int | 772 | static struct prop_location * |
| 778 | expect_property_change (display, window, property, state) | 773 | expect_property_change (display, window, property, state) |
| 779 | Display *display; | 774 | Display *display; |
| 780 | Window window; | 775 | Window window; |
| @@ -789,21 +784,22 @@ expect_property_change (display, window, property, state) | |||
| 789 | pl->property = property; | 784 | pl->property = property; |
| 790 | pl->desired_state = state; | 785 | pl->desired_state = state; |
| 791 | pl->next = property_change_wait_list; | 786 | pl->next = property_change_wait_list; |
| 787 | pl->arrived = 0; | ||
| 792 | property_change_wait_list = pl; | 788 | property_change_wait_list = pl; |
| 793 | return pl->identifier; | 789 | return pl; |
| 794 | } | 790 | } |
| 795 | 791 | ||
| 796 | /* Delete an entry from the list of property changes we are waiting for. | 792 | /* Delete an entry from the list of property changes we are waiting for. |
| 797 | IDENTIFIER is the number that uniquely identifies the entry. */ | 793 | IDENTIFIER is the number that uniquely identifies the entry. */ |
| 798 | 794 | ||
| 799 | static void | 795 | static void |
| 800 | unexpect_property_change (identifier) | 796 | unexpect_property_change (location) |
| 801 | int identifier; | 797 | struct prop_location *location; |
| 802 | { | 798 | { |
| 803 | struct prop_location *prev = 0, *rest = property_change_wait_list; | 799 | struct prop_location *prev = 0, *rest = property_change_wait_list; |
| 804 | while (rest) | 800 | while (rest) |
| 805 | { | 801 | { |
| 806 | if (rest->identifier == identifier) | 802 | if (rest == location) |
| 807 | { | 803 | { |
| 808 | if (prev) | 804 | if (prev) |
| 809 | prev->next = rest->next; | 805 | prev->next = rest->next; |
| @@ -823,30 +819,37 @@ static Lisp_Object | |||
| 823 | wait_for_property_change_unwind (identifierval) | 819 | wait_for_property_change_unwind (identifierval) |
| 824 | Lisp_Object identifierval; | 820 | Lisp_Object identifierval; |
| 825 | { | 821 | { |
| 826 | unexpect_property_change (XFASTINT (identifierval)); | 822 | unexpect_property_change (XPNTR (identifierval)); |
| 827 | } | 823 | } |
| 828 | 824 | ||
| 829 | /* Actually wait for a property change. | 825 | /* Actually wait for a property change. |
| 830 | IDENTIFIER should be the value that expect_property_change returned. */ | 826 | IDENTIFIER should be the value that expect_property_change returned. */ |
| 831 | 827 | ||
| 832 | static void | 828 | static void |
| 833 | wait_for_property_change (identifier) | 829 | wait_for_property_change (location) |
| 830 | struct prop_location *location; | ||
| 834 | { | 831 | { |
| 835 | int secs, usecs; | 832 | int secs, usecs; |
| 836 | int count = specpdl_ptr - specpdl; | 833 | int count = specpdl_ptr - specpdl; |
| 834 | Lisp_Object tem; | ||
| 835 | |||
| 836 | XSET (tem, Lisp_Cons, location); | ||
| 837 | 837 | ||
| 838 | /* Make sure to do unexpect_property_change if we quit or err. */ | 838 | /* Make sure to do unexpect_property_change if we quit or err. */ |
| 839 | record_unwind_protect (wait_for_property_change_unwind, | 839 | record_unwind_protect (wait_for_property_change_unwind, tem); |
| 840 | make_number (identifier)); | ||
| 841 | 840 | ||
| 842 | XCONS (property_change_reply)->car = Qnil; | 841 | XCONS (property_change_reply)->car = Qnil; |
| 843 | property_change_reply_identifier = identifier; | ||
| 844 | secs = x_selection_timeout / 1000; | ||
| 845 | usecs = (x_selection_timeout % 1000) * 1000; | ||
| 846 | wait_reading_process_input (secs, usecs, property_change_reply, 0); | ||
| 847 | 842 | ||
| 848 | if (NILP (XCONS (property_change_reply)->car)) | 843 | if (! location->arrived) |
| 849 | error ("timed out waiting for property-notify event"); | 844 | { |
| 845 | property_change_reply_object = location; | ||
| 846 | secs = x_selection_timeout / 1000; | ||
| 847 | usecs = (x_selection_timeout % 1000) * 1000; | ||
| 848 | wait_reading_process_input (secs, usecs, property_change_reply, 0); | ||
| 849 | |||
| 850 | if (NILP (XCONS (property_change_reply)->car)) | ||
| 851 | error ("timed out waiting for property-notify event"); | ||
| 852 | } | ||
| 850 | 853 | ||
| 851 | unbind_to (count, Qnil); | 854 | unbind_to (count, Qnil); |
| 852 | } | 855 | } |
| @@ -873,9 +876,11 @@ x_handle_property_notify (event) | |||
| 873 | ->name->data); | 876 | ->name->data); |
| 874 | #endif | 877 | #endif |
| 875 | 878 | ||
| 879 | rest->arrived = 1; | ||
| 880 | |||
| 876 | /* If this is the one wait_for_property_change is waiting for, | 881 | /* If this is the one wait_for_property_change is waiting for, |
| 877 | tell it to wake up. */ | 882 | tell it to wake up. */ |
| 878 | if (rest->identifier == property_change_reply_identifier) | 883 | if (rest == property_change_reply_object) |
| 879 | XCONS (property_change_reply)->car = Qt; | 884 | XCONS (property_change_reply)->car = Qt; |
| 880 | 885 | ||
| 881 | if (prev) | 886 | if (prev) |
| @@ -1100,7 +1105,7 @@ receive_incremental_selection (display, window, property, target_type, | |||
| 1100 | int *format_ret; | 1105 | int *format_ret; |
| 1101 | { | 1106 | { |
| 1102 | int offset = 0; | 1107 | int offset = 0; |
| 1103 | int prop_id; | 1108 | struct prop_location *wait_object; |
| 1104 | *size_bytes_ret = min_size_bytes; | 1109 | *size_bytes_ret = min_size_bytes; |
| 1105 | *data_ret = (unsigned char *) xmalloc (*size_bytes_ret); | 1110 | *data_ret = (unsigned char *) xmalloc (*size_bytes_ret); |
| 1106 | #if 0 | 1111 | #if 0 |
| @@ -1118,8 +1123,8 @@ receive_incremental_selection (display, window, property, target_type, | |||
| 1118 | BLOCK_INPUT; | 1123 | BLOCK_INPUT; |
| 1119 | XSelectInput (display, window, STANDARD_EVENT_SET | PropertyChangeMask); | 1124 | XSelectInput (display, window, STANDARD_EVENT_SET | PropertyChangeMask); |
| 1120 | XDeleteProperty (display, window, property); | 1125 | XDeleteProperty (display, window, property); |
| 1121 | prop_id = expect_property_change (display, window, property, | 1126 | wait_object = expect_property_change (display, window, property, |
| 1122 | PropertyNewValue); | 1127 | PropertyNewValue); |
| 1123 | XFlushQueue (); | 1128 | XFlushQueue (); |
| 1124 | UNBLOCK_INPUT; | 1129 | UNBLOCK_INPUT; |
| 1125 | 1130 | ||
| @@ -1127,7 +1132,7 @@ receive_incremental_selection (display, window, property, target_type, | |||
| 1127 | { | 1132 | { |
| 1128 | unsigned char *tmp_data; | 1133 | unsigned char *tmp_data; |
| 1129 | int tmp_size_bytes; | 1134 | int tmp_size_bytes; |
| 1130 | wait_for_property_change (prop_id); | 1135 | wait_for_property_change (wait_object); |
| 1131 | /* expect it again immediately, because x_get_window_property may | 1136 | /* expect it again immediately, because x_get_window_property may |
| 1132 | .. no it wont, I dont get it. | 1137 | .. no it wont, I dont get it. |
| 1133 | .. Ok, I get it now, the Xt code that implements INCR is broken. | 1138 | .. Ok, I get it now, the Xt code that implements INCR is broken. |
| @@ -1143,15 +1148,15 @@ receive_incremental_selection (display, window, property, target_type, | |||
| 1143 | #endif | 1148 | #endif |
| 1144 | if (! waiting_for_other_props_on_window (display, window)) | 1149 | if (! waiting_for_other_props_on_window (display, window)) |
| 1145 | XSelectInput (display, window, STANDARD_EVENT_SET); | 1150 | XSelectInput (display, window, STANDARD_EVENT_SET); |
| 1146 | unexpect_property_change (prop_id); | 1151 | unexpect_property_change (wait_object); |
| 1147 | if (tmp_data) xfree (tmp_data); | 1152 | if (tmp_data) xfree (tmp_data); |
| 1148 | break; | 1153 | break; |
| 1149 | } | 1154 | } |
| 1150 | 1155 | ||
| 1151 | BLOCK_INPUT; | 1156 | BLOCK_INPUT; |
| 1152 | XDeleteProperty (display, window, property); | 1157 | XDeleteProperty (display, window, property); |
| 1153 | prop_id = expect_property_change (display, window, property, | 1158 | wait_object = expect_property_change (display, window, property, |
| 1154 | PropertyNewValue); | 1159 | PropertyNewValue); |
| 1155 | XFlushQueue (); | 1160 | XFlushQueue (); |
| 1156 | UNBLOCK_INPUT; | 1161 | UNBLOCK_INPUT; |
| 1157 | 1162 | ||