diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-09-18 08:26:31 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-09-18 08:26:31 +0300 |
commit | 95941a8fca886ba258716c535d51d0d68d075993 (patch) | |
tree | 0be54cd99abf2da1bbc426485c6a980546a6a3a9 | |
parent | daaf3e72b472e05a4378a7789c6ebedd9b0e9b6e (diff) |
Tracking hover widget; cleanup
The hover widget may get deleted during event processing, so Window keeps track of it for refreshing.
TODO: Random crash when a destroyed menu is still in the onTop array (?).
-rw-r--r-- | src/app.c | 20 | ||||
-rw-r--r-- | src/ui/inputwidget.c | 1 | ||||
-rw-r--r-- | src/ui/mobile.c | 6 | ||||
-rw-r--r-- | src/ui/mobile.h | 2 | ||||
-rw-r--r-- | src/ui/root.c | 4 | ||||
-rw-r--r-- | src/ui/touch.c | 6 | ||||
-rw-r--r-- | src/ui/widget.c | 22 | ||||
-rw-r--r-- | src/ui/window.c | 6 | ||||
-rw-r--r-- | src/ui/window.h | 2 |
9 files changed, 31 insertions, 38 deletions
@@ -1069,11 +1069,6 @@ iLocalDef iBool isWaitingAllowed_App_(iApp *d) { | |||
1069 | return iFalse; | 1069 | return iFalse; |
1070 | } | 1070 | } |
1071 | #endif | 1071 | #endif |
1072 | //#if defined (iPlatformMobile) | ||
1073 | // if (!isFinished_Anim(&d->window->rootOffset)) { | ||
1074 | // return iFalse; | ||
1075 | // } | ||
1076 | //#endif | ||
1077 | return !value_Atomic(&d->pendingRefresh) && isEmpty_SortedArray(&d->tickers); | 1072 | return !value_Atomic(&d->pendingRefresh) && isEmpty_SortedArray(&d->tickers); |
1078 | } | 1073 | } |
1079 | 1074 | ||
@@ -1273,7 +1268,7 @@ void processEvents_App(enum iAppEventMode eventMode) { | |||
1273 | } | 1268 | } |
1274 | } | 1269 | } |
1275 | #endif | 1270 | #endif |
1276 | const iWidget *oldHover = d->window->hover; | 1271 | d->window->lastHover = d->window->hover; |
1277 | iBool wasUsed = processEvent_Window(d->window, &ev); | 1272 | iBool wasUsed = processEvent_Window(d->window, &ev); |
1278 | if (!wasUsed) { | 1273 | if (!wasUsed) { |
1279 | /* There may be a key bindings for this. */ | 1274 | /* There may be a key bindings for this. */ |
@@ -1309,8 +1304,8 @@ void processEvents_App(enum iAppEventMode eventMode) { | |||
1309 | free(ev.user.data1); | 1304 | free(ev.user.data1); |
1310 | } | 1305 | } |
1311 | /* Update when hover has changed. */ | 1306 | /* Update when hover has changed. */ |
1312 | if (oldHover != d->window->hover) { | 1307 | if (d->window->lastHover != d->window->hover) { |
1313 | refresh_Widget(oldHover); | 1308 | refresh_Widget(d->window->lastHover); |
1314 | refresh_Widget(d->window->hover); | 1309 | refresh_Widget(d->window->hover); |
1315 | } | 1310 | } |
1316 | break; | 1311 | break; |
@@ -1318,7 +1313,7 @@ void processEvents_App(enum iAppEventMode eventMode) { | |||
1318 | } | 1313 | } |
1319 | } | 1314 | } |
1320 | #if defined (LAGRANGE_ENABLE_IDLE_SLEEP) | 1315 | #if defined (LAGRANGE_ENABLE_IDLE_SLEEP) |
1321 | if (d->isIdling && !gotEvents /*&& isFinished_Anim(&d->window->rootOffset)*/) { | 1316 | if (d->isIdling && !gotEvents) { |
1322 | /* This is where we spend most of our time when idle. 60 Hz still quite a lot but we | 1317 | /* This is where we spend most of our time when idle. 60 Hz still quite a lot but we |
1323 | can't wait too long after the user tries to interact again with the app. In any | 1318 | can't wait too long after the user tries to interact again with the app. In any |
1324 | case, on macOS SDL_WaitEvent() seems to use 10x more CPU time than sleeping. */ | 1319 | case, on macOS SDL_WaitEvent() seems to use 10x more CPU time than sleeping. */ |
@@ -1410,10 +1405,7 @@ void refresh_App(void) { | |||
1410 | } | 1405 | } |
1411 | #endif | 1406 | #endif |
1412 | if (!exchange_Atomic(&d->pendingRefresh, iFalse)) { | 1407 | if (!exchange_Atomic(&d->pendingRefresh, iFalse)) { |
1413 | /* Refreshing wasn't pending. */ | 1408 | return; |
1414 | // if (isFinished_Anim(&d->window->rootOffset)) { | ||
1415 | return; | ||
1416 | // } | ||
1417 | } | 1409 | } |
1418 | // iTime draw; | 1410 | // iTime draw; |
1419 | // initCurrent_Time(&draw); | 1411 | // initCurrent_Time(&draw); |
@@ -2746,7 +2738,7 @@ iBool handleCommand_App(const char *cmd) { | |||
2746 | else if (equal_Command(cmd, "feeds.update.finished")) { | 2738 | else if (equal_Command(cmd, "feeds.update.finished")) { |
2747 | showCollapsed_Widget(findWidget_Root("feeds.progress"), iFalse); | 2739 | showCollapsed_Widget(findWidget_Root("feeds.progress"), iFalse); |
2748 | refreshFinished_Feeds(); | 2740 | refreshFinished_Feeds(); |
2749 | postRefresh_App(); | 2741 | refresh_Widget(findWidget_App("url")); |
2750 | return iFalse; | 2742 | return iFalse; |
2751 | } | 2743 | } |
2752 | else if (equal_Command(cmd, "visited.changed")) { | 2744 | else if (equal_Command(cmd, "visited.changed")) { |
diff --git a/src/ui/inputwidget.c b/src/ui/inputwidget.c index d078593a..a561d5bd 100644 --- a/src/ui/inputwidget.c +++ b/src/ui/inputwidget.c | |||
@@ -1916,6 +1916,7 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) { | |||
1916 | } | 1916 | } |
1917 | return iFalse; | 1917 | return iFalse; |
1918 | } | 1918 | } |
1919 | /* TODO: Scroll to keep widget visible when keyboard appears. */ | ||
1919 | // else if (isCommand_UserEvent(ev, "keyboard.changed")) { | 1920 | // else if (isCommand_UserEvent(ev, "keyboard.changed")) { |
1920 | // if (isFocused_Widget(d) && arg_Command(command_UserEvent(ev))) { | 1921 | // if (isFocused_Widget(d) && arg_Command(command_UserEvent(ev))) { |
1921 | // iRect rect = bounds_Widget(w); | 1922 | // iRect rect = bounds_Widget(w); |
diff --git a/src/ui/mobile.c b/src/ui/mobile.c index e04e8d20..3cb6e631 100644 --- a/src/ui/mobile.c +++ b/src/ui/mobile.c | |||
@@ -425,10 +425,10 @@ static iWidget *addChildPanel_(iWidget *parent, iLabelWidget *panelButton, | |||
425 | return panel; | 425 | return panel; |
426 | } | 426 | } |
427 | 427 | ||
428 | void finalizeSheet_Mobile(iWidget *sheet) { | 428 | //void finalizeSheet_Mobile(iWidget *sheet) { |
429 | arrange_Widget(sheet); | 429 | // arrange_Widget(sheet); |
430 | // postRefresh_App(); | 430 | // postRefresh_App(); |
431 | } | 431 | //} |
432 | 432 | ||
433 | static size_t countItems_(const iMenuItem *itemsNullTerminated) { | 433 | static size_t countItems_(const iMenuItem *itemsNullTerminated) { |
434 | size_t num = 0; | 434 | size_t num = 0; |
diff --git a/src/ui/mobile.h b/src/ui/mobile.h index 957c0e42..9d7ac8e4 100644 --- a/src/ui/mobile.h +++ b/src/ui/mobile.h | |||
@@ -55,5 +55,3 @@ enum iTransitionDir { | |||
55 | 55 | ||
56 | void setupMenuTransition_Mobile (iWidget *menu, iBool isIncoming); | 56 | void setupMenuTransition_Mobile (iWidget *menu, iBool isIncoming); |
57 | void setupSheetTransition_Mobile (iWidget *sheet, int flags); | 57 | void setupSheetTransition_Mobile (iWidget *sheet, int flags); |
58 | |||
59 | void finalizeSheet_Mobile (iWidget *sheet); | ||
diff --git a/src/ui/root.c b/src/ui/root.c index 71f53af4..21bed366 100644 --- a/src/ui/root.c +++ b/src/ui/root.c | |||
@@ -271,13 +271,15 @@ void destroyPending_Root(iRoot *d) { | |||
271 | setCurrent_Root(d); | 271 | setCurrent_Root(d); |
272 | iForEach(PtrSet, i, d->pendingDestruction) { | 272 | iForEach(PtrSet, i, d->pendingDestruction) { |
273 | iWidget *widget = *i.value; | 273 | iWidget *widget = *i.value; |
274 | iAssert(widget->root == d); | ||
274 | if (!isFinished_Anim(&widget->visualOffset) || | 275 | if (!isFinished_Anim(&widget->visualOffset) || |
275 | isBeingVisuallyOffsetByReference_Widget(widget)) { | 276 | isBeingVisuallyOffsetByReference_Widget(widget)) { |
276 | continue; | 277 | continue; |
277 | } | 278 | } |
278 | if (widget->flags & keepOnTop_WidgetFlag) { | 279 | if (widget->flags & keepOnTop_WidgetFlag) { |
279 | removeOne_PtrArray(onTop_Root(widget->root), widget); | 280 | removeOne_PtrArray(d->onTop, widget); |
280 | } | 281 | } |
282 | iAssert(indexOf_PtrArray(d->onTop, widget) == iInvalidPos); | ||
281 | if (widget->parent) { | 283 | if (widget->parent) { |
282 | removeChild_Widget(widget->parent, widget); | 284 | removeChild_Widget(widget->parent, widget); |
283 | } | 285 | } |
diff --git a/src/ui/touch.c b/src/ui/touch.c index 5130149b..613f2c0d 100644 --- a/src/ui/touch.c +++ b/src/ui/touch.c | |||
@@ -472,13 +472,9 @@ iBool processEvent_Touch(const SDL_Event *ev) { | |||
472 | } | 472 | } |
473 | iTouchState *d = touchState_(); | 473 | iTouchState *d = touchState_(); |
474 | iWindow *window = get_Window(); | 474 | iWindow *window = get_Window(); |
475 | // if (!isFinished_Anim(&window->rootOffset)) { | ||
476 | // return iFalse; | ||
477 | // } | ||
478 | const iInt2 rootSize = size_Window(window); | 475 | const iInt2 rootSize = size_Window(window); |
479 | const SDL_TouchFingerEvent *fing = &ev->tfinger; | 476 | const SDL_TouchFingerEvent *fing = &ev->tfinger; |
480 | const iFloat3 pos = add_F3(init_F3(fing->x * rootSize.x, fing->y * rootSize.y, 0), /* pixels */ | 477 | const iFloat3 pos = init_F3(fing->x * rootSize.x, fing->y * rootSize.y, 0); /* pixels */ |
481 | init_F3(0, 0 /*-value_Anim(&window->rootOffset)*/, 0)); | ||
482 | const uint32_t nowTime = SDL_GetTicks(); | 478 | const uint32_t nowTime = SDL_GetTicks(); |
483 | if (ev->type == SDL_FINGERDOWN) { | 479 | if (ev->type == SDL_FINGERDOWN) { |
484 | /* Register the new touch. */ | 480 | /* Register the new touch. */ |
diff --git a/src/ui/widget.c b/src/ui/widget.c index 25142691..184ce2a3 100644 --- a/src/ui/widget.c +++ b/src/ui/widget.c | |||
@@ -163,11 +163,15 @@ static void aboutToBeDestroyed_Widget_(iWidget *d) { | |||
163 | d->flags |= destroyPending_WidgetFlag; | 163 | d->flags |= destroyPending_WidgetFlag; |
164 | if (isFocused_Widget(d)) { | 164 | if (isFocused_Widget(d)) { |
165 | setFocus_Widget(NULL); | 165 | setFocus_Widget(NULL); |
166 | return; | 166 | //return; /* TODO: Why?! */ |
167 | } | 167 | } |
168 | remove_Periodic(periodic_App(), d); | 168 | remove_Periodic(periodic_App(), d); |
169 | iWindow *win = get_Window(); | ||
169 | if (isHover_Widget(d)) { | 170 | if (isHover_Widget(d)) { |
170 | get_Window()->hover = NULL; | 171 | win->hover = NULL; |
172 | } | ||
173 | if (win->lastHover == d) { | ||
174 | win->lastHover = NULL; | ||
171 | } | 175 | } |
172 | iForEach(ObjectList, i, d->children) { | 176 | iForEach(ObjectList, i, d->children) { |
173 | aboutToBeDestroyed_Widget_(as_Widget(i.object)); | 177 | aboutToBeDestroyed_Widget_(as_Widget(i.object)); |
@@ -214,6 +218,7 @@ void setFlags_Widget(iWidget *d, int64_t flags, iBool set) { | |||
214 | } | 218 | } |
215 | else { | 219 | else { |
216 | removeOne_PtrArray(onTop, d); | 220 | removeOne_PtrArray(onTop, d); |
221 | iAssert(indexOf_PtrArray(onTop, d) == iInvalidPos); | ||
217 | } | 222 | } |
218 | } | 223 | } |
219 | if (d->flags & arrangeWidth_WidgetFlag && | 224 | if (d->flags & arrangeWidth_WidgetFlag && |
@@ -880,9 +885,6 @@ iInt2 localToWindow_Widget(const iWidget *d, iInt2 localCoord) { | |||
880 | applyVisualOffset_Widget_(w, &pos); | 885 | applyVisualOffset_Widget_(w, &pos); |
881 | addv_I2(&window, pos); | 886 | addv_I2(&window, pos); |
882 | } | 887 | } |
883 | //#if defined (iPlatformMobile) | ||
884 | // window.y += value_Anim(&get_Window()->rootOffset); | ||
885 | //#endif | ||
886 | return window; | 888 | return window; |
887 | } | 889 | } |
888 | 890 | ||
@@ -962,7 +964,11 @@ static iBool filterEvent_Widget_(const iWidget *d, const SDL_Event *ev) { | |||
962 | } | 964 | } |
963 | 965 | ||
964 | void unhover_Widget(void) { | 966 | void unhover_Widget(void) { |
965 | get_Window()->hover = NULL; | 967 | iWidget **hover = &get_Window()->hover; |
968 | if (*hover) { | ||
969 | refresh_Widget(*hover); | ||
970 | } | ||
971 | *hover = NULL; | ||
966 | } | 972 | } |
967 | 973 | ||
968 | iBool dispatchEvent_Widget(iWidget *d, const SDL_Event *ev) { | 974 | iBool dispatchEvent_Widget(iWidget *d, const SDL_Event *ev) { |
@@ -1415,7 +1421,9 @@ static void findPotentiallyVisible_Widget_(const iWidget *d, iPtrArray *pvs) { | |||
1415 | iRect fullyMasked = zero_Rect(); | 1421 | iRect fullyMasked = zero_Rect(); |
1416 | if (isRoot_Widget_(d)) { | 1422 | if (isRoot_Widget_(d)) { |
1417 | iReverseConstForEach(PtrArray, i, onTop_Root(d->root)) { | 1423 | iReverseConstForEach(PtrArray, i, onTop_Root(d->root)) { |
1418 | addToPotentiallyVisible_Widget_(i.ptr, pvs, &fullyMasked); | 1424 | const iWidget *top = i.ptr; |
1425 | iAssert(top->parent); | ||
1426 | addToPotentiallyVisible_Widget_(top, pvs, &fullyMasked); | ||
1419 | } | 1427 | } |
1420 | } | 1428 | } |
1421 | iReverseConstForEach(ObjectList, i, d->children) { | 1429 | iReverseConstForEach(ObjectList, i, d->children) { |
diff --git a/src/ui/window.c b/src/ui/window.c index ed2ec024..0dd248e6 100644 --- a/src/ui/window.c +++ b/src/ui/window.c | |||
@@ -405,6 +405,7 @@ void init_Window(iWindow *d, iRect rect) { | |||
405 | d->splitMode = d->pendingSplitMode = 0; | 405 | d->splitMode = d->pendingSplitMode = 0; |
406 | d->pendingSplitUrl = new_String(); | 406 | d->pendingSplitUrl = new_String(); |
407 | d->hover = NULL; | 407 | d->hover = NULL; |
408 | d->lastHover = NULL; | ||
408 | d->mouseGrab = NULL; | 409 | d->mouseGrab = NULL; |
409 | d->focus = NULL; | 410 | d->focus = NULL; |
410 | iZap(d->cursors); | 411 | iZap(d->cursors); |
@@ -421,7 +422,6 @@ void init_Window(iWindow *d, iRect rect) { | |||
421 | d->ignoreClick = iFalse; | 422 | d->ignoreClick = iFalse; |
422 | d->focusGainedAt = 0; | 423 | d->focusGainedAt = 0; |
423 | d->keyboardHeight = 0; | 424 | d->keyboardHeight = 0; |
424 | // init_Anim(&d->rootOffset, 0.0f); | ||
425 | uint32_t flags = 0; | 425 | uint32_t flags = 0; |
426 | #if defined (iPlatformAppleDesktop) | 426 | #if defined (iPlatformAppleDesktop) |
427 | SDL_SetHint(SDL_HINT_RENDER_DRIVER, shouldDefaultToMetalRenderer_MacOS() ? "metal" : "opengl"); | 427 | SDL_SetHint(SDL_HINT_RENDER_DRIVER, shouldDefaultToMetalRenderer_MacOS() ? "metal" : "opengl"); |
@@ -1215,10 +1215,6 @@ iBool isOpenGLRenderer_Window(void) { | |||
1215 | void setKeyboardHeight_Window(iWindow *d, int height) { | 1215 | void setKeyboardHeight_Window(iWindow *d, int height) { |
1216 | if (d->keyboardHeight != height) { | 1216 | if (d->keyboardHeight != height) { |
1217 | d->keyboardHeight = height; | 1217 | d->keyboardHeight = height; |
1218 | // if (height == 0) { | ||
1219 | // setFlags_Anim(&d->rootOffset, easeBoth_AnimFlag, iTrue); | ||
1220 | // setValue_Anim(&d->rootOffset, 0, 250); | ||
1221 | // } | ||
1222 | postCommandf_App("keyboard.changed arg:%d", height); | 1218 | postCommandf_App("keyboard.changed arg:%d", height); |
1223 | postRefresh_App(); | 1219 | postRefresh_App(); |
1224 | } | 1220 | } |
diff --git a/src/ui/window.h b/src/ui/window.h index a5b8f137..282e1682 100644 --- a/src/ui/window.h +++ b/src/ui/window.h | |||
@@ -86,6 +86,7 @@ struct Impl_Window { | |||
86 | iRoot * roots[2]; /* root widget and UI state; second one is for split mode */ | 86 | iRoot * roots[2]; /* root widget and UI state; second one is for split mode */ |
87 | iRoot * keyRoot; /* root that has the current keyboard input focus */ | 87 | iRoot * keyRoot; /* root that has the current keyboard input focus */ |
88 | iWidget * hover; | 88 | iWidget * hover; |
89 | iWidget * lastHover; /* cleared if deleted */ | ||
89 | iWidget * mouseGrab; | 90 | iWidget * mouseGrab; |
90 | iWidget * focus; | 91 | iWidget * focus; |
91 | float pixelRatio; /* conversion between points and pixels, e.g., coords, window size */ | 92 | float pixelRatio; /* conversion between points and pixels, e.g., coords, window size */ |
@@ -98,7 +99,6 @@ struct Impl_Window { | |||
98 | SDL_Cursor * cursors[SDL_NUM_SYSTEM_CURSORS]; | 99 | SDL_Cursor * cursors[SDL_NUM_SYSTEM_CURSORS]; |
99 | SDL_Cursor * pendingCursor; | 100 | SDL_Cursor * pendingCursor; |
100 | int loadAnimTimer; | 101 | int loadAnimTimer; |
101 | // iAnim rootOffset; | ||
102 | int keyboardHeight; /* mobile software keyboards */ | 102 | int keyboardHeight; /* mobile software keyboards */ |
103 | }; | 103 | }; |
104 | 104 | ||