From 3b8e60de58ae2b2f9fafd806e9f888e716a0f22b Mon Sep 17 00:00:00 2001 From: Noam Postavsky Date: Wed, 30 Aug 2017 23:12:22 -0400 Subject: [PATCH v1] Bring back the busy wait after x_make_frame_visible (Bug#25521) But limit the wait to a configurable timeout. This mostly reverts "Don't wait for frame to become visible". * src/xterm.c (syms_of_xterm) [x-visible-frame-timeout]: New variable. * src/xterm.c (x_make_frame_visible): * src/w32term.c (x_make_frame_visible): Wait for frame to become visible according to its value. --- src/w32term.c | 13 ++++++++---- src/xterm.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 74 insertions(+), 6 deletions(-) diff --git a/src/w32term.c b/src/w32term.c index 2785ae2b52..8b129ae029 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -6609,7 +6609,8 @@ w32_frame_raise_lower (struct frame *f, bool raise_flag) /* Change of visibility. */ -/* This tries to wait until the frame is really visible. +/* This tries to wait until the frame is really visible, depending on + the value of Vx_visible_frame_timeout. However, if the window manager asks the user where to position the frame, this will return before the user finishes doing that. The frame will not actually be visible at that time, @@ -6668,12 +6669,16 @@ x_make_frame_visible (struct frame *f) : SW_SHOWNORMAL); } + if (!FLOATP (Vx_visible_frame_timeout)) + return; + /* Synchronize to ensure Emacs knows the frame is visible before we do anything else. We do this loop with input not blocked so that incoming events are handled. */ { Lisp_Object frame; - int count; + double timeout = XFLOAT_DATA (Vx_visible_frame_timeout); + double start_time = XFLOAT_DATA (Ffloat_time (Qnil)); /* This must come after we set COUNT. */ unblock_input (); @@ -6683,8 +6688,8 @@ x_make_frame_visible (struct frame *f) /* Wait until the frame is visible. Process X events until a MapNotify event has been seen, or until we think we won't get a MapNotify at all.. */ - for (count = input_signal_count + 10; - input_signal_count < count && !FRAME_VISIBLE_P (f);) + while (timeout > (XFLOAT_DATA (Ffloat_time (Qnil)) - start_time) && + !FRAME_VISIBLE_P (f)) { /* Force processing of queued events. */ /* TODO: x_sync equivalent? */ diff --git a/src/xterm.c b/src/xterm.c index a7a52064a1..3ade688f1b 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -11373,8 +11373,13 @@ xembed_send_message (struct frame *f, Time t, enum xembed_message msg, /* Change of visibility. */ -/* This function sends the request to make the frame visible, but may - return before it the frame's visibility is changed. */ +/* This tries to wait until the frame is really visible, depending on + the value of Vx_visible_frame_timeout. + However, if the window manager asks the user where to position + the frame, this will return before the user finishes doing that. + The frame will not actually be visible at that time, + but it will become visible later when the window manager + finishes with it. */ void x_make_frame_visible (struct frame *f) @@ -11445,11 +11450,14 @@ x_make_frame_visible (struct frame *f) before we do anything else. We do this loop with input not blocked so that incoming events are handled. */ { + Lisp_Object frame; /* This must be before UNBLOCK_INPUT since events that arrive in response to the actions above will set it when they are handled. */ bool previously_visible = f->output_data.x->has_been_visible; + XSETFRAME (frame, f); + int original_left = f->left_pos; int original_top = f->top_pos; @@ -11496,6 +11504,48 @@ x_make_frame_visible (struct frame *f) unblock_input (); } + + + if (!FLOATP (Vx_visible_frame_timeout)) + return; + + double timeout = XFLOAT_DATA (Vx_visible_frame_timeout); + double start_time = XFLOAT_DATA (Ffloat_time (Qnil)); + + /* Process X events until a MapNotify event has been seen. */ + while (timeout > (XFLOAT_DATA (Ffloat_time (Qnil)) - start_time) && + !FRAME_VISIBLE_P (f)) + { + /* Force processing of queued events. */ + x_sync (f); + + /* This hack is still in use at least for Cygwin. See + http://lists.gnu.org/archive/html/emacs-devel/2013-12/msg00351.html. + + Machines that do polling rather than SIGIO have been + observed to go into a busy-wait here. So we'll fake an + alarm signal to let the handler know that there's something + to be read. We used to raise a real alarm, but it seems + that the handler isn't always enabled here. This is + probably a bug. */ + if (input_polling_used ()) + { + /* It could be confusing if a real alarm arrives while + processing the fake one. Turn it off and let the + handler reset it. */ + int old_poll_suppress_count = poll_suppress_count; + poll_suppress_count = 1; + poll_for_input_1 (); + poll_suppress_count = old_poll_suppress_count; + } + + if (XPending (FRAME_X_DISPLAY (f))) + { + XEvent xev; + XNextEvent (FRAME_X_DISPLAY (f), &xev); + x_dispatch_event (&xev, FRAME_X_DISPLAY (f)); + } + } } } @@ -13291,6 +13341,19 @@ syms_of_xterm (void) keysyms. The default is nil, which is the same as `super'. */); Vx_super_keysym = Qnil; + DEFVAR_LISP ("x-visible-frame-timeout", Vx_visible_frame_timeout, + doc: /* How long to wait for a frame to become visible. +Emacs will wait up to this many seconds after `make-frame-visible' is +called until receiving notification from the windowing system that the +frame has become visible. Under some window managers this can take an +indefinite amount of time, so it is important to limit the wait. + +If set to a non-float value, there will be no wait at all. This +should be fine unless your config contains some code that assumes +frames will become visible immediately (e.g., calling +`select-frame-by-name' directly after creating a named frame). */); + Vx_visible_frame_timeout = make_float (0.5); + DEFVAR_LISP ("x-keysym-table", Vx_keysym_table, doc: /* Hash table of character codes indexed by X keysym codes. */); Vx_keysym_table = make_hash_table (hashtest_eql, 900, -- 2.14.1