1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-03-20 05:45:27 -05:00
Simon Tatham 420fe75552 Suspend terminal output while a window resize is pending.
This is the payoff from the last few commits of refactoring. It fixes
the following race-condition bug in terminal application redraw:

 * server sends a window-resizing escape sequence
 * terminal requests a window resize from the front end
 * server sends further escape sequences to perform a redraw of some
   full-screen application, which assume that the window resize has
   occurred and the window is already its new size
 * terminal processes all those sequences in the context of the old
   window size, while the front end is still thinking
 * window resize completes in the front end and term_size() tells the
   terminal it now has its new size, but it's too late, the screen
   redraw has made a total mess.

(Perhaps the server might even send its window resize + followup
redraw all in one SSH packet, so that it's all queued in term->inbuf
in one go.)

As far as I can see, handling of this case has been broken more or
less forever in the GTK frontend (where window resizes are inherently
asynchronous due to the way X11 works, and we've never done anything
to compensate for that). On Windows, where window size is changed via
SetWindowPos which is synchronous, it used to work, but broke in
commit d74308e90e3813a (i.e. between 0.74 and 0.75), which made all
the ancillary window updates run on the same delayed-action timer as
ordinary text display.

So, it's time to fix it, and I think now I should be able to fix it in
GTK as well as on Windows.

Now, as soon as we've set the term->win_resize_pending flag (in
response to a resize escape sequence), the next return to the top of
the main loop in term_out will terminate output processing early,
leaving any further terminal data still in the term->inbuf bufchain.
Once we get a term_size() callback from the front end telling us our
new size, we reset term->win_resize_pending, which unblocks output
processing again, and we also queue a toplevel callback to have
another try at term_out() so that it will be unblocked promptly.

To implement this I've changed term->win_resize_pending from a bool
into a three-state enumeration, so that we can tell the difference
between 'pending' in the sense of not yet having sent our resize
request to the frontend, and in the sense of waiting for the frontend
to reply. That way, a window resize from the GUI user at least won't
be mistaken for the response to our resize request if it arrives in
the former state. (It can still be mistaken for one in the latter
case, but if the user is resizing the window at the same time as the
server-side application is doing critically size-dependent redrawing,
I don't think there can be any reasonable expectation of nothing going
wrong.)

As mentioned in the previous commit, some failure modes under X11 (in
particular the window manager process getting wedged in some way) can
result in no response being received to a ConfigureWindow request. In
that situation, it seems to me that we really _shouldn't_ sit there
waiting forever - perhaps it's technically the WM's fault and not
ours, but what kind of X window are you most likely to want to use to
do emergency WM repair? A terminal window, of course, so it would be
exceptionally unhelpful to make any terminal window stop working
completely in this situation! Hence, there's a fallback timeout in
terminal.c, so that if we don't receive a response in _too_ long,
we'll assume one is not forthcoming, and resume processing terminal
data at the old window size. The fallback timeout is set to 5 seconds,
following existing practice in libXt (DEFAULT_WM_TIMEOUT).
2021-12-19 10:54:59 +00:00
..
2021-10-16 12:03:39 +01:00
2021-10-16 12:03:39 +01:00
2021-10-10 15:00:30 +01:00