diff options
| author | Po Lu | 2022-05-30 14:04:43 +0800 |
|---|---|---|
| committer | Po Lu | 2022-05-30 14:05:30 +0800 |
| commit | fd510f12392fcb2bf34eb08262ddda20d8a3c221 (patch) | |
| tree | bd293cd92a1338e9aab3b80d23e26127485f8cce /src | |
| parent | 52d41f2750c0f66d7f7ba8e198832734fe750fa5 (diff) | |
| download | emacs-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.c | 22 | ||||
| -rw-r--r-- | src/xterm.c | 64 | ||||
| -rw-r--r-- | src/xterm.h | 5 |
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. */ | ||
| 14841 | void | ||
| 14842 | x_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 |
| 14840 | static void | 14904 | static void |
| 14841 | x_monitors_changed_cb (GdkScreen *gscr, gpointer user_data) | 14905 | x_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 | ||
| 1389 | typedef void (*x_special_error_handler)(Display *, XErrorEvent *, char *, | 1389 | typedef void (*x_special_error_handler) (Display *, XErrorEvent *, char *, |
| 1390 | void *); | 1390 | void *); |
| 1391 | 1391 | ||
| 1392 | extern bool x_text_icon (struct frame *, const char *); | 1392 | extern bool x_text_icon (struct frame *, const char *); |
| 1393 | extern void x_catch_errors (Display *); | 1393 | extern 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) |
| 1426 | extern void x_mouse_leave (struct x_display_info *); | 1426 | extern void x_mouse_leave (struct x_display_info *); |
| 1427 | #endif | 1427 | #endif |
| 1428 | extern void x_wait_for_cell_change (Lisp_Object, struct timespec); | ||
| 1428 | 1429 | ||
| 1429 | #ifndef USE_GTK | 1430 | #ifndef USE_GTK |
| 1430 | extern int x_dispatch_event (XEvent *, Display *); | 1431 | extern int x_dispatch_event (XEvent *, Display *); |