intmax_t secs = timeout / 1000;
int nsecs = (timeout % 1000) * 1000000;
TRACE2 (" Waiting %"PRIdMAX" secs, %d nsecs", secs, nsecs);
- wait_reading_process_output (secs, nsecs, 0, false,
- property_change_reply, NULL, 0);
+
+ if (!input_blocked_p ())
+ wait_reading_process_output (secs, nsecs, 0, false,
+ property_change_reply, NULL, 0);
+ else
+ x_wait_for_cell_change (property_change_reply,
+ make_timespec (secs, nsecs));
if (NILP (XCAR (property_change_reply)))
{
intmax_t secs = timeout / 1000;
int nsecs = (timeout % 1000) * 1000000;
TRACE1 (" Start waiting %"PRIdMAX" secs for SelectionNotify", secs);
- wait_reading_process_output (secs, nsecs, 0, false,
- reading_selection_reply, NULL, 0);
+ /* This function can be called with input blocked inside Xt or GTK
+ timeouts run inside popup menus, so use a function that works
+ when input is blocked. Prefer wait_reading_process_output
+ otherwise, or the toolkit might not get some events.
+ (bug#22214) */
+ if (!input_blocked_p ())
+ wait_reading_process_output (secs, nsecs, 0, false,
+ reading_selection_reply, NULL, 0);
+ else
+ x_wait_for_cell_change (reading_selection_reply,
+ make_timespec (secs, nsecs));
TRACE1 (" Got event = %d", !NILP (XCAR (reading_selection_reply)));
if (NILP (XCAR (reading_selection_reply)))
return WidthOfScreen (dpyinfo->screen);
}
+/* Handle events from each display until CELL's car becomes non-nil,
+ or TIMEOUT elapses. */
+void
+x_wait_for_cell_change (Lisp_Object cell, struct timespec timeout)
+{
+ struct x_display_info *dpyinfo;
+ fd_set fds;
+ int fd, maxfd, finish;
+ XEvent event;
+ struct input_event hold_quit;
+ struct timespec current, at;
+
+ at = timespec_add (current_timespec (), timeout);
+
+ while (true)
+ {
+ FD_ZERO (&fds);
+ maxfd = -1;
+
+ for (dpyinfo = x_display_list; dpyinfo;
+ dpyinfo = dpyinfo->next)
+ {
+ if (XPending (dpyinfo->display))
+ {
+ EVENT_INIT (hold_quit);
+
+ XNextEvent (dpyinfo->display, &event);
+ handle_one_xevent (dpyinfo, &event,
+ &finish, &hold_quit);
+
+ /* Make us quit now. */
+ if (hold_quit.kind != NO_EVENT)
+ kbd_buffer_store_event (&hold_quit);
+
+ if (!NILP (XCAR (cell)))
+ return;
+ }
+
+ fd = XConnectionNumber (dpyinfo->display);
+
+ if (fd > maxfd)
+ maxfd = fd;
+
+ eassert (fd < FD_SETSIZE);
+ FD_SET (XConnectionNumber (dpyinfo->display), &fds);
+ }
+
+ eassert (maxfd >= 0);
+
+ current = current_timespec ();
+
+ if (timespec_cmp (at, current) < 0
+ || !NILP (XCAR (cell)))
+ return;
+
+ timeout = timespec_sub (at, current);
+
+ /* We don't have to check the return of pselect, because if an
+ error occurs XPending will call the IO error handler, which
+ then brings us out of this loop. */
+ pselect (maxfd, &fds, NULL, NULL, &timeout, NULL);
+ }
+}
+
#ifdef USE_GTK
static void
x_monitors_changed_cb (GdkScreen *gscr, gpointer user_data)
/* Defined in xterm.c */
-typedef void (*x_special_error_handler)(Display *, XErrorEvent *, char *,
- void *);
+typedef void (*x_special_error_handler) (Display *, XErrorEvent *, char *,
+ void *);
extern bool x_text_icon (struct frame *, const char *);
extern void x_catch_errors (Display *);
|| (!defined USE_X_TOOLKIT && !defined USE_GTK)
extern void x_mouse_leave (struct x_display_info *);
#endif
+extern void x_wait_for_cell_change (Lisp_Object, struct timespec);
#ifndef USE_GTK
extern int x_dispatch_event (XEvent *, Display *);