Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move smooth scroll timers to a separate thread, instead of using SetTimer #4722

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Move scroll timer to a thread, instead of SetTimer
  • Loading branch information
goodtrailer committed Dec 15, 2024
commit f3aae88960a3e3014e585470436bdf4cb9181445
9 changes: 3 additions & 6 deletions src/Canvas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,6 @@ bool gNoFlickerRender = true;

Kind kNotifAnnotation = "notifAnnotation";

// Timer for mouse wheel smooth scrolling
constexpr UINT_PTR kSmoothScrollTimerID = 6;

// Smooth scrolling factor. This is a value between 0 and 1.
// Each step, we scroll the needed delta times this factor.
// Therefore, a higher factor makes smooth scrolling faster.
Expand Down Expand Up @@ -151,7 +148,7 @@ static void OnVScroll(MainWindow* win, WPARAM wp) {
if (si.nPos != currPos || msg == SB_THUMBTRACK) {
if (gGlobalPrefs->smoothScroll) {
win->scrollTargetY = si.nPos;
SetTimer(win->hwndCanvas, kSmoothScrollTimerID, USER_TIMER_MINIMUM, nullptr);
SetEvent(win->scrollTimer);
} else {
win->AsFixed()->ScrollYTo(si.nPos);
}
Expand Down Expand Up @@ -1211,7 +1208,7 @@ static void ZoomByMouseWheel(MainWindow* win, WPARAM wp) {
win->dragStartPending = false;
// Kill the smooth scroll timer when zooming
// We don't want to move to the new updated y offset after zooming
KillTimer(win->hwndCanvas, kSmoothScrollTimerID);
ResetEvent(win->scrollTimer);

short delta = GET_WHEEL_DELTA_WPARAM(wp);
Point pt = HwndGetCursorPos(win->hwndCanvas);
Expand Down Expand Up @@ -1875,7 +1872,7 @@ static void OnTimer(MainWindow* win, HWND hwnd, WPARAM timerId) {
int delta = target - current;

if (delta == 0) {
KillTimer(hwnd, kSmoothScrollTimerID);
ResetEvent(win->scrollTimer);
} else {
// logf("Smooth scrolling from %d to %d (delta %d)\n", current, target, delta);

Expand Down
3 changes: 3 additions & 0 deletions src/Canvas.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
/* Copyright 2022 the SumatraPDF project authors (see AUTHORS file).
License: GPLv3 */

// Timer for mouse wheel smooth scrolling
constexpr UINT_PTR kSmoothScrollTimerID = 6;

void UpdateDeltaPerLine();

LRESULT CALLBACK WndProcCanvas(HWND, UINT, WPARAM, LPARAM);
Expand Down
5 changes: 5 additions & 0 deletions src/MainWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,11 @@ struct MainWindow {

DocControllerCallback* cbHandler = nullptr;

// Seprate scroll thread for higher precision scrolling updates
HANDLE scrollTimerThread = nullptr;
bool scrollTimerCancelled = false;
HANDLE scrollTimer = nullptr;

// The target y offset for smooth scrolling.
// We use a timer to gradually scroll there.
int scrollTargetY = 0;
Expand Down
40 changes: 40 additions & 0 deletions src/SumatraPDF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1464,6 +1464,36 @@ static void UpdateToolbarSidebarText(MainWindow* win) {
win->favLabelWithClose->SetLabel(_TRA("Favorites"));
}

static void ScrollTimerThread(MainWindow* win) {
while (WaitForSingleObject(win->scrollTimer, INFINITE) == WAIT_OBJECT_0) {
if (win->scrollTimerCancelled) {
break;
}

SendMessage(win->hwndCanvas, WM_TIMER, kSmoothScrollTimerID, 0);

// Re-fetch the monitor refresh rate in case window is moved to
// new window, or monitor refresh rate changed

HMONITOR monitor = MonitorFromWindow(win->hwndCanvas, MONITOR_DEFAULTTOPRIMARY);
MONITORINFOEX info;
info.cbSize = sizeof(MONITORINFOEX);
if (!GetMonitorInfo(monitor, &info)) {
Sleep(1000 / 60);
continue;
}
DEVMODE mode;
mode.dmSize = sizeof(DEVMODE);
mode.dmDriverExtra = 0;
if (!EnumDisplaySettings(info.szDevice, ENUM_CURRENT_SETTINGS, &mode) || mode.dmDisplayFrequency == 0) {
Sleep(1000 / 60);
continue;
}

Sleep(1000 / mode.dmDisplayFrequency);
}
}

static MainWindow* CreateMainWindow() {
Rect windowPos = gGlobalPrefs->windowPos;
if (!windowPos.IsEmpty()) {
Expand Down Expand Up @@ -1513,6 +1543,10 @@ static MainWindow* CreateMainWindow() {
// hide scrollbars to avoid showing/hiding on empty window
ShowScrollBar(win->hwndCanvas, SB_BOTH, FALSE);

win->scrollTimer = CreateEvent(nullptr, true, false, nullptr);
Func0 fn = MkFunc0(ScrollTimerThread, win);
win->scrollTimerThread = StartThread(fn, "Scroll Thread");

ReportIf(win->menu);
win->menu = BuildMenu(win);
win->isMenuHidden = !gGlobalPrefs->showMenubar;
Expand Down Expand Up @@ -2728,6 +2762,12 @@ void CloseWindow(MainWindow* win, bool quitIfLast, bool forceClose) {

AbortFinding(win, true);
AbortPrinting(win);
if (win->scrollTimerThread) {
win->scrollTimerCancelled = true;
SetEvent(win->scrollTimer);
WaitForSingleObject(win->scrollTimerThread, INFINITE);
}
win->scrollTimerCancelled = false;

for (auto& tab : win->Tabs()) {
if (tab->AsFixed()) {
Expand Down