diff --git a/putty.h b/putty.h index e16a5d04..b15425a9 100644 --- a/putty.h +++ b/putty.h @@ -1636,6 +1636,17 @@ struct TermWinVtable { 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 (*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 *); void term_free(Terminal *); void term_size(Terminal *, int, int, int); +void term_resize_request_completed(Terminal *); void term_paint(Terminal *, int, int, int, int, bool); void term_scroll(Terminal *, int, int); void term_scroll_to_selection(Terminal *, int); diff --git a/terminal/terminal.c b/terminal/terminal.c index ca36e4f9..fbaa619b 100644 --- a/terminal/terminal.c +++ b/terminal/terminal.c @@ -1220,12 +1220,6 @@ static void term_timer(void *ctx, unsigned long now) if (term->window_update_pending) 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) @@ -1426,8 +1420,6 @@ void term_update(Terminal *term) term->win_resize_pending = WIN_RESIZE_AWAIT_REPLY; win_request_resize(term->win, term->win_resize_pending_w, term->win_resize_pending_h); - term->win_resize_timeout = schedule_timer( - WIN_RESIZE_TIMEOUT, term_timer, term); } if (term->win_zorder_pending) { 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 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 && newsavelines == term->savelines) 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); } +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. */ diff --git a/terminal/terminal.h b/terminal/terminal.h index b2347f9a..3f918b22 100644 --- a/terminal/terminal.h +++ b/terminal/terminal.h @@ -427,24 +427,6 @@ struct terminal_tag { WIN_RESIZE_NO, WIN_RESIZE_NEED_SEND, WIN_RESIZE_AWAIT_REPLY } win_resize_pending; 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) diff --git a/unix/window.c b/unix/window.c index d9d007b4..4fca971a 100644 --- a/unix/window.c +++ b/unix/window.c @@ -189,6 +189,24 @@ struct GtkFrontend { #endif 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; TermWin termwin; LogPolicy logpolicy; @@ -759,6 +777,10 @@ static void drawing_area_setup(GtkFrontend *inst, int width, int height) inst->drawing_area_setup_called = true; if (inst->term) 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) return; @@ -2480,6 +2502,17 @@ static void gtkwin_deny_term_resize(void *vctx) 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) { GtkFrontend *inst = container_of(tw, GtkFrontend, termwin); @@ -2525,6 +2558,7 @@ static void gtkwin_request_resize(TermWin *tw, int w, int h) #endif 0)) { queue_toplevel_callback(gtkwin_deny_term_resize, inst); + term_resize_request_completed(inst->term); return; } } @@ -2613,6 +2647,10 @@ static void gtkwin_request_resize(TermWin *tw, int w, int h) #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) diff --git a/windows/window.c b/windows/window.c index 59c56ee1..3d6420d0 100644 --- a/windows/window.c +++ b/windows/window.c @@ -1667,8 +1667,6 @@ static void deinit_fonts(void) 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) { 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 && !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; height = extra_height + font_height * h; SetWindowPos(wgs.term_hwnd, NULL, 0, 0, width, height, SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOZORDER); - - if (!sent_term_size) - term_size(term, h, w, conf_get_int(conf, CONF_savelines)); } else { /* * 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); } + term_resize_request_completed(term); InvalidateRect(wgs.term_hwnd, NULL, true); } @@ -2188,11 +2171,6 @@ static void wm_size_resize_term(LPARAM lParam, bool border) } else { term_size(term, h, w, 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; } }