1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00

Merge interactive scrolling fix from 'pre-0.75'.

This commit is contained in:
Simon Tatham 2021-04-24 19:56:22 +01:00
commit 3c851b2907

View File

@ -2172,6 +2172,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
static bool ignore_clip = false;
static bool fullscr_on_max = false;
static bool processed_resize = false;
static bool in_scrollbar_loop = false;
static UINT last_mousemove = 0;
int resize_action;
@ -2226,6 +2227,21 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
case WM_COMMAND:
case WM_SYSCOMMAND:
switch (wParam & ~0xF) { /* low 4 bits reserved to Windows */
case SC_VSCROLL:
case SC_HSCROLL:
if (message == WM_SYSCOMMAND) {
/* As per the long comment in WM_VSCROLL handler: give
* this message the default handling, which starts a
* subsidiary message loop, but set a flag so that
* when we're re-entered from that loop, scroll events
* within an interactive scrollbar-drag can be handled
* differently. */
in_scrollbar_loop = true;
LRESULT result = DefWindowProcW(hwnd, message, wParam, lParam);
in_scrollbar_loop = false;
return result;
}
break;
case IDM_SHOWLOG:
showeventlog(hwnd);
break;
@ -3138,6 +3154,54 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
if (GetScrollInfo(hwnd, SB_VERT, &si) == 0)
si.nTrackPos = HIWORD(wParam);
term_scroll(term, 1, si.nTrackPos);
if (in_scrollbar_loop) {
/*
* Allow window updates to happen during interactive
* scroll.
*
* When the user takes hold of our window's scrollbar
* and wobbles it interactively back and forth, the
* first thing that happens is that this window
* procedure receives WM_SYSCOMMAND / SC_VSCROLL. [1]
* The default handler for that window message starts
* a subsidiary message loop, which continues to run
* until the user lets go of the scrollbar again. All
* WM_VSCROLL / SB_THUMBTRACK messages are generated
* by the handlers within that subsidiary message
* loop.
*
* So, during that time, _our_ message loop is not
* running, which means toplevel callbacks and timers
* and so forth are not happening, which means that
* when we redraw the window and set a timer to clear
* the cooldown flag 20ms later, that timer never
* fires, and we aren't able to keep redrawing the
* window.
*
* The 'obvious' answer would be to seize that
* SYSCOMMAND ourselves and inhibit the default
* handler, so that our message loop carries on
* running. But that would mean we'd have to
* reimplement the whole of the scrollbar handler!
*
* So instead we apply a bodge: set a static variable
* that indicates that we're _in_ that sub-loop, and
* if so, decide it's OK to manually call
* term_update() proper, bypassing the timer and
* cooldown and rate-limiting systems completely,
* whenever we see an SB_THUMBTRACK. This shouldn't
* cause a rate overload, because we're only doing it
* once per UI event!
*
* [1] Actually, there's an extra oddity where
* SC_HSCROLL and SC_VSCROLL have their documented
* values the wrong way round. Many people on the
* Internet have noticed this, e.g.
* https://stackoverflow.com/q/55528397
*/
term_update(term);
}
break;
}
}