diff --git a/CMakeLists.txt b/CMakeLists.txt

index 82d55590..0edfbed2 100644

--- a/CMakeLists.txt

+++ b/CMakeLists.txt

@@ -30,6 +30,7 @@ option (ENABLE_X11_SWRENDER "Use software rendering under X11" OFF)

option (ENABLE_KERNING "Enable kerning in font renderer (slower)" ON)

option (ENABLE_RESOURCE_EMBED "Embed resources inside the executable" OFF)

option (ENABLE_WINDOWPOS_FIX "Set position after showing window (workaround for SDL bug)" OFF)

+option (ENABLE_IDLE_SLEEP "While idle, sleep in the main thread instead of waiting for events" ON)



include (BuildType.cmake)

include (res/Embed.cmake)

@@ -219,6 +220,9 @@ if (ENABLE_MPG123 AND MPG123_FOUND)

 target_compile_definitions (app PUBLIC LAGRANGE_ENABLE_MPG123=1)

 target_link_libraries (app PUBLIC PkgConfig::MPG123)

endif ()

+if (ENABLE_IDLE_SLEEP)

+ target_compile_definitions (app PUBLIC LAGRANGE_IDLE_SLEEP=1)

+endif ()

target_link_libraries (app PUBLIC the_Foundation::the_Foundation)

target_link_libraries (app PUBLIC ${SDL2_LDFLAGS})

if (APPLE)

diff --git a/res/about/version.gmi b/res/about/version.gmi

index af758486..5944932f 100644

--- a/res/about/version.gmi

+++ b/res/about/version.gmi

@@ -10,6 +10,7 @@

+* macOS: Fixed excessive CPU usage while idling.



0.12

diff --git a/src/app.c b/src/app.c

index 1e0a847d..ba7d41d2 100644

--- a/src/app.c

+++ b/src/app.c

@@ -89,6 +89,8 @@ static const char *prefsFileName_App_ = "prefs.cfg";

static const char *stateFileName_App_ = "state.binary";

static const char *downloadDir_App_ = "~/Downloads";



+static const int idleThreshold_App_ = 1000; /* ms */

+

struct Impl_App {

 iCommandLine args;

 iString *    execPath;

@@ -100,7 +102,12 @@ struct Impl_App {

 iSortedArray tickers;

 uint32_t     lastTickerTime;

 uint32_t     elapsedSinceLastTicker;

- iBool running;

+ iBool isRunning;

+#if defined (LAGRANGE_IDLE_SLEEP)

+ iBool isIdling;

+ uint32_t lastEventTime;

+ int sleepTimer;

+#endif

 iAtomicInt   pendingRefresh;

 int          tabEnum;

 iStringList *launchCommands;

@@ -320,6 +327,16 @@ static void saveState_App_(const iApp *d) {

 iRelease(f);

}



+#if defined (LAGRANGE_IDLE_SLEEP)

+static uint32_t checkAsleep_App_(uint32_t interval, void *param) {

+ iApp *d = param;

+ SDL_Event ev = { .type = SDL_USEREVENT };

+ ev.user.code = asleep_UserEventCode;

+ SDL_PushEvent(&ev);

+ return interval;

+}

+#endif

+

static void init_App_(iApp *d, int argc, char **argv) {

 const iBool isFirstRun = !fileExistsCStr_FileInfo(cleanedPath_CStr(dataDir_App_));

 d->isFinishedLaunching = iFalse;

@@ -349,7 +366,7 @@ static void init_App_(iApp *d, int argc, char **argv) {

#endif

 init_Prefs(&d->prefs);

 setCStr_String(&d->prefs.downloadDir, downloadDir_App_);

- d->running = iFalse;

+ d->isRunning = iFalse;

 d->window            = NULL;

 set_Atomic(&d->pendingRefresh, iFalse);

 d->mimehooks         = new_MimeHooks();

@@ -358,6 +375,11 @@ static void init_App_(iApp *d, int argc, char **argv) {

 d->bookmarks         = new_Bookmarks();

 d->tabEnum           = 0; /* generates unique IDs for tab pages */

 setThemePalette_Color(d->prefs.theme);

+#if defined (LAGRANGE_IDLE_SLEEP)

+ d->isIdling = iFalse;

+ d->lastEventTime = 0;

+ d->sleepTimer = SDL_AddTimer(1000, checkAsleep_App_, d);

+#endif

#if defined (iPlatformApple)

 setupApplication_MacOS();

#endif

@@ -484,19 +506,25 @@ const iString *debugInfo_App(void) {

}



iLocalDef iBool isWaitingAllowed_App_(iApp *d) {

+#if defined (LAGRANGE_IDLE_SLEEP)

+ if (d->isIdling) {

+ return iFalse;

+ }

+#endif

 return !value_Atomic(&d->pendingRefresh) && isEmpty_SortedArray(&d->tickers);

}



void processEvents_App(enum iAppEventMode eventMode) {

 iApp *d = &app_;

 SDL_Event ev;

+ iBool gotEvents = iFalse;

 while ((isWaitingAllowed_App_(d) && eventMode == waitForNewEvents_AppEventMode &&

         SDL_WaitEvent(&ev)) ||

        ((!isWaitingAllowed_App_(d) || eventMode == postedEventsOnly_AppEventMode) &&

         SDL_PollEvent(&ev))) {

     switch (ev.type) {

         case SDL_QUIT:

- d->running = iFalse;

+ d->isRunning = iFalse;

             goto backToMainLoop;

         case SDL_DROPFILE: {

             iBool newTab = iFalse;

@@ -516,6 +544,25 @@ void processEvents_App(enum iAppEventMode eventMode) {

             break;

         }

         default: {

+#if defined (LAGRANGE_IDLE_SLEEP)

+ if (ev.type == SDL_USEREVENT && ev.user.code == asleep_UserEventCode) {

+ if (SDL_GetTicks() - d->lastEventTime > idleThreshold_App_) {

+ if (!d->isIdling) {

+ printf("[App] idling...\n");

+ fflush(stdout);

+ }

+ d->isIdling = iTrue;

+ }

+ continue;

+ }

+ d->lastEventTime = SDL_GetTicks();

+ if (d->isIdling) {

+ printf("[App] ...woke up\n");

+ fflush(stdout);

+ }

+ d->isIdling = iFalse;

+#endif

+ gotEvents = iTrue;

             iBool wasUsed = processEvent_Window(d->window, &ev);

             if (!wasUsed) {

                 /* There may be a key bindings for this. */

@@ -539,6 +586,14 @@ void processEvents_App(enum iAppEventMode eventMode) {

         }

     }

 }

+#if defined (LAGRANGE_IDLE_SLEEP)

+ if (d->isIdling && !gotEvents) {

+ /* This is where we spend most of our time when idle. 60 Hz still quite a lot but we

+ can't wait too long after the user tries to interact again with the app. In any

+ case, on macOS SDL_WaitEvent() seems to use 10x more CPU time than sleeping. */

+ SDL_Delay(1000 / 60);

+ }

+#endif

backToMainLoop:;

}



@@ -586,10 +641,10 @@ static int resizeWatcher_(void *user, SDL_Event *event) {



static int run_App_(iApp *d) {

 arrange_Widget(findWidget_App("root"));

- d->running = iTrue;

+ d->isRunning = iTrue;

 SDL_EventState(SDL_DROPFILE, SDL_ENABLE); /* open files via drag'n'drop */

 SDL_AddEventWatch(resizeWatcher_, d);

- while (d->running) {

+ while (d->isRunning) {

     processEvents_App(waitForNewEvents_AppEventMode);

     runTickers_App_(d);

     refresh_App();

@@ -600,6 +655,9 @@ static int run_App_(iApp *d) {



void refresh_App(void) {

 iApp *d = &app_;

+#if defined (LAGRANGE_IDLE_SLEEP)

+ if (d->isIdling) return;

+#endif

 destroyPending_Widget();

 draw_Window(d->window);

 set_Atomic(&d->pendingRefresh, iFalse);

@@ -657,6 +715,9 @@ int run_App(int argc, char **argv) {



void postRefresh_App(void) {

 iApp *d = &app_;

+#if defined (LAGRANGE_IDLE_SLEEP)

+ d->isIdling = iFalse;

+#endif

 const iBool wasPending = exchange_Atomic(&d->pendingRefresh, iTrue);

 if (!wasPending) {

     SDL_Event ev;

@@ -1085,12 +1146,12 @@ iBool handleCommand_App(const char *cmd) {

 }

 else if (equal_Command(cmd, "prefs.sideicon.changed")) {

     d->prefs.sideIcon = arg_Command(cmd) != 0;

- refresh_App();

+ postRefresh_App();

     return iTrue;

 }

 else if (equal_Command(cmd, "prefs.hoveroutline.changed")) {

     d->prefs.hoverOutline = arg_Command(cmd) != 0;

- refresh_App();

+ postRefresh_App();

     return iTrue;

 }

 else if (equal_Command(cmd, "saturation.set")) {

@@ -1373,13 +1434,13 @@ iBool handleCommand_App(const char *cmd) {

 }

 else if (equal_Command(cmd, "feeds.update.started")) {

     setFlags_Widget(findWidget_App("feeds.progress"), hidden_WidgetFlag, iFalse);

- refresh_App();

+ postRefresh_App();

     return iFalse;

 }

 else if (equal_Command(cmd, "feeds.update.finished")) {

     setFlags_Widget(findWidget_App("feeds.progress"), hidden_WidgetFlag, iTrue);

     refreshFinished_Feeds();

- refresh_App();

+ postRefresh_App();

     return iFalse;

 }

 else if (equal_Command(cmd, "visited.changed")) {

diff --git a/src/app.h b/src/app.h

index bc086dfe..743484a5 100644

--- a/src/app.h

+++ b/src/app.h

@@ -46,6 +46,7 @@ enum iAppEventMode {

enum iUserEventCode {

 command_UserEventCode = 1,

 refresh_UserEventCode = 2,

+ asleep_UserEventCode = 3,

};



const iString *execPath_App (void);

Proxy Information
Original URL
gemini://git.skyjake.fi/lagrange/work%2Fv1.10/pcdiff/6a565ea71745aaf4c91a7698bbf56f7d906fcaaa
Status Code
Success (20)
Meta
text/plain
Capsule Response Time
59.33576 milliseconds
Gemini-to-HTML Time
3.256618 milliseconds

This content has been proxied by September (ba2dc).