mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-03-20 05:45:27 -05:00

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).