summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt4
-rw-r--r--res/about/version.gmi1
-rw-r--r--src/app.c79
-rw-r--r--src/app.h1
4 files changed, 76 insertions, 9 deletions
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)
30option (ENABLE_KERNING "Enable kerning in font renderer (slower)" ON) 30option (ENABLE_KERNING "Enable kerning in font renderer (slower)" ON)
31option (ENABLE_RESOURCE_EMBED "Embed resources inside the executable" OFF) 31option (ENABLE_RESOURCE_EMBED "Embed resources inside the executable" OFF)
32option (ENABLE_WINDOWPOS_FIX "Set position after showing window (workaround for SDL bug)" OFF) 32option (ENABLE_WINDOWPOS_FIX "Set position after showing window (workaround for SDL bug)" OFF)
33option (ENABLE_IDLE_SLEEP "While idle, sleep in the main thread instead of waiting for events" ON)
33 34
34include (BuildType.cmake) 35include (BuildType.cmake)
35include (res/Embed.cmake) 36include (res/Embed.cmake)
@@ -219,6 +220,9 @@ if (ENABLE_MPG123 AND MPG123_FOUND)
219 target_compile_definitions (app PUBLIC LAGRANGE_ENABLE_MPG123=1) 220 target_compile_definitions (app PUBLIC LAGRANGE_ENABLE_MPG123=1)
220 target_link_libraries (app PUBLIC PkgConfig::MPG123) 221 target_link_libraries (app PUBLIC PkgConfig::MPG123)
221endif () 222endif ()
223if (ENABLE_IDLE_SLEEP)
224 target_compile_definitions (app PUBLIC LAGRANGE_IDLE_SLEEP=1)
225endif ()
222target_link_libraries (app PUBLIC the_Foundation::the_Foundation) 226target_link_libraries (app PUBLIC the_Foundation::the_Foundation)
223target_link_libraries (app PUBLIC ${SDL2_LDFLAGS}) 227target_link_libraries (app PUBLIC ${SDL2_LDFLAGS})
224if (APPLE) 228if (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 @@
10* 'text/*' content falls back to plain text. 10* 'text/*' content falls back to plain text.
11* Reduced visual artifacts in Unicode box-drawing characters (overlapping/gaps). 11* Reduced visual artifacts in Unicode box-drawing characters (overlapping/gaps).
12* Fixed truncated tab titles when opening tabs in background. 12* Fixed truncated tab titles when opening tabs in background.
13* macOS: Fixed excessive CPU usage while idling.
13 14
14## 0.12 15## 0.12
15* Added MIME hooks: pipe Gemini responses through external programs for arbitrary processing. (See "about:help" for usage.) 16* Added MIME hooks: pipe Gemini responses through external programs for arbitrary processing. (See "about:help" for usage.)
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";
89static const char *stateFileName_App_ = "state.binary"; 89static const char *stateFileName_App_ = "state.binary";
90static const char *downloadDir_App_ = "~/Downloads"; 90static const char *downloadDir_App_ = "~/Downloads";
91 91
92static const int idleThreshold_App_ = 1000; /* ms */
93
92struct Impl_App { 94struct Impl_App {
93 iCommandLine args; 95 iCommandLine args;
94 iString * execPath; 96 iString * execPath;
@@ -100,7 +102,12 @@ struct Impl_App {
100 iSortedArray tickers; 102 iSortedArray tickers;
101 uint32_t lastTickerTime; 103 uint32_t lastTickerTime;
102 uint32_t elapsedSinceLastTicker; 104 uint32_t elapsedSinceLastTicker;
103 iBool running; 105 iBool isRunning;
106#if defined (LAGRANGE_IDLE_SLEEP)
107 iBool isIdling;
108 uint32_t lastEventTime;
109 int sleepTimer;
110#endif
104 iAtomicInt pendingRefresh; 111 iAtomicInt pendingRefresh;
105 int tabEnum; 112 int tabEnum;
106 iStringList *launchCommands; 113 iStringList *launchCommands;
@@ -320,6 +327,16 @@ static void saveState_App_(const iApp *d) {
320 iRelease(f); 327 iRelease(f);
321} 328}
322 329
330#if defined (LAGRANGE_IDLE_SLEEP)
331static uint32_t checkAsleep_App_(uint32_t interval, void *param) {
332 iApp *d = param;
333 SDL_Event ev = { .type = SDL_USEREVENT };
334 ev.user.code = asleep_UserEventCode;
335 SDL_PushEvent(&ev);
336 return interval;
337}
338#endif
339
323static void init_App_(iApp *d, int argc, char **argv) { 340static void init_App_(iApp *d, int argc, char **argv) {
324 const iBool isFirstRun = !fileExistsCStr_FileInfo(cleanedPath_CStr(dataDir_App_)); 341 const iBool isFirstRun = !fileExistsCStr_FileInfo(cleanedPath_CStr(dataDir_App_));
325 d->isFinishedLaunching = iFalse; 342 d->isFinishedLaunching = iFalse;
@@ -349,7 +366,7 @@ static void init_App_(iApp *d, int argc, char **argv) {
349#endif 366#endif
350 init_Prefs(&d->prefs); 367 init_Prefs(&d->prefs);
351 setCStr_String(&d->prefs.downloadDir, downloadDir_App_); 368 setCStr_String(&d->prefs.downloadDir, downloadDir_App_);
352 d->running = iFalse; 369 d->isRunning = iFalse;
353 d->window = NULL; 370 d->window = NULL;
354 set_Atomic(&d->pendingRefresh, iFalse); 371 set_Atomic(&d->pendingRefresh, iFalse);
355 d->mimehooks = new_MimeHooks(); 372 d->mimehooks = new_MimeHooks();
@@ -358,6 +375,11 @@ static void init_App_(iApp *d, int argc, char **argv) {
358 d->bookmarks = new_Bookmarks(); 375 d->bookmarks = new_Bookmarks();
359 d->tabEnum = 0; /* generates unique IDs for tab pages */ 376 d->tabEnum = 0; /* generates unique IDs for tab pages */
360 setThemePalette_Color(d->prefs.theme); 377 setThemePalette_Color(d->prefs.theme);
378#if defined (LAGRANGE_IDLE_SLEEP)
379 d->isIdling = iFalse;
380 d->lastEventTime = 0;
381 d->sleepTimer = SDL_AddTimer(1000, checkAsleep_App_, d);
382#endif
361#if defined (iPlatformApple) 383#if defined (iPlatformApple)
362 setupApplication_MacOS(); 384 setupApplication_MacOS();
363#endif 385#endif
@@ -484,19 +506,25 @@ const iString *debugInfo_App(void) {
484} 506}
485 507
486iLocalDef iBool isWaitingAllowed_App_(iApp *d) { 508iLocalDef iBool isWaitingAllowed_App_(iApp *d) {
509#if defined (LAGRANGE_IDLE_SLEEP)
510 if (d->isIdling) {
511 return iFalse;
512 }
513#endif
487 return !value_Atomic(&d->pendingRefresh) && isEmpty_SortedArray(&d->tickers); 514 return !value_Atomic(&d->pendingRefresh) && isEmpty_SortedArray(&d->tickers);
488} 515}
489 516
490void processEvents_App(enum iAppEventMode eventMode) { 517void processEvents_App(enum iAppEventMode eventMode) {
491 iApp *d = &app_; 518 iApp *d = &app_;
492 SDL_Event ev; 519 SDL_Event ev;
520 iBool gotEvents = iFalse;
493 while ((isWaitingAllowed_App_(d) && eventMode == waitForNewEvents_AppEventMode && 521 while ((isWaitingAllowed_App_(d) && eventMode == waitForNewEvents_AppEventMode &&
494 SDL_WaitEvent(&ev)) || 522 SDL_WaitEvent(&ev)) ||
495 ((!isWaitingAllowed_App_(d) || eventMode == postedEventsOnly_AppEventMode) && 523 ((!isWaitingAllowed_App_(d) || eventMode == postedEventsOnly_AppEventMode) &&
496 SDL_PollEvent(&ev))) { 524 SDL_PollEvent(&ev))) {
497 switch (ev.type) { 525 switch (ev.type) {
498 case SDL_QUIT: 526 case SDL_QUIT:
499 d->running = iFalse; 527 d->isRunning = iFalse;
500 goto backToMainLoop; 528 goto backToMainLoop;
501 case SDL_DROPFILE: { 529 case SDL_DROPFILE: {
502 iBool newTab = iFalse; 530 iBool newTab = iFalse;
@@ -516,6 +544,25 @@ void processEvents_App(enum iAppEventMode eventMode) {
516 break; 544 break;
517 } 545 }
518 default: { 546 default: {
547#if defined (LAGRANGE_IDLE_SLEEP)
548 if (ev.type == SDL_USEREVENT && ev.user.code == asleep_UserEventCode) {
549 if (SDL_GetTicks() - d->lastEventTime > idleThreshold_App_) {
550 if (!d->isIdling) {
551 printf("[App] idling...\n");
552 fflush(stdout);
553 }
554 d->isIdling = iTrue;
555 }
556 continue;
557 }
558 d->lastEventTime = SDL_GetTicks();
559 if (d->isIdling) {
560 printf("[App] ...woke up\n");
561 fflush(stdout);
562 }
563 d->isIdling = iFalse;
564#endif
565 gotEvents = iTrue;
519 iBool wasUsed = processEvent_Window(d->window, &ev); 566 iBool wasUsed = processEvent_Window(d->window, &ev);
520 if (!wasUsed) { 567 if (!wasUsed) {
521 /* There may be a key bindings for this. */ 568 /* There may be a key bindings for this. */
@@ -539,6 +586,14 @@ void processEvents_App(enum iAppEventMode eventMode) {
539 } 586 }
540 } 587 }
541 } 588 }
589#if defined (LAGRANGE_IDLE_SLEEP)
590 if (d->isIdling && !gotEvents) {
591 /* This is where we spend most of our time when idle. 60 Hz still quite a lot but we
592 can't wait too long after the user tries to interact again with the app. In any
593 case, on macOS SDL_WaitEvent() seems to use 10x more CPU time than sleeping. */
594 SDL_Delay(1000 / 60);
595 }
596#endif
542backToMainLoop:; 597backToMainLoop:;
543} 598}
544 599
@@ -586,10 +641,10 @@ static int resizeWatcher_(void *user, SDL_Event *event) {
586 641
587static int run_App_(iApp *d) { 642static int run_App_(iApp *d) {
588 arrange_Widget(findWidget_App("root")); 643 arrange_Widget(findWidget_App("root"));
589 d->running = iTrue; 644 d->isRunning = iTrue;
590 SDL_EventState(SDL_DROPFILE, SDL_ENABLE); /* open files via drag'n'drop */ 645 SDL_EventState(SDL_DROPFILE, SDL_ENABLE); /* open files via drag'n'drop */
591 SDL_AddEventWatch(resizeWatcher_, d); 646 SDL_AddEventWatch(resizeWatcher_, d);
592 while (d->running) { 647 while (d->isRunning) {
593 processEvents_App(waitForNewEvents_AppEventMode); 648 processEvents_App(waitForNewEvents_AppEventMode);
594 runTickers_App_(d); 649 runTickers_App_(d);
595 refresh_App(); 650 refresh_App();
@@ -600,6 +655,9 @@ static int run_App_(iApp *d) {
600 655
601void refresh_App(void) { 656void refresh_App(void) {
602 iApp *d = &app_; 657 iApp *d = &app_;
658#if defined (LAGRANGE_IDLE_SLEEP)
659 if (d->isIdling) return;
660#endif
603 destroyPending_Widget(); 661 destroyPending_Widget();
604 draw_Window(d->window); 662 draw_Window(d->window);
605 set_Atomic(&d->pendingRefresh, iFalse); 663 set_Atomic(&d->pendingRefresh, iFalse);
@@ -657,6 +715,9 @@ int run_App(int argc, char **argv) {
657 715
658void postRefresh_App(void) { 716void postRefresh_App(void) {
659 iApp *d = &app_; 717 iApp *d = &app_;
718#if defined (LAGRANGE_IDLE_SLEEP)
719 d->isIdling = iFalse;
720#endif
660 const iBool wasPending = exchange_Atomic(&d->pendingRefresh, iTrue); 721 const iBool wasPending = exchange_Atomic(&d->pendingRefresh, iTrue);
661 if (!wasPending) { 722 if (!wasPending) {
662 SDL_Event ev; 723 SDL_Event ev;
@@ -1085,12 +1146,12 @@ iBool handleCommand_App(const char *cmd) {
1085 } 1146 }
1086 else if (equal_Command(cmd, "prefs.sideicon.changed")) { 1147 else if (equal_Command(cmd, "prefs.sideicon.changed")) {
1087 d->prefs.sideIcon = arg_Command(cmd) != 0; 1148 d->prefs.sideIcon = arg_Command(cmd) != 0;
1088 refresh_App(); 1149 postRefresh_App();
1089 return iTrue; 1150 return iTrue;
1090 } 1151 }
1091 else if (equal_Command(cmd, "prefs.hoveroutline.changed")) { 1152 else if (equal_Command(cmd, "prefs.hoveroutline.changed")) {
1092 d->prefs.hoverOutline = arg_Command(cmd) != 0; 1153 d->prefs.hoverOutline = arg_Command(cmd) != 0;
1093 refresh_App(); 1154 postRefresh_App();
1094 return iTrue; 1155 return iTrue;
1095 } 1156 }
1096 else if (equal_Command(cmd, "saturation.set")) { 1157 else if (equal_Command(cmd, "saturation.set")) {
@@ -1373,13 +1434,13 @@ iBool handleCommand_App(const char *cmd) {
1373 } 1434 }
1374 else if (equal_Command(cmd, "feeds.update.started")) { 1435 else if (equal_Command(cmd, "feeds.update.started")) {
1375 setFlags_Widget(findWidget_App("feeds.progress"), hidden_WidgetFlag, iFalse); 1436 setFlags_Widget(findWidget_App("feeds.progress"), hidden_WidgetFlag, iFalse);
1376 refresh_App(); 1437 postRefresh_App();
1377 return iFalse; 1438 return iFalse;
1378 } 1439 }
1379 else if (equal_Command(cmd, "feeds.update.finished")) { 1440 else if (equal_Command(cmd, "feeds.update.finished")) {
1380 setFlags_Widget(findWidget_App("feeds.progress"), hidden_WidgetFlag, iTrue); 1441 setFlags_Widget(findWidget_App("feeds.progress"), hidden_WidgetFlag, iTrue);
1381 refreshFinished_Feeds(); 1442 refreshFinished_Feeds();
1382 refresh_App(); 1443 postRefresh_App();
1383 return iFalse; 1444 return iFalse;
1384 } 1445 }
1385 else if (equal_Command(cmd, "visited.changed")) { 1446 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 {
46enum iUserEventCode { 46enum iUserEventCode {
47 command_UserEventCode = 1, 47 command_UserEventCode = 1,
48 refresh_UserEventCode = 2, 48 refresh_UserEventCode = 2,
49 asleep_UserEventCode = 3,
49}; 50};
50 51
51const iString *execPath_App (void); 52const iString *execPath_App (void);