[1mdiff --git a/CMakeLists.txt b/CMakeLists.txt[m
[1mindex 82d55590..0edfbed2 100644[m
[1m--- a/CMakeLists.txt[m
[1m+++ b/CMakeLists.txt[m
[36m@@ -30,6 +30,7 @@[m [moption (ENABLE_X11_SWRENDER "Use software rendering under X11" OFF)[m
option (ENABLE_KERNING "Enable kerning in font renderer (slower)" ON)[m
option (ENABLE_RESOURCE_EMBED "Embed resources inside the executable" OFF)[m
option (ENABLE_WINDOWPOS_FIX "Set position after showing window (workaround for SDL bug)" OFF)[m
[32m+[m[32moption (ENABLE_IDLE_SLEEP "While idle, sleep in the main thread instead of waiting for events" ON)[m
[m
include (BuildType.cmake)[m
include (res/Embed.cmake)[m
[36m@@ -219,6 +220,9 @@[m [mif (ENABLE_MPG123 AND MPG123_FOUND)[m
target_compile_definitions (app PUBLIC LAGRANGE_ENABLE_MPG123=1)[m
target_link_libraries (app PUBLIC PkgConfig::MPG123)[m
endif ()[m
[32m+[m[32mif (ENABLE_IDLE_SLEEP)[m
[32m+[m[32m target_compile_definitions (app PUBLIC LAGRANGE_IDLE_SLEEP=1)[m
[32m+[m[32mendif ()[m
target_link_libraries (app PUBLIC the_Foundation::the_Foundation)[m
target_link_libraries (app PUBLIC ${SDL2_LDFLAGS})[m
if (APPLE)[m
[1mdiff --git a/res/about/version.gmi b/res/about/version.gmi[m
[1mindex af758486..5944932f 100644[m
[1m--- a/res/about/version.gmi[m
[1m+++ b/res/about/version.gmi[m
[36m@@ -10,6 +10,7 @@[m
[32m+[m[32m* macOS: Fixed excessive CPU usage while idling.[m
[m
[1mdiff --git a/src/app.c b/src/app.c[m
[1mindex 1e0a847d..ba7d41d2 100644[m
[1m--- a/src/app.c[m
[1m+++ b/src/app.c[m
[36m@@ -89,6 +89,8 @@[m [mstatic const char *prefsFileName_App_ = "prefs.cfg";[m
static const char *stateFileName_App_ = "state.binary";[m
static const char *downloadDir_App_ = "~/Downloads";[m
[m
[32m+[m[32mstatic const int idleThreshold_App_ = 1000; /* ms */[m
[32m+[m
struct Impl_App {[m
iCommandLine args;[m
iString * execPath;[m
[36m@@ -100,7 +102,12 @@[m [mstruct Impl_App {[m
iSortedArray tickers;[m
uint32_t lastTickerTime;[m
uint32_t elapsedSinceLastTicker;[m
[31m- iBool running;[m
[32m+[m[32m iBool isRunning;[m
[32m+[m[32m#if defined (LAGRANGE_IDLE_SLEEP)[m
[32m+[m[32m iBool isIdling;[m
[32m+[m[32m uint32_t lastEventTime;[m
[32m+[m[32m int sleepTimer;[m
[32m+[m[32m#endif[m
iAtomicInt pendingRefresh;[m
int tabEnum;[m
iStringList *launchCommands;[m
[36m@@ -320,6 +327,16 @@[m [mstatic void saveState_App_(const iApp *d) {[m
iRelease(f);[m
}[m
[m
[32m+[m[32m#if defined (LAGRANGE_IDLE_SLEEP)[m
[32m+[m[32mstatic uint32_t checkAsleep_App_(uint32_t interval, void *param) {[m
[32m+[m[32m iApp *d = param;[m
[32m+[m[32m SDL_Event ev = { .type = SDL_USEREVENT };[m
[32m+[m[32m ev.user.code = asleep_UserEventCode;[m
[32m+[m[32m SDL_PushEvent(&ev);[m
[32m+[m[32m return interval;[m
[32m+[m[32m}[m
[32m+[m[32m#endif[m
[32m+[m
static void init_App_(iApp *d, int argc, char **argv) {[m
const iBool isFirstRun = !fileExistsCStr_FileInfo(cleanedPath_CStr(dataDir_App_));[m
d->isFinishedLaunching = iFalse;[m
[36m@@ -349,7 +366,7 @@[m [mstatic void init_App_(iApp *d, int argc, char **argv) {[m
#endif[m
init_Prefs(&d->prefs);[m
setCStr_String(&d->prefs.downloadDir, downloadDir_App_);[m
[31m- d->running = iFalse;[m
[32m+[m[32m d->isRunning = iFalse;[m
d->window = NULL;[m
set_Atomic(&d->pendingRefresh, iFalse);[m
d->mimehooks = new_MimeHooks();[m
[36m@@ -358,6 +375,11 @@[m [mstatic void init_App_(iApp *d, int argc, char **argv) {[m
d->bookmarks = new_Bookmarks();[m
d->tabEnum = 0; /* generates unique IDs for tab pages */[m
setThemePalette_Color(d->prefs.theme);[m
[32m+[m[32m#if defined (LAGRANGE_IDLE_SLEEP)[m
[32m+[m[32m d->isIdling = iFalse;[m
[32m+[m[32m d->lastEventTime = 0;[m
[32m+[m[32m d->sleepTimer = SDL_AddTimer(1000, checkAsleep_App_, d);[m
[32m+[m[32m#endif[m
#if defined (iPlatformApple)[m
setupApplication_MacOS();[m
#endif[m
[36m@@ -484,19 +506,25 @@[m [mconst iString *debugInfo_App(void) {[m
}[m
[m
iLocalDef iBool isWaitingAllowed_App_(iApp *d) {[m
[32m+[m[32m#if defined (LAGRANGE_IDLE_SLEEP)[m
[32m+[m[32m if (d->isIdling) {[m
[32m+[m[32m return iFalse;[m
[32m+[m[32m }[m
[32m+[m[32m#endif[m
return !value_Atomic(&d->pendingRefresh) && isEmpty_SortedArray(&d->tickers);[m
}[m
[m
void processEvents_App(enum iAppEventMode eventMode) {[m
iApp *d = &app_;[m
SDL_Event ev;[m
[32m+[m[32m iBool gotEvents = iFalse;[m
while ((isWaitingAllowed_App_(d) && eventMode == waitForNewEvents_AppEventMode &&[m
SDL_WaitEvent(&ev)) ||[m
((!isWaitingAllowed_App_(d) || eventMode == postedEventsOnly_AppEventMode) &&[m
SDL_PollEvent(&ev))) {[m
switch (ev.type) {[m
case SDL_QUIT:[m
[31m- d->running = iFalse;[m
[32m+[m[32m d->isRunning = iFalse;[m
goto backToMainLoop;[m
case SDL_DROPFILE: {[m
iBool newTab = iFalse;[m
[36m@@ -516,6 +544,25 @@[m [mvoid processEvents_App(enum iAppEventMode eventMode) {[m
break;[m
}[m
default: {[m
[32m+[m[32m#if defined (LAGRANGE_IDLE_SLEEP)[m
[32m+[m[32m if (ev.type == SDL_USEREVENT && ev.user.code == asleep_UserEventCode) {[m
[32m+[m[32m if (SDL_GetTicks() - d->lastEventTime > idleThreshold_App_) {[m
[32m+[m[32m if (!d->isIdling) {[m
[32m+[m[32m printf("[App] idling...\n");[m
[32m+[m[32m fflush(stdout);[m
[32m+[m[32m }[m
[32m+[m[32m d->isIdling = iTrue;[m
[32m+[m[32m }[m
[32m+[m[32m continue;[m
[32m+[m[32m }[m
[32m+[m[32m d->lastEventTime = SDL_GetTicks();[m
[32m+[m[32m if (d->isIdling) {[m
[32m+[m[32m printf("[App] ...woke up\n");[m
[32m+[m[32m fflush(stdout);[m
[32m+[m[32m }[m
[32m+[m[32m d->isIdling = iFalse;[m
[32m+[m[32m#endif[m
[32m+[m[32m gotEvents = iTrue;[m
iBool wasUsed = processEvent_Window(d->window, &ev);[m
if (!wasUsed) {[m
/* There may be a key bindings for this. */[m
[36m@@ -539,6 +586,14 @@[m [mvoid processEvents_App(enum iAppEventMode eventMode) {[m
}[m
}[m
}[m
[32m+[m[32m#if defined (LAGRANGE_IDLE_SLEEP)[m
[32m+[m[32m if (d->isIdling && !gotEvents) {[m
[32m+[m[32m /* This is where we spend most of our time when idle. 60 Hz still quite a lot but we[m
[32m+[m[32m can't wait too long after the user tries to interact again with the app. In any[m
[32m+[m[32m case, on macOS SDL_WaitEvent() seems to use 10x more CPU time than sleeping. */[m
[32m+[m[32m SDL_Delay(1000 / 60);[m
[32m+[m[32m }[m
[32m+[m[32m#endif[m
backToMainLoop:;[m
}[m
[m
[36m@@ -586,10 +641,10 @@[m [mstatic int resizeWatcher_(void *user, SDL_Event *event) {[m
[m
static int run_App_(iApp *d) {[m
arrange_Widget(findWidget_App("root"));[m
[31m- d->running = iTrue;[m
[32m+[m[32m d->isRunning = iTrue;[m
SDL_EventState(SDL_DROPFILE, SDL_ENABLE); /* open files via drag'n'drop */[m
SDL_AddEventWatch(resizeWatcher_, d);[m
[31m- while (d->running) {[m
[32m+[m[32m while (d->isRunning) {[m
processEvents_App(waitForNewEvents_AppEventMode);[m
runTickers_App_(d);[m
refresh_App();[m
[36m@@ -600,6 +655,9 @@[m [mstatic int run_App_(iApp *d) {[m
[m
void refresh_App(void) {[m
iApp *d = &app_;[m
[32m+[m[32m#if defined (LAGRANGE_IDLE_SLEEP)[m
[32m+[m[32m if (d->isIdling) return;[m
[32m+[m[32m#endif[m
destroyPending_Widget();[m
draw_Window(d->window);[m
set_Atomic(&d->pendingRefresh, iFalse);[m
[36m@@ -657,6 +715,9 @@[m [mint run_App(int argc, char **argv) {[m
[m
void postRefresh_App(void) {[m
iApp *d = &app_;[m
[32m+[m[32m#if defined (LAGRANGE_IDLE_SLEEP)[m
[32m+[m[32m d->isIdling = iFalse;[m
[32m+[m[32m#endif[m
const iBool wasPending = exchange_Atomic(&d->pendingRefresh, iTrue);[m
if (!wasPending) {[m
SDL_Event ev;[m
[36m@@ -1085,12 +1146,12 @@[m [miBool handleCommand_App(const char *cmd) {[m
}[m
else if (equal_Command(cmd, "prefs.sideicon.changed")) {[m
d->prefs.sideIcon = arg_Command(cmd) != 0;[m
[31m- refresh_App();[m
[32m+[m[32m postRefresh_App();[m
return iTrue;[m
}[m
else if (equal_Command(cmd, "prefs.hoveroutline.changed")) {[m
d->prefs.hoverOutline = arg_Command(cmd) != 0;[m
[31m- refresh_App();[m
[32m+[m[32m postRefresh_App();[m
return iTrue;[m
}[m
else if (equal_Command(cmd, "saturation.set")) {[m
[36m@@ -1373,13 +1434,13 @@[m [miBool handleCommand_App(const char *cmd) {[m
}[m
else if (equal_Command(cmd, "feeds.update.started")) {[m
setFlags_Widget(findWidget_App("feeds.progress"), hidden_WidgetFlag, iFalse);[m
[31m- refresh_App();[m
[32m+[m[32m postRefresh_App();[m
return iFalse;[m
}[m
else if (equal_Command(cmd, "feeds.update.finished")) {[m
setFlags_Widget(findWidget_App("feeds.progress"), hidden_WidgetFlag, iTrue);[m
refreshFinished_Feeds();[m
[31m- refresh_App();[m
[32m+[m[32m postRefresh_App();[m
return iFalse;[m
}[m
else if (equal_Command(cmd, "visited.changed")) {[m
[1mdiff --git a/src/app.h b/src/app.h[m
[1mindex bc086dfe..743484a5 100644[m
[1m--- a/src/app.h[m
[1m+++ b/src/app.h[m
[36m@@ -46,6 +46,7 @@[m [menum iAppEventMode {[m
enum iUserEventCode {[m
command_UserEventCode = 1,[m
refresh_UserEventCode = 2,[m
[32m+[m[32m asleep_UserEventCode = 3,[m
};[m
[m
const iString *execPath_App (void);[m
text/plain
This content has been proxied by September (ba2dc).