mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-02-17 01:34:21 +00:00
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.
This commit is contained in:
parent
52d41f2750
commit
fd510f1239
3 changed files with 85 additions and 6 deletions
|
|
@ -1148,8 +1148,13 @@ wait_for_property_change (struct prop_location *location)
|
|||
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)))
|
||||
{
|
||||
|
|
@ -1256,8 +1261,17 @@ x_get_foreign_selection (Lisp_Object selection_symbol, Lisp_Object target_type,
|
|||
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)))
|
||||
|
|
|
|||
64
src/xterm.c
64
src/xterm.c
|
|
@ -14836,6 +14836,70 @@ x_display_pixel_width (struct x_display_info *dpyinfo)
|
|||
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)
|
||||
|
|
|
|||
|
|
@ -1386,8 +1386,8 @@ extern const char *x_get_string_resource (void *, const char *, const char *);
|
|||
|
||||
/* 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 *);
|
||||
|
|
@ -1425,6 +1425,7 @@ extern void x_clear_area (struct frame *f, int, int, int, int);
|
|||
|| (!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 *);
|
||||
|
|
|
|||
Loading…
Reference in a new issue