aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPo Lu2022-06-08 15:08:09 +0800
committerPo Lu2022-06-08 15:08:27 +0800
commit22d3f0e95a5602b2bde763cff185f5b4fed6e53e (patch)
tree1a20706bfe3ad7228209ad2ed783753534caac5e /src
parent90f3da0ccdb4c58265e9f8c3d9465198d8a2092a (diff)
downloademacs-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.c3
-rw-r--r--src/xmenu.c24
-rw-r--r--src/xselect.c8
-rw-r--r--src/xterm.c63
-rw-r--r--src/xterm.h6
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. */
794static int x_use_pending_selection_requests; 794static int x_use_pending_selection_requests;
795 795
796static void 796static 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. */
804void
797x_defer_selection_requests (void) 805x_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
802static void 835static 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
841void
842x_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
808struct x_selection_request_event 850struct 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);
1456extern void x_scroll_bar_configure (GdkEvent *); 1456extern 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
1463extern void x_defer_selection_requests (void);
1464extern void x_release_selection_requests_and_flush (void);
1459extern void x_handle_pending_selection_requests (void); 1465extern void x_handle_pending_selection_requests (void);
1460extern bool x_detect_pending_selection_requests (void); 1466extern bool x_detect_pending_selection_requests (void);
1461extern Lisp_Object x_dnd_begin_drag_and_drop (struct frame *, Time, Atom, 1467extern Lisp_Object x_dnd_begin_drag_and_drop (struct frame *, Time, Atom,