summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-03-20 18:51:03 +0200
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-03-20 18:51:03 +0200
commit5dfb890cf841579edaeb2633025db218e86f45c2 (patch)
treea6937d904579b8d7051cf033e03e99464d298c98 /src
parentaa70507d43d17ca2c426acd6bf91548fe267ac19 (diff)
App: Periodic commands without timers/threads
Now the periodic commands get posted on the main thread at intervals, and the event loop cooperates by not sleeping if there are periodic commands pending. The macOS animation hangup seems to be unrelated, though — perhaps some internal SDL/Metal machinery related to app refresh stopping for a while?
Diffstat (limited to 'src')
-rw-r--r--src/app.c32
-rw-r--r--src/periodic.c44
-rw-r--r--src/periodic.h16
-rw-r--r--src/ui/scrollwidget.c2
4 files changed, 51 insertions, 43 deletions
diff --git a/src/app.c b/src/app.c
index 31bd33ed..0611b6dd 100644
--- a/src/app.c
+++ b/src/app.c
@@ -837,6 +837,9 @@ void trimCache_App(void) {
837} 837}
838 838
839iLocalDef iBool isWaitingAllowed_App_(iApp *d) { 839iLocalDef iBool isWaitingAllowed_App_(iApp *d) {
840 if (!isEmpty_Periodic(&d->periodic)) {
841 return iFalse;
842 }
840 if (d->warmupFrames > 0) { 843 if (d->warmupFrames > 0) {
841 return iFalse; 844 return iFalse;
842 } 845 }
@@ -853,14 +856,26 @@ iLocalDef iBool isWaitingAllowed_App_(iApp *d) {
853 return !value_Atomic(&d->pendingRefresh) && isEmpty_SortedArray(&d->tickers); 856 return !value_Atomic(&d->pendingRefresh) && isEmpty_SortedArray(&d->tickers);
854} 857}
855 858
859static iBool nextEvent_App_(iApp *d, enum iAppEventMode eventMode, SDL_Event *event) {
860 if (eventMode == waitForNewEvents_AppEventMode && isWaitingAllowed_App_(d)) {
861 /* If there are periodic commands pending, wait only for a short while. */
862 if (!isEmpty_Periodic(&d->periodic)) {
863 return SDL_WaitEventTimeout(event, 500);
864 }
865 /* We may be allowed to block here until an event comes in. */
866 if (isWaitingAllowed_App_(d)) {
867 return SDL_WaitEvent(event);
868 }
869 }
870 return SDL_PollEvent(event);
871}
872
856void processEvents_App(enum iAppEventMode eventMode) { 873void processEvents_App(enum iAppEventMode eventMode) {
857 iApp *d = &app_; 874 iApp *d = &app_;
858 SDL_Event ev; 875 SDL_Event ev;
859 iBool gotEvents = iFalse; 876 iBool gotEvents = iFalse;
860 while ((isWaitingAllowed_App_(d) && eventMode == waitForNewEvents_AppEventMode && 877 postCommands_Periodic(&d->periodic);
861 SDL_WaitEvent(&ev)) || 878 while (nextEvent_App_(d, eventMode, &ev)) {
862 ((!isWaitingAllowed_App_(d) || eventMode == postedEventsOnly_AppEventMode) &&
863 SDL_PollEvent(&ev))) {
864#if defined (iPlatformAppleMobile) 879#if defined (iPlatformAppleMobile)
865 if (processEvent_iOS(&ev)) { 880 if (processEvent_iOS(&ev)) {
866 continue; 881 continue;
@@ -1064,13 +1079,18 @@ static int run_App_(iApp *d) {
1064 1079
1065void refresh_App(void) { 1080void refresh_App(void) {
1066 iApp *d = &app_; 1081 iApp *d = &app_;
1082 destroyPending_Widget();
1067#if defined (LAGRANGE_IDLE_SLEEP) 1083#if defined (LAGRANGE_IDLE_SLEEP)
1068 if (d->warmupFrames == 0 && d->isIdling) { 1084 if (d->warmupFrames == 0 && d->isIdling) {
1069 return; 1085 return;
1070 } 1086 }
1071#endif 1087#endif
1072 set_Atomic(&d->pendingRefresh, iFalse); 1088 if (!exchange_Atomic(&d->pendingRefresh, iFalse)) {
1073 destroyPending_Widget(); 1089 /* Refreshing wasn't pending. */
1090 if (isFinished_Anim(&d->window->rootOffset)) {
1091 return;
1092 }
1093 }
1074// iTime draw; 1094// iTime draw;
1075// initCurrent_Time(&draw); 1095// initCurrent_Time(&draw);
1076 draw_Window(d->window); 1096 draw_Window(d->window);
diff --git a/src/periodic.c b/src/periodic.c
index c039097d..29c26de9 100644
--- a/src/periodic.c
+++ b/src/periodic.c
@@ -52,50 +52,35 @@ iDefineTypeConstructionArgs(PeriodicCommand, (iAny *ctx, const char *cmd), ctx,
52 52
53/*----------------------------------------------------------------------------------------------*/ 53/*----------------------------------------------------------------------------------------------*/
54 54
55//static uint32_t postCommands_Periodic_(uint32_t interval, void *param) { 55static const uint32_t postingInterval_Periodic_ = 500;
56static iThreadResult poster_Periodic_(iThread *thread) { 56
57 iPeriodic *d = userData_Thread(thread); 57iBool postCommands_Periodic(iPeriodic *d) {
58 const uint32_t now = SDL_GetTicks();
59 if (now - d->lastPostTime < postingInterval_Periodic_) {
60 return iFalse;
61 }
62 d->lastPostTime = now;
63 iBool wasPosted = iFalse;
58 lock_Mutex(d->mutex); 64 lock_Mutex(d->mutex);
59 while (!value_Atomic(&d->isStopping)) { 65 iConstForEach(Array, i, &d->commands.values) {
60 if (isEmpty_SortedArray(&d->commands)) { 66 postCommandString_App(&((const iPeriodicCommand *) i.value)->command);
61 /* Sleep until we have something to post. */ 67 wasPosted = iTrue;
62 wait_Condition(&d->haveCommands, d->mutex);
63 continue;
64 }
65 iConstForEach(Array, i, &d->commands.values) {
66 postCommandString_App(&((const iPeriodicCommand *) i.value)->command);
67 }
68 /* Sleep for a while. */
69 iTime until;
70 initTimeout_Time(&until, 0.5f);
71 waitTimeout_Condition(&d->haveCommands, d->mutex, &until);
72 } 68 }
73 unlock_Mutex(d->mutex); 69 unlock_Mutex(d->mutex);
74 return 0; 70 return wasPosted;
75} 71}
76 72
77void init_Periodic(iPeriodic *d) { 73void init_Periodic(iPeriodic *d) {
78 d->mutex = new_Mutex(); 74 d->mutex = new_Mutex();
79 init_SortedArray(&d->commands, sizeof(iPeriodicCommand), cmp_PeriodicCommand_); 75 init_SortedArray(&d->commands, sizeof(iPeriodicCommand), cmp_PeriodicCommand_);
80// d->timer = SDL_AddTimer(500, postCommands_Periodic_, d); 76 d->lastPostTime = 0;
81 set_Atomic(&d->isStopping, iFalse);
82 init_Condition(&d->haveCommands);
83 d->thread = new_Thread(poster_Periodic_);
84 setUserData_Thread(d->thread, d);
85 start_Thread(d->thread);
86} 77}
87 78
88void deinit_Periodic(iPeriodic *d) { 79void deinit_Periodic(iPeriodic *d) {
89// SDL_RemoveTimer(d->timer);
90 set_Atomic(&d->isStopping, iTrue);
91 signal_Condition(&d->haveCommands);
92 join_Thread(d->thread);
93 iRelease(d->thread);
94 iForEach(Array, i, &d->commands.values) { 80 iForEach(Array, i, &d->commands.values) {
95 deinit_PeriodicCommand(i.value); 81 deinit_PeriodicCommand(i.value);
96 } 82 }
97 deinit_SortedArray(&d->commands); 83 deinit_SortedArray(&d->commands);
98 deinit_Condition(&d->haveCommands);
99 delete_Mutex(d->mutex); 84 delete_Mutex(d->mutex);
100} 85}
101 86
@@ -112,7 +97,6 @@ void add_Periodic(iPeriodic *d, iAny *context, const char *command) {
112 init_PeriodicCommand(&pc, context, command); 97 init_PeriodicCommand(&pc, context, command);
113 insert_SortedArray(&d->commands, &pc); 98 insert_SortedArray(&d->commands, &pc);
114 } 99 }
115 signal_Condition(&d->haveCommands);
116 unlock_Mutex(d->mutex); 100 unlock_Mutex(d->mutex);
117} 101}
118 102
diff --git a/src/periodic.h b/src/periodic.h
index c643a2fe..db90b848 100644
--- a/src/periodic.h
+++ b/src/periodic.h
@@ -26,17 +26,21 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
26iDeclareType(Periodic) 26iDeclareType(Periodic)
27iDeclareType(Thread) 27iDeclareType(Thread)
28 28
29/* Animation utility. Not per frame but several times per second. */ 29/* Animation utility. Not per frame but several times per second. Thread safe. */
30struct Impl_Periodic { 30struct Impl_Periodic {
31 iMutex * mutex; 31 iMutex * mutex;
32 iSortedArray commands; 32 iSortedArray commands;
33 iCondition haveCommands; 33 uint32_t lastPostTime;
34 iThread * thread;
35 iAtomicInt isStopping;
36}; 34};
37 35
38void init_Periodic (iPeriodic *); 36void init_Periodic (iPeriodic *);
39void deinit_Periodic (iPeriodic *); 37void deinit_Periodic (iPeriodic *);
40 38
41void add_Periodic (iPeriodic *, iAny *context, const char *command); 39iLocalDef iBool isEmpty_Periodic(const iPeriodic *d) {
42void remove_Periodic (iPeriodic *, iAny *context); 40 return isEmpty_SortedArray(&d->commands);
41}
42
43void add_Periodic (iPeriodic *, iAny *context, const char *command);
44void remove_Periodic (iPeriodic *, iAny *context);
45
46iBool postCommands_Periodic (iPeriodic *);
diff --git a/src/ui/scrollwidget.c b/src/ui/scrollwidget.c
index b5b204a1..55ede426 100644
--- a/src/ui/scrollwidget.c
+++ b/src/ui/scrollwidget.c
@@ -112,7 +112,7 @@ static void unfade_ScrollWidget_(iScrollWidget *d, float opacity) {
112 d->willCheckFade = iTrue; 112 d->willCheckFade = iTrue;
113 /* TODO: This causes an inexplicable refresh issue on macOS: the drawing of one frame 113 /* TODO: This causes an inexplicable refresh issue on macOS: the drawing of one frame
114 takes 100ms for some reason (not the current frame but some time after). */ 114 takes 100ms for some reason (not the current frame but some time after). */
115// add_Periodic(periodic_App(), d, "scrollbar.fade"); 115 add_Periodic(periodic_App(), d, "scrollbar.fade");
116 } 116 }
117 refresh_Widget(d); 117 refresh_Widget(d);
118} 118}