diff options
| author | Po Lu | 2022-06-08 15:08:09 +0800 |
|---|---|---|
| committer | Po Lu | 2022-06-08 15:08:27 +0800 |
| commit | 22d3f0e95a5602b2bde763cff185f5b4fed6e53e (patch) | |
| tree | 1a20706bfe3ad7228209ad2ed783753534caac5e /src | |
| parent | 90f3da0ccdb4c58265e9f8c3d9465198d8a2092a (diff) | |
| download | emacs-22d3f0e95a5602b2bde763cff185f5b4fed6e53e.tar.gz emacs-22d3f0e95a5602b2bde763cff185f5b4fed6e53e.zip | |
Make responding to selection requests work inside popups
* src/xfns.c (Fx_file_dialog):
* src/xmenu.c (x_menu_wait_for_event, create_and_show_popup_menu)
(create_and_show_dialog, x_menu_show): Defer selection requests.
* src/xselect.c (x_get_foreign_selection)
(x_handle_selection_notify): Add some more info to selection
trace.
* src/xterm.c (x_defer_selection_requests): Make non-static.
(x_release_selection_requests_and_flush): New function.
(x_dnd_begin_drag_and_drop): Use DEFER_SELECTIONS instead.
(x_wait_for_cell_change): Fix initial value of rc for pushed
back events.
(handle_one_xevent): Allow GTK to respond to selections in its
windows too.
* src/xterm.h (DEFER_SELECTIONS): New slug of code.
Diffstat (limited to 'src')
| -rw-r--r-- | src/xfns.c | 3 | ||||
| -rw-r--r-- | src/xmenu.c | 24 | ||||
| -rw-r--r-- | src/xselect.c | 8 | ||||
| -rw-r--r-- | src/xterm.c | 63 | ||||
| -rw-r--r-- | src/xterm.h | 6 |
5 files changed, 86 insertions, 18 deletions
diff --git a/src/xfns.c b/src/xfns.c index cffb4a5d96c..f0a2ec666c9 100644 --- a/src/xfns.c +++ b/src/xfns.c | |||
| @@ -8885,6 +8885,9 @@ DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 5, 0, | |||
| 8885 | /* Prevent redisplay. */ | 8885 | /* Prevent redisplay. */ |
| 8886 | specbind (Qinhibit_redisplay, Qt); | 8886 | specbind (Qinhibit_redisplay, Qt); |
| 8887 | 8887 | ||
| 8888 | /* Defer selection requests. */ | ||
| 8889 | DEFER_SELECTIONS; | ||
| 8890 | |||
| 8888 | block_input (); | 8891 | block_input (); |
| 8889 | 8892 | ||
| 8890 | /* Create the dialog with PROMPT as title, using DIR as initial | 8893 | /* Create the dialog with PROMPT as title, using DIR as initial |
diff --git a/src/xmenu.c b/src/xmenu.c index e9601981edd..7134bf22c83 100644 --- a/src/xmenu.c +++ b/src/xmenu.c | |||
| @@ -198,6 +198,10 @@ x_menu_wait_for_event (void *data) | |||
| 198 | struct x_display_info *dpyinfo; | 198 | struct x_display_info *dpyinfo; |
| 199 | int n = 0; | 199 | int n = 0; |
| 200 | 200 | ||
| 201 | /* ISTM that if timer_check is okay, this should be too, since | ||
| 202 | both can run random Lisp. */ | ||
| 203 | x_handle_pending_selection_requests (); | ||
| 204 | |||
| 201 | FD_ZERO (&read_fds); | 205 | FD_ZERO (&read_fds); |
| 202 | for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next) | 206 | for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next) |
| 203 | { | 207 | { |
| @@ -1579,6 +1583,8 @@ create_and_show_popup_menu (struct frame *f, widget_value *first_wv, | |||
| 1579 | } | 1583 | } |
| 1580 | #endif | 1584 | #endif |
| 1581 | 1585 | ||
| 1586 | DEFER_SELECTIONS; | ||
| 1587 | |||
| 1582 | /* Display the menu. */ | 1588 | /* Display the menu. */ |
| 1583 | gtk_widget_show_all (menu); | 1589 | gtk_widget_show_all (menu); |
| 1584 | 1590 | ||
| @@ -1868,6 +1874,8 @@ create_and_show_popup_menu (struct frame *f, widget_value *first_wv, | |||
| 1868 | { | 1874 | { |
| 1869 | specpdl_ref specpdl_count = SPECPDL_INDEX (); | 1875 | specpdl_ref specpdl_count = SPECPDL_INDEX (); |
| 1870 | 1876 | ||
| 1877 | DEFER_SELECTIONS; | ||
| 1878 | |||
| 1871 | record_unwind_protect_int (pop_down_menu, (int) menu_id); | 1879 | record_unwind_protect_int (pop_down_menu, (int) menu_id); |
| 1872 | #ifdef HAVE_XINPUT2 | 1880 | #ifdef HAVE_XINPUT2 |
| 1873 | record_unwind_protect_ptr (leave_toolkit_menu, f); | 1881 | record_unwind_protect_ptr (leave_toolkit_menu, f); |
| @@ -2199,6 +2207,8 @@ create_and_show_dialog (struct frame *f, widget_value *first_wv) | |||
| 2199 | if (menu) | 2207 | if (menu) |
| 2200 | { | 2208 | { |
| 2201 | specpdl_ref specpdl_count = SPECPDL_INDEX (); | 2209 | specpdl_ref specpdl_count = SPECPDL_INDEX (); |
| 2210 | |||
| 2211 | DEFER_SELECTIONS; | ||
| 2202 | record_unwind_protect_ptr (pop_down_menu, menu); | 2212 | record_unwind_protect_ptr (pop_down_menu, menu); |
| 2203 | 2213 | ||
| 2204 | /* Display the menu. */ | 2214 | /* Display the menu. */ |
| @@ -2255,6 +2265,8 @@ create_and_show_dialog (struct frame *f, widget_value *first_wv) | |||
| 2255 | { | 2265 | { |
| 2256 | specpdl_ref count = SPECPDL_INDEX (); | 2266 | specpdl_ref count = SPECPDL_INDEX (); |
| 2257 | 2267 | ||
| 2268 | DEFER_SELECTIONS; | ||
| 2269 | |||
| 2258 | /* xdialog_show_unwind is responsible for popping the dialog box down. */ | 2270 | /* xdialog_show_unwind is responsible for popping the dialog box down. */ |
| 2259 | 2271 | ||
| 2260 | record_unwind_protect_int (pop_down_menu, (int) dialog_id); | 2272 | record_unwind_protect_int (pop_down_menu, (int) dialog_id); |
| @@ -2715,18 +2727,18 @@ x_menu_show (struct frame *f, int x, int y, int menuflags, | |||
| 2715 | y = max (y, 1); | 2727 | y = max (y, 1); |
| 2716 | XMenuLocate (FRAME_X_DISPLAY (f), menu, 0, 0, x, y, | 2728 | XMenuLocate (FRAME_X_DISPLAY (f), menu, 0, 0, x, y, |
| 2717 | &ulx, &uly, &width, &height); | 2729 | &ulx, &uly, &width, &height); |
| 2718 | if (ulx+width > dispwidth) | 2730 | if (ulx + width > dispwidth) |
| 2719 | { | 2731 | { |
| 2720 | x -= (ulx + width) - dispwidth; | 2732 | x -= (ulx + width) - dispwidth; |
| 2721 | ulx = dispwidth - width; | 2733 | ulx = dispwidth - width; |
| 2722 | } | 2734 | } |
| 2723 | if (uly+height > dispheight) | 2735 | if (uly + height > dispheight) |
| 2724 | { | 2736 | { |
| 2725 | y -= (uly + height) - dispheight; | 2737 | y -= (uly + height) - dispheight; |
| 2726 | uly = dispheight - height; | 2738 | uly = dispheight - height; |
| 2727 | } | 2739 | } |
| 2728 | #ifndef HAVE_X_WINDOWS | 2740 | #ifndef HAVE_X_WINDOWS |
| 2729 | if (FRAME_HAS_MINIBUF_P (f) && uly+height > dispheight - 1) | 2741 | if (FRAME_HAS_MINIBUF_P (f) && uly + height > dispheight - 1) |
| 2730 | { | 2742 | { |
| 2731 | /* Move the menu away of the echo area, to avoid overwriting the | 2743 | /* Move the menu away of the echo area, to avoid overwriting the |
| 2732 | menu with help echo messages or vice versa. */ | 2744 | menu with help echo messages or vice versa. */ |
| @@ -2750,8 +2762,8 @@ x_menu_show (struct frame *f, int x, int y, int menuflags, | |||
| 2750 | /* If position was not given by a mouse click, adjust so upper left | 2762 | /* If position was not given by a mouse click, adjust so upper left |
| 2751 | corner of the menu as a whole ends up at given coordinates. This | 2763 | corner of the menu as a whole ends up at given coordinates. This |
| 2752 | is what x-popup-menu says in its documentation. */ | 2764 | is what x-popup-menu says in its documentation. */ |
| 2753 | x += width/2; | 2765 | x += width / 2; |
| 2754 | y += 1.5*height/(maxlines+2); | 2766 | y += 1.5 * height/ (maxlines + 2); |
| 2755 | } | 2767 | } |
| 2756 | 2768 | ||
| 2757 | XMenuSetAEQ (menu, true); | 2769 | XMenuSetAEQ (menu, true); |
| @@ -2759,6 +2771,8 @@ x_menu_show (struct frame *f, int x, int y, int menuflags, | |||
| 2759 | pane = selidx = 0; | 2771 | pane = selidx = 0; |
| 2760 | 2772 | ||
| 2761 | #ifndef MSDOS | 2773 | #ifndef MSDOS |
| 2774 | DEFER_SELECTIONS; | ||
| 2775 | |||
| 2762 | XMenuActivateSetWaitFunction (x_menu_wait_for_event, FRAME_X_DISPLAY (f)); | 2776 | XMenuActivateSetWaitFunction (x_menu_wait_for_event, FRAME_X_DISPLAY (f)); |
| 2763 | #ifdef HAVE_XINPUT2 | 2777 | #ifdef HAVE_XINPUT2 |
| 2764 | XMenuActivateSetTranslateFunction (x_menu_translate_generic_event); | 2778 | XMenuActivateSetTranslateFunction (x_menu_translate_generic_event); |
diff --git a/src/xselect.c b/src/xselect.c index d184489cbd8..40b6571e0ad 100644 --- a/src/xselect.c +++ b/src/xselect.c | |||
| @@ -1252,7 +1252,11 @@ x_get_foreign_selection (Lisp_Object selection_symbol, Lisp_Object target_type, | |||
| 1252 | else | 1252 | else |
| 1253 | x_wait_for_cell_change (reading_selection_reply, | 1253 | x_wait_for_cell_change (reading_selection_reply, |
| 1254 | make_timespec (secs, nsecs)); | 1254 | make_timespec (secs, nsecs)); |
| 1255 | TRACE1 (" Got event = %d", !NILP (XCAR (reading_selection_reply))); | 1255 | TRACE1 (" Got event = %s", (!NILP (XCAR (reading_selection_reply)) |
| 1256 | ? (SYMBOLP (XCAR (reading_selection_reply)) | ||
| 1257 | ? SSDATA (SYMBOL_NAME (XCAR (reading_selection_reply))) | ||
| 1258 | : "YES") | ||
| 1259 | : "NO")); | ||
| 1256 | 1260 | ||
| 1257 | if (NILP (XCAR (reading_selection_reply))) | 1261 | if (NILP (XCAR (reading_selection_reply))) |
| 1258 | error ("Timed out waiting for reply from selection owner"); | 1262 | error ("Timed out waiting for reply from selection owner"); |
| @@ -1947,7 +1951,7 @@ x_handle_selection_notify (const XSelectionEvent *event) | |||
| 1947 | if (event->selection != reading_which_selection) | 1951 | if (event->selection != reading_which_selection) |
| 1948 | return; | 1952 | return; |
| 1949 | 1953 | ||
| 1950 | TRACE0 ("Received SelectionNotify"); | 1954 | TRACE1 ("Received SelectionNotify: %d", (int) event->property); |
| 1951 | XSETCAR (reading_selection_reply, | 1955 | XSETCAR (reading_selection_reply, |
| 1952 | (event->property != 0 ? Qt : Qlambda)); | 1956 | (event->property != 0 ? Qt : Qlambda)); |
| 1953 | } | 1957 | } |
diff --git a/src/xterm.c b/src/xterm.c index 444adcf94f1..1f4d301e6a5 100644 --- a/src/xterm.c +++ b/src/xterm.c | |||
| @@ -793,10 +793,43 @@ static struct input_event *current_hold_quit; | |||
| 793 | than 0. */ | 793 | than 0. */ |
| 794 | static int x_use_pending_selection_requests; | 794 | static int x_use_pending_selection_requests; |
| 795 | 795 | ||
| 796 | static void | 796 | static void x_push_selection_request (struct selection_input_event *); |
| 797 | |||
| 798 | /* Defer selection requests. Any selection requests generated after | ||
| 799 | this can then be processed by calling | ||
| 800 | `x_handle_pending_selection_requests'. | ||
| 801 | |||
| 802 | Also run through and queue all the selection events already in the | ||
| 803 | keyboard buffer. */ | ||
| 804 | void | ||
| 797 | x_defer_selection_requests (void) | 805 | x_defer_selection_requests (void) |
| 798 | { | 806 | { |
| 807 | union buffered_input_event *event; | ||
| 808 | |||
| 809 | block_input (); | ||
| 799 | x_use_pending_selection_requests++; | 810 | x_use_pending_selection_requests++; |
| 811 | |||
| 812 | if (!x_use_pending_selection_requests) | ||
| 813 | { | ||
| 814 | event = kbd_fetch_ptr; | ||
| 815 | |||
| 816 | while (event != kbd_store_ptr) | ||
| 817 | { | ||
| 818 | if (event->ie.kind == SELECTION_REQUEST_EVENT | ||
| 819 | || event->ie.kind == SELECTION_CLEAR_EVENT) | ||
| 820 | { | ||
| 821 | x_push_selection_request (&event->sie); | ||
| 822 | |||
| 823 | /* Mark this selection event as invalid. */ | ||
| 824 | SELECTION_EVENT_DPYINFO (&event->sie) = NULL; | ||
| 825 | } | ||
| 826 | |||
| 827 | event = (event == kbd_buffer + KBD_BUFFER_SIZE - 1 | ||
| 828 | ? kbd_buffer : event + 1); | ||
| 829 | } | ||
| 830 | } | ||
| 831 | |||
| 832 | unblock_input (); | ||
| 800 | } | 833 | } |
| 801 | 834 | ||
| 802 | static void | 835 | static void |
| @@ -805,6 +838,15 @@ x_release_selection_requests (void) | |||
| 805 | x_use_pending_selection_requests--; | 838 | x_use_pending_selection_requests--; |
| 806 | } | 839 | } |
| 807 | 840 | ||
| 841 | void | ||
| 842 | x_release_selection_requests_and_flush (void) | ||
| 843 | { | ||
| 844 | x_release_selection_requests (); | ||
| 845 | |||
| 846 | if (!x_use_pending_selection_requests) | ||
| 847 | x_handle_pending_selection_requests (); | ||
| 848 | } | ||
| 849 | |||
| 808 | struct x_selection_request_event | 850 | struct x_selection_request_event |
| 809 | { | 851 | { |
| 810 | /* The selection request event. */ | 852 | /* The selection request event. */ |
| @@ -10764,8 +10806,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, | |||
| 10764 | if (x_dnd_in_progress || x_dnd_waiting_for_finish) | 10806 | if (x_dnd_in_progress || x_dnd_waiting_for_finish) |
| 10765 | error ("A drag-and-drop session is already in progress"); | 10807 | error ("A drag-and-drop session is already in progress"); |
| 10766 | 10808 | ||
| 10767 | x_defer_selection_requests (); | 10809 | DEFER_SELECTIONS; |
| 10768 | record_unwind_protect_void (x_release_selection_requests); | ||
| 10769 | 10810 | ||
| 10770 | /* If local_value is nil, then we lost ownership of XdndSelection. | 10811 | /* If local_value is nil, then we lost ownership of XdndSelection. |
| 10771 | Signal a more informative error than args-out-of-range. */ | 10812 | Signal a more informative error than args-out-of-range. */ |
| @@ -10781,8 +10822,8 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, | |||
| 10781 | if (popup_activated ()) | 10822 | if (popup_activated ()) |
| 10782 | error ("Trying to drag-and-drop from within a menu-entry"); | 10823 | error ("Trying to drag-and-drop from within a menu-entry"); |
| 10783 | 10824 | ||
| 10784 | record_unwind_protect_void (x_free_dnd_targets); | ||
| 10785 | x_set_dnd_targets (target_atoms, ntargets); | 10825 | x_set_dnd_targets (target_atoms, ntargets); |
| 10826 | record_unwind_protect_void (x_free_dnd_targets); | ||
| 10786 | 10827 | ||
| 10787 | ltimestamp = x_timestamp_for_selection (FRAME_DISPLAY_INFO (f), | 10828 | ltimestamp = x_timestamp_for_selection (FRAME_DISPLAY_INFO (f), |
| 10788 | QXdndSelection); | 10829 | QXdndSelection); |
| @@ -15306,7 +15347,7 @@ x_wait_for_cell_change (Lisp_Object cell, struct timespec timeout) | |||
| 15306 | 15347 | ||
| 15307 | #ifndef USE_GTK | 15348 | #ifndef USE_GTK |
| 15308 | FD_ZERO (&rfds); | 15349 | FD_ZERO (&rfds); |
| 15309 | rc = 0; | 15350 | rc = -1; |
| 15310 | #endif | 15351 | #endif |
| 15311 | 15352 | ||
| 15312 | while (true) | 15353 | while (true) |
| @@ -15892,18 +15933,18 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 15892 | break; | 15933 | break; |
| 15893 | 15934 | ||
| 15894 | case SelectionNotify: | 15935 | case SelectionNotify: |
| 15895 | #ifdef USE_X_TOOLKIT | 15936 | #if defined USE_X_TOOLKIT || defined USE_GTK |
| 15896 | if (! x_window_to_frame (dpyinfo, event->xselection.requestor)) | 15937 | if (!x_window_to_frame (dpyinfo, event->xselection.requestor)) |
| 15897 | goto OTHER; | 15938 | goto OTHER; |
| 15898 | #endif /* not USE_X_TOOLKIT */ | 15939 | #endif /* not USE_X_TOOLKIT and not USE_GTK */ |
| 15899 | x_handle_selection_notify (&event->xselection); | 15940 | x_handle_selection_notify (&event->xselection); |
| 15900 | break; | 15941 | break; |
| 15901 | 15942 | ||
| 15902 | case SelectionClear: /* Someone has grabbed ownership. */ | 15943 | case SelectionClear: /* Someone has grabbed ownership. */ |
| 15903 | #ifdef USE_X_TOOLKIT | 15944 | #if defined USE_X_TOOLKIT || defined USE_GTK |
| 15904 | if (! x_window_to_frame (dpyinfo, event->xselectionclear.window)) | 15945 | if (!x_window_to_frame (dpyinfo, event->xselectionclear.window)) |
| 15905 | goto OTHER; | 15946 | goto OTHER; |
| 15906 | #endif /* USE_X_TOOLKIT */ | 15947 | #endif /* not USE_X_TOOLKIT and not USE_GTK */ |
| 15907 | { | 15948 | { |
| 15908 | const XSelectionClearEvent *eventp = &event->xselectionclear; | 15949 | const XSelectionClearEvent *eventp = &event->xselectionclear; |
| 15909 | 15950 | ||
diff --git a/src/xterm.h b/src/xterm.h index 1ab65f15d10..7e91e28ed13 100644 --- a/src/xterm.h +++ b/src/xterm.h | |||
| @@ -1456,6 +1456,12 @@ extern void x_xr_reset_ext_clip (struct frame *f); | |||
| 1456 | extern void x_scroll_bar_configure (GdkEvent *); | 1456 | extern void x_scroll_bar_configure (GdkEvent *); |
| 1457 | #endif | 1457 | #endif |
| 1458 | 1458 | ||
| 1459 | #define DEFER_SELECTIONS \ | ||
| 1460 | x_defer_selection_requests (); \ | ||
| 1461 | record_unwind_protect_void (x_release_selection_requests_and_flush) | ||
| 1462 | |||
| 1463 | extern void x_defer_selection_requests (void); | ||
| 1464 | extern void x_release_selection_requests_and_flush (void); | ||
| 1459 | extern void x_handle_pending_selection_requests (void); | 1465 | extern void x_handle_pending_selection_requests (void); |
| 1460 | extern bool x_detect_pending_selection_requests (void); | 1466 | extern bool x_detect_pending_selection_requests (void); |
| 1461 | extern Lisp_Object x_dnd_begin_drag_and_drop (struct frame *, Time, Atom, | 1467 | extern Lisp_Object x_dnd_begin_drag_and_drop (struct frame *, Time, Atom, |