mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-10 01:48:00 +00:00
Move window resize timeouts into the GTK frontend.
In the changes around commit 420fe75552
, I made the terminal
suspend output processing while it waited for a term_size() callback
in response to a resize request. Because on X11 there are unusual
circumstances in which you never receive that callback, I also added a
last-ditch 5-second timeout, so that eventually we'll resume terminal
output processing regardless.
But the timeout lives in terminal.c, in the cross-platform code. This
is pointless on Windows (where resize processing is synchronous, so we
always finish it before the timer code next gets called anyway), but I
decided it was easier to keep the whole mechanism in terminal.c in the
absence of a good reason not to.
Now I've found that reason. We _also_ generate window resizes locally
to the GTK front end, in response to the key combinations that change
the font size, and _those_ still have an asynchrony problem.
So, to begin with, I'm refactoring the request_resize system so that
now there's an explicit callback from the frontend to the terminal to
say 'Your resize request has now been processed, whether or not you've
received a term_size() call'. On Windows, this simplifies matters
greatly because we always know exactly when to call that, and don't
have to keep a 'have we called term_size() already?' flag. On GTK, the
timing complexity previously in terminal.c has moved into window.c.
No functional change (I hope). The payoff will be in the next commit.
This commit is contained in:
parent
de66b0313a
commit
4da67d8fa6
12
putty.h
12
putty.h
@ -1636,6 +1636,17 @@ struct TermWinVtable {
|
|||||||
|
|
||||||
void (*refresh)(TermWin *);
|
void (*refresh)(TermWin *);
|
||||||
|
|
||||||
|
/* request_resize asks the front end if the terminal can please be
|
||||||
|
* resized to (w,h) in characters. The front end MAY call
|
||||||
|
* term_size() in response to tell the terminal its new size
|
||||||
|
* (which MAY be the requested size, or some other size if the
|
||||||
|
* requested one can't be achieved). The front end MAY also not
|
||||||
|
* call term_size() at all. But the front end MUST reply to this
|
||||||
|
* request by calling term_resize_request_completed(), after the
|
||||||
|
* responding resize event has taken place (if any).
|
||||||
|
*
|
||||||
|
* The calls to term_size and term_resize_request_completed may be
|
||||||
|
* synchronous callbacks from within the call to request_resize(). */
|
||||||
void (*request_resize)(TermWin *, int w, int h);
|
void (*request_resize)(TermWin *, int w, int h);
|
||||||
|
|
||||||
void (*set_title)(TermWin *, const char *title, int codepage);
|
void (*set_title)(TermWin *, const char *title, int codepage);
|
||||||
@ -2133,6 +2144,7 @@ FontSpec *platform_default_fontspec(const char *name);
|
|||||||
Terminal *term_init(Conf *, struct unicode_data *, TermWin *);
|
Terminal *term_init(Conf *, struct unicode_data *, TermWin *);
|
||||||
void term_free(Terminal *);
|
void term_free(Terminal *);
|
||||||
void term_size(Terminal *, int, int, int);
|
void term_size(Terminal *, int, int, int);
|
||||||
|
void term_resize_request_completed(Terminal *);
|
||||||
void term_paint(Terminal *, int, int, int, int, bool);
|
void term_paint(Terminal *, int, int, int, int, bool);
|
||||||
void term_scroll(Terminal *, int, int);
|
void term_scroll(Terminal *, int, int);
|
||||||
void term_scroll_to_selection(Terminal *, int);
|
void term_scroll_to_selection(Terminal *, int);
|
||||||
|
@ -1220,12 +1220,6 @@ static void term_timer(void *ctx, unsigned long now)
|
|||||||
|
|
||||||
if (term->window_update_pending)
|
if (term->window_update_pending)
|
||||||
term_update_callback(term);
|
term_update_callback(term);
|
||||||
|
|
||||||
if (term->win_resize_pending == WIN_RESIZE_AWAIT_REPLY &&
|
|
||||||
now == term->win_resize_timeout) {
|
|
||||||
term->win_resize_pending = WIN_RESIZE_NO;
|
|
||||||
queue_toplevel_callback(term_out_cb, term);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void term_update_callback(void *ctx)
|
static void term_update_callback(void *ctx)
|
||||||
@ -1426,8 +1420,6 @@ void term_update(Terminal *term)
|
|||||||
term->win_resize_pending = WIN_RESIZE_AWAIT_REPLY;
|
term->win_resize_pending = WIN_RESIZE_AWAIT_REPLY;
|
||||||
win_request_resize(term->win, term->win_resize_pending_w,
|
win_request_resize(term->win, term->win_resize_pending_w,
|
||||||
term->win_resize_pending_h);
|
term->win_resize_pending_h);
|
||||||
term->win_resize_timeout = schedule_timer(
|
|
||||||
WIN_RESIZE_TIMEOUT, term_timer, term);
|
|
||||||
}
|
}
|
||||||
if (term->win_zorder_pending) {
|
if (term->win_zorder_pending) {
|
||||||
win_set_zorder(term->win, term->win_zorder_top);
|
win_set_zorder(term->win, term->win_zorder_top);
|
||||||
@ -2151,14 +2143,6 @@ void term_size(Terminal *term, int newrows, int newcols, int newsavelines)
|
|||||||
int sblen;
|
int sblen;
|
||||||
int save_alt_which = term->alt_which;
|
int save_alt_which = term->alt_which;
|
||||||
|
|
||||||
/* If we were holding buffered terminal data because we were
|
|
||||||
* waiting for confirmation of a resize, queue a callback to start
|
|
||||||
* processing it again. */
|
|
||||||
if (term->win_resize_pending == WIN_RESIZE_AWAIT_REPLY) {
|
|
||||||
term->win_resize_pending = WIN_RESIZE_NO;
|
|
||||||
queue_toplevel_callback(term_out_cb, term);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newrows == term->rows && newcols == term->cols &&
|
if (newrows == term->rows && newcols == term->cols &&
|
||||||
newsavelines == term->savelines)
|
newsavelines == term->savelines)
|
||||||
return; /* nothing to do */
|
return; /* nothing to do */
|
||||||
@ -2336,6 +2320,13 @@ void term_size(Terminal *term, int newrows, int newcols, int newsavelines)
|
|||||||
backend_size(term->backend, term->cols, term->rows);
|
backend_size(term->backend, term->cols, term->rows);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void term_resize_request_completed(Terminal *term)
|
||||||
|
{
|
||||||
|
assert(term->win_resize_pending == WIN_RESIZE_AWAIT_REPLY);
|
||||||
|
term->win_resize_pending = WIN_RESIZE_NO;
|
||||||
|
queue_toplevel_callback(term_out_cb, term);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hand a backend to the terminal, so it can be notified of resizes.
|
* Hand a backend to the terminal, so it can be notified of resizes.
|
||||||
*/
|
*/
|
||||||
|
@ -427,24 +427,6 @@ struct terminal_tag {
|
|||||||
WIN_RESIZE_NO, WIN_RESIZE_NEED_SEND, WIN_RESIZE_AWAIT_REPLY
|
WIN_RESIZE_NO, WIN_RESIZE_NEED_SEND, WIN_RESIZE_AWAIT_REPLY
|
||||||
} win_resize_pending;
|
} win_resize_pending;
|
||||||
int win_resize_pending_w, win_resize_pending_h;
|
int win_resize_pending_w, win_resize_pending_h;
|
||||||
|
|
||||||
/*
|
|
||||||
* Not every frontend / TermWin implementation can be relied on
|
|
||||||
* 100% to reply to a resize request in a timely manner. (In X11
|
|
||||||
* it's all asynchronous and goes via the window manager, and if
|
|
||||||
* your window manager is seriously unwell, you'd rather not have
|
|
||||||
* terminal windows start becoming unusable as a knock-on effect,
|
|
||||||
* since those are just the thing you might need to use for
|
|
||||||
* emergency WM maintenance!) So when we enter AWAIT_REPLY status,
|
|
||||||
* we also set a 5-second timer, after which we'll regretfully
|
|
||||||
* conclude that a resize is probably not going to happen after
|
|
||||||
* all.
|
|
||||||
*
|
|
||||||
* However, in non-emergency cases, the plan is that this
|
|
||||||
* shouldn't be needed, for one reason or another.
|
|
||||||
*/
|
|
||||||
long win_resize_timeout;
|
|
||||||
#define WIN_RESIZE_TIMEOUT (TICKSPERSEC*5)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline bool in_utf(Terminal *term)
|
static inline bool in_utf(Terminal *term)
|
||||||
|
@ -189,6 +189,24 @@ struct GtkFrontend {
|
|||||||
#endif
|
#endif
|
||||||
int trust_sigil_w, trust_sigil_h;
|
int trust_sigil_w, trust_sigil_h;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Not every GDK backend can be relied on 100% to reply to a
|
||||||
|
* resize request in a timely manner. (In X11 it's all
|
||||||
|
* asynchronous and goes via the window manager, and if your
|
||||||
|
* window manager is seriously unwell, you'd rather not have
|
||||||
|
* terminal windows start becoming unusable as a knock-on effect,
|
||||||
|
* since those are just the thing you might need to use for
|
||||||
|
* emergency WM maintenance!)
|
||||||
|
*
|
||||||
|
* So when we ask GTK to resize our terminal window, we also set a
|
||||||
|
* 5-second timer, after which we'll regretfully conclude that a
|
||||||
|
* resize (or ConfigureNotify telling us no resize took place) is
|
||||||
|
* probably not going to happen after all.
|
||||||
|
*/
|
||||||
|
bool win_resize_pending, term_resize_notification_required;
|
||||||
|
long win_resize_timeout;
|
||||||
|
#define WIN_RESIZE_TIMEOUT (TICKSPERSEC*5)
|
||||||
|
|
||||||
Seat seat;
|
Seat seat;
|
||||||
TermWin termwin;
|
TermWin termwin;
|
||||||
LogPolicy logpolicy;
|
LogPolicy logpolicy;
|
||||||
@ -759,6 +777,10 @@ static void drawing_area_setup(GtkFrontend *inst, int width, int height)
|
|||||||
inst->drawing_area_setup_called = true;
|
inst->drawing_area_setup_called = true;
|
||||||
if (inst->term)
|
if (inst->term)
|
||||||
term_size(inst->term, h, w, conf_get_int(inst->conf, CONF_savelines));
|
term_size(inst->term, h, w, conf_get_int(inst->conf, CONF_savelines));
|
||||||
|
if (inst->term_resize_notification_required)
|
||||||
|
term_resize_request_completed(inst->term);
|
||||||
|
if (inst->win_resize_pending)
|
||||||
|
inst->win_resize_pending = false;
|
||||||
|
|
||||||
if (!inst->drawing_area_setup_needed)
|
if (!inst->drawing_area_setup_needed)
|
||||||
return;
|
return;
|
||||||
@ -2480,6 +2502,17 @@ static void gtkwin_deny_term_resize(void *vctx)
|
|||||||
drawing_area_setup_simple(inst);
|
drawing_area_setup_simple(inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void gtkwin_timer(void *vctx, unsigned long now)
|
||||||
|
{
|
||||||
|
GtkFrontend *inst = (GtkFrontend *)vctx;
|
||||||
|
|
||||||
|
if (inst->win_resize_pending && now == inst->win_resize_timeout) {
|
||||||
|
if (inst->term_resize_notification_required)
|
||||||
|
term_resize_request_completed(inst->term);
|
||||||
|
inst->win_resize_pending = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void gtkwin_request_resize(TermWin *tw, int w, int h)
|
static void gtkwin_request_resize(TermWin *tw, int w, int h)
|
||||||
{
|
{
|
||||||
GtkFrontend *inst = container_of(tw, GtkFrontend, termwin);
|
GtkFrontend *inst = container_of(tw, GtkFrontend, termwin);
|
||||||
@ -2525,6 +2558,7 @@ static void gtkwin_request_resize(TermWin *tw, int w, int h)
|
|||||||
#endif
|
#endif
|
||||||
0)) {
|
0)) {
|
||||||
queue_toplevel_callback(gtkwin_deny_term_resize, inst);
|
queue_toplevel_callback(gtkwin_deny_term_resize, inst);
|
||||||
|
term_resize_request_completed(inst->term);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2613,6 +2647,10 @@ static void gtkwin_request_resize(TermWin *tw, int w, int h)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
inst->win_resize_pending = true;
|
||||||
|
inst->term_resize_notification_required = true;
|
||||||
|
inst->win_resize_timeout = schedule_timer(
|
||||||
|
WIN_RESIZE_TIMEOUT, gtkwin_timer, inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if GTK_CHECK_VERSION(3,0,0)
|
#if GTK_CHECK_VERSION(3,0,0)
|
||||||
|
@ -1667,8 +1667,6 @@ static void deinit_fonts(void)
|
|||||||
trust_icon = INVALID_HANDLE_VALUE;
|
trust_icon = INVALID_HANDLE_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool sent_term_size; /* only live during wintw_request_resize() */
|
|
||||||
|
|
||||||
static void wintw_request_resize(TermWin *tw, int w, int h)
|
static void wintw_request_resize(TermWin *tw, int w, int h)
|
||||||
{
|
{
|
||||||
const struct BackendVtable *vt;
|
const struct BackendVtable *vt;
|
||||||
@ -1716,28 +1714,12 @@ static void wintw_request_resize(TermWin *tw, int w, int h)
|
|||||||
|
|
||||||
if (conf_get_int(conf, CONF_resize_action) != RESIZE_FONT &&
|
if (conf_get_int(conf, CONF_resize_action) != RESIZE_FONT &&
|
||||||
!IsZoomed(wgs.term_hwnd)) {
|
!IsZoomed(wgs.term_hwnd)) {
|
||||||
/*
|
|
||||||
* We want to send exactly one term_size() to the terminal,
|
|
||||||
* telling it what size it ended up after this operation.
|
|
||||||
*
|
|
||||||
* If we don't get the size we asked for in SetWindowPos, then
|
|
||||||
* we'll be sent a WM_SIZE message, whose handler will make
|
|
||||||
* that call, all before SetWindowPos even returns to here.
|
|
||||||
*
|
|
||||||
* But if that _didn't_ happen, we'll need to call term_size
|
|
||||||
* ourselves afterwards.
|
|
||||||
*/
|
|
||||||
sent_term_size = false;
|
|
||||||
|
|
||||||
width = extra_width + font_width * w;
|
width = extra_width + font_width * w;
|
||||||
height = extra_height + font_height * h;
|
height = extra_height + font_height * h;
|
||||||
|
|
||||||
SetWindowPos(wgs.term_hwnd, NULL, 0, 0, width, height,
|
SetWindowPos(wgs.term_hwnd, NULL, 0, 0, width, height,
|
||||||
SWP_NOACTIVATE | SWP_NOCOPYBITS |
|
SWP_NOACTIVATE | SWP_NOCOPYBITS |
|
||||||
SWP_NOMOVE | SWP_NOZORDER);
|
SWP_NOMOVE | SWP_NOZORDER);
|
||||||
|
|
||||||
if (!sent_term_size)
|
|
||||||
term_size(term, h, w, conf_get_int(conf, CONF_savelines));
|
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* If we're resizing by changing the font, we must tell the
|
* If we're resizing by changing the font, we must tell the
|
||||||
@ -1748,6 +1730,7 @@ static void wintw_request_resize(TermWin *tw, int w, int h)
|
|||||||
reset_window(0);
|
reset_window(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
term_resize_request_completed(term);
|
||||||
InvalidateRect(wgs.term_hwnd, NULL, true);
|
InvalidateRect(wgs.term_hwnd, NULL, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2188,11 +2171,6 @@ static void wm_size_resize_term(LPARAM lParam, bool border)
|
|||||||
} else {
|
} else {
|
||||||
term_size(term, h, w,
|
term_size(term, h, w,
|
||||||
conf_get_int(conf, CONF_savelines));
|
conf_get_int(conf, CONF_savelines));
|
||||||
/* If this is happening re-entrantly during the call to
|
|
||||||
* SetWindowPos in wintw_request_resize, let it know that
|
|
||||||
* we've already done a term_size() so that it doesn't have
|
|
||||||
* to. */
|
|
||||||
sent_term_size = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user