aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPo Lu2022-05-30 14:04:43 +0800
committerPo Lu2022-05-30 14:05:30 +0800
commitfd510f12392fcb2bf34eb08262ddda20d8a3c221 (patch)
treebd293cd92a1338e9aab3b80d23e26127485f8cce /src
parent52d41f2750c0f66d7f7ba8e198832734fe750fa5 (diff)
downloademacs-fd510f12392fcb2bf34eb08262ddda20d8a3c221.tar.gz
emacs-fd510f12392fcb2bf34eb08262ddda20d8a3c221.zip
Fix hangs when x-get-selection is called inside a popup menu
* src/xselect.c (wait_for_property_change): (x_get_foreign_selection): Use `x_wait_for_cell_change' if input is blocked. (bug#22214) * src/xterm.c (x_wait_for_cell_change): New function. * src/xterm.h: Update prototypes.
Diffstat (limited to 'src')
-rw-r--r--src/xselect.c22
-rw-r--r--src/xterm.c64
-rw-r--r--src/xterm.h5
3 files changed, 85 insertions, 6 deletions
diff --git a/src/xselect.c b/src/xselect.c
index bfd081b1e28..a4148735945 100644
--- a/src/xselect.c
+++ b/src/xselect.c
@@ -1148,8 +1148,13 @@ wait_for_property_change (struct prop_location *location)
1148 intmax_t secs = timeout / 1000; 1148 intmax_t secs = timeout / 1000;
1149 int nsecs = (timeout % 1000) * 1000000; 1149 int nsecs = (timeout % 1000) * 1000000;
1150 TRACE2 (" Waiting %"PRIdMAX" secs, %d nsecs", secs, nsecs); 1150 TRACE2 (" Waiting %"PRIdMAX" secs, %d nsecs", secs, nsecs);
1151 wait_reading_process_output (secs, nsecs, 0, false, 1151
1152 property_change_reply, NULL, 0); 1152 if (!input_blocked_p ())
1153 wait_reading_process_output (secs, nsecs, 0, false,
1154 property_change_reply, NULL, 0);
1155 else
1156 x_wait_for_cell_change (property_change_reply,
1157 make_timespec (secs, nsecs));
1153 1158
1154 if (NILP (XCAR (property_change_reply))) 1159 if (NILP (XCAR (property_change_reply)))
1155 { 1160 {
@@ -1256,8 +1261,17 @@ x_get_foreign_selection (Lisp_Object selection_symbol, Lisp_Object target_type,
1256 intmax_t secs = timeout / 1000; 1261 intmax_t secs = timeout / 1000;
1257 int nsecs = (timeout % 1000) * 1000000; 1262 int nsecs = (timeout % 1000) * 1000000;
1258 TRACE1 (" Start waiting %"PRIdMAX" secs for SelectionNotify", secs); 1263 TRACE1 (" Start waiting %"PRIdMAX" secs for SelectionNotify", secs);
1259 wait_reading_process_output (secs, nsecs, 0, false, 1264 /* This function can be called with input blocked inside Xt or GTK
1260 reading_selection_reply, NULL, 0); 1265 timeouts run inside popup menus, so use a function that works
1266 when input is blocked. Prefer wait_reading_process_output
1267 otherwise, or the toolkit might not get some events.
1268 (bug#22214) */
1269 if (!input_blocked_p ())
1270 wait_reading_process_output (secs, nsecs, 0, false,
1271 reading_selection_reply, NULL, 0);
1272 else
1273 x_wait_for_cell_change (reading_selection_reply,
1274 make_timespec (secs, nsecs));
1261 TRACE1 (" Got event = %d", !NILP (XCAR (reading_selection_reply))); 1275 TRACE1 (" Got event = %d", !NILP (XCAR (reading_selection_reply)));
1262 1276
1263 if (NILP (XCAR (reading_selection_reply))) 1277 if (NILP (XCAR (reading_selection_reply)))
diff --git a/src/xterm.c b/src/xterm.c
index eee888f6fe6..777a6c4dafc 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -14836,6 +14836,70 @@ x_display_pixel_width (struct x_display_info *dpyinfo)
14836 return WidthOfScreen (dpyinfo->screen); 14836 return WidthOfScreen (dpyinfo->screen);
14837} 14837}
14838 14838
14839/* Handle events from each display until CELL's car becomes non-nil,
14840 or TIMEOUT elapses. */
14841void
14842x_wait_for_cell_change (Lisp_Object cell, struct timespec timeout)
14843{
14844 struct x_display_info *dpyinfo;
14845 fd_set fds;
14846 int fd, maxfd, finish;
14847 XEvent event;
14848 struct input_event hold_quit;
14849 struct timespec current, at;
14850
14851 at = timespec_add (current_timespec (), timeout);
14852
14853 while (true)
14854 {
14855 FD_ZERO (&fds);
14856 maxfd = -1;
14857
14858 for (dpyinfo = x_display_list; dpyinfo;
14859 dpyinfo = dpyinfo->next)
14860 {
14861 if (XPending (dpyinfo->display))
14862 {
14863 EVENT_INIT (hold_quit);
14864
14865 XNextEvent (dpyinfo->display, &event);
14866 handle_one_xevent (dpyinfo, &event,
14867 &finish, &hold_quit);
14868
14869 /* Make us quit now. */
14870 if (hold_quit.kind != NO_EVENT)
14871 kbd_buffer_store_event (&hold_quit);
14872
14873 if (!NILP (XCAR (cell)))
14874 return;
14875 }
14876
14877 fd = XConnectionNumber (dpyinfo->display);
14878
14879 if (fd > maxfd)
14880 maxfd = fd;
14881
14882 eassert (fd < FD_SETSIZE);
14883 FD_SET (XConnectionNumber (dpyinfo->display), &fds);
14884 }
14885
14886 eassert (maxfd >= 0);
14887
14888 current = current_timespec ();
14889
14890 if (timespec_cmp (at, current) < 0
14891 || !NILP (XCAR (cell)))
14892 return;
14893
14894 timeout = timespec_sub (at, current);
14895
14896 /* We don't have to check the return of pselect, because if an
14897 error occurs XPending will call the IO error handler, which
14898 then brings us out of this loop. */
14899 pselect (maxfd, &fds, NULL, NULL, &timeout, NULL);
14900 }
14901}
14902
14839#ifdef USE_GTK 14903#ifdef USE_GTK
14840static void 14904static void
14841x_monitors_changed_cb (GdkScreen *gscr, gpointer user_data) 14905x_monitors_changed_cb (GdkScreen *gscr, gpointer user_data)
diff --git a/src/xterm.h b/src/xterm.h
index c8e86d5d094..d7e184ed9f1 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -1386,8 +1386,8 @@ extern const char *x_get_string_resource (void *, const char *, const char *);
1386 1386
1387/* Defined in xterm.c */ 1387/* Defined in xterm.c */
1388 1388
1389typedef void (*x_special_error_handler)(Display *, XErrorEvent *, char *, 1389typedef void (*x_special_error_handler) (Display *, XErrorEvent *, char *,
1390 void *); 1390 void *);
1391 1391
1392extern bool x_text_icon (struct frame *, const char *); 1392extern bool x_text_icon (struct frame *, const char *);
1393extern void x_catch_errors (Display *); 1393extern void x_catch_errors (Display *);
@@ -1425,6 +1425,7 @@ extern void x_clear_area (struct frame *f, int, int, int, int);
1425 || (!defined USE_X_TOOLKIT && !defined USE_GTK) 1425 || (!defined USE_X_TOOLKIT && !defined USE_GTK)
1426extern void x_mouse_leave (struct x_display_info *); 1426extern void x_mouse_leave (struct x_display_info *);
1427#endif 1427#endif
1428extern void x_wait_for_cell_change (Lisp_Object, struct timespec);
1428 1429
1429#ifndef USE_GTK 1430#ifndef USE_GTK
1430extern int x_dispatch_event (XEvent *, Display *); 1431extern int x_dispatch_event (XEvent *, Display *);