Lagrange [work/v1.12]

Mobile: Attempting to mitigate scroll judder

=> fcebf3ede89e9a64a095c0deef4526addff09397

diff --git a/src/app.c b/src/app.c
index d33f31e1..75807111 100644
--- a/src/app.c
+++ b/src/app.c
@@ -43,8 +43,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
 #include "ui/labelwidget.h"
 #include "ui/root.h"
 #include "ui/sidebarwidget.h"
-#include "ui/uploadwidget.h"
+#include "ui/touch.h"
 #include "ui/text.h"
+#include "ui/uploadwidget.h"
 #include "ui/util.h"
 #include "ui/window.h"
 #include "visited.h"
@@ -1376,6 +1377,9 @@ void trimMemory_App(void) {
 }
 
 iLocalDef iBool isWaitingAllowed_App_(iApp *d) {
+//    if (deviceType_App() != desktop_AppDeviceType && numFingers_Touch() > 0) {
+//        return iFalse;
+//    }
     if (d->warmupFrames > 0) {
         return iFalse;
     }
diff --git a/src/ui/touch.c b/src/ui/touch.c
index 21a92b80..1de6c244 100644
--- a/src/ui/touch.c
+++ b/src/ui/touch.c
@@ -79,6 +79,10 @@ struct Impl_Touch {
     iFloat3 pos[numHistory_Touch_];
     size_t posCount;
     iFloat3 accum;
+    iInt2 pendingScroll[3]; /* SDL_FINGERMOTION sometimes arrives in clumps on iOS;
+                               buffer the scrolls to post more evenly */
+    int numPendingScroll;
+    int pendingScrollThreshold;
 };
 
 iLocalDef void pushPos_Touch_(iTouch *d, const iFloat3 pos, uint32_t time) {
@@ -275,6 +279,27 @@ static void update_TouchState_(void *ptr) {
     const uint32_t nowTime = SDL_GetTicks();
     iForEach(Array, i, d->touches) {
         iTouch *touch = i.value;
+        /* Post the next pending scroll. */
+        if (touch->numPendingScroll > touch->pendingScrollThreshold) {
+            const iInt2 pixels = touch->pendingScroll[0];
+//            printf("%u :: (%d/%d) pending scroll %d,%d\n", nowTime, touch->numPendingScroll, touch->pendingScrollThreshold, pixels.x, pixels.y);
+            memmove(touch->pendingScroll, touch->pendingScroll + 1,
+                    sizeof(touch->pendingScroll[0]) * (iElemCount(touch->pendingScroll) - 1));
+            touch->numPendingScroll--;
+            dispatchMotion_Touch_(touch->startPos, 0);
+            setCurrent_Root(touch->affinity->root);
+            dispatchEvent_Widget(touch->affinity, (SDL_Event *) &(SDL_MouseWheelEvent){
+                .type = SDL_MOUSEWHEEL,
+                .which = SDL_TOUCH_MOUSEID,
+                .windowID = id_Window(window_Widget(touch->affinity)),
+                .timestamp = SDL_GetTicks(),
+                .x = pixels.x,
+                .y = pixels.y,
+                .direction = perPixel_MouseWheelFlag,
+            });
+            /* TODO: Keep increasing movement if the direction is the same. */
+            clearWidgetMomentum_TouchState_(d, touch->affinity);
+        }
         if (touch->pinchId || touch->isTouchDrag) {
             continue;
         }
@@ -640,8 +665,9 @@ iBool processEvent_Touch(const SDL_Event *ev) {
             }
 #if 0
             static uint32_t lastTime = 0;
-            printf("%u :: %p (%s) py: %i wy: %f acc: %f edge: %d\n",
+            printf("%u [%u] :: %p (%s) py: %i wy: %f acc: %f edge: %d\n",
                    nowTime - lastTime,
+                   ev->common.timestamp,
                    touch->affinity,
                    class_Widget(touch->affinity)->name,
                    pixels.y, y_F3(amount), y_F3(touch->accum),
@@ -649,20 +675,23 @@ iBool processEvent_Touch(const SDL_Event *ev) {
             lastTime = nowTime;
 #endif
             if (pixels.x || pixels.y) {
-                //setFocus_Widget(NULL);
-                dispatchMotion_Touch_(touch->startPos /*pos[0]*/, 0);
-                setCurrent_Root(touch->affinity->root);
-                dispatchEvent_Widget(touch->affinity, (SDL_Event *) &(SDL_MouseWheelEvent){
-                    .type = SDL_MOUSEWHEEL,
-                    .which = SDL_TOUCH_MOUSEID,
-                    .windowID = id_Window(window_Widget(touch->affinity)),
-                    .timestamp = SDL_GetTicks(),
-                    .x = pixels.x,
-                    .y = pixels.y,
-                    .direction = perPixel_MouseWheelFlag,
-                });
-                /* TODO: Keep increasing movement if the direction is the same. */
-                clearWidgetMomentum_TouchState_(d, touch->affinity);
+                /* Finger events may not arrive at regular intervals (particularly with the SDL on
+                   iOS, it seems!), so we won't post the scroll event immediately but instead
+                   wait until next ticker iteration. This allows us to buffer events if too many
+                   arrive at once. */
+                const int maxPending = iElemCount(touch->pendingScroll);
+                if (touch->numPendingScroll == maxPending) {
+                    addv_I2(&touch->pendingScroll[maxPending - 1], pixels);
+                }
+                else {
+                    touch->pendingScroll[touch->numPendingScroll] = pixels;
+#if defined (iPlatformAppleMobile)
+                    touch->pendingScrollThreshold = iMin(touch->numPendingScroll, 1);
+#else
+                    touch->pendingScrollThreshold = 0;
+#endif
+                    touch->numPendingScroll++;
+                }
             }
         }
     }
@@ -676,11 +705,6 @@ iBool processEvent_Touch(const SDL_Event *ev) {
                 endPinch_TouchState_(d, touch->pinchId);
                 break;
             }
-#if 0
-            if (touch->edgeDragging) {
-                setFlags_Widget(touch->edgeDragging, dragged_WidgetFlag, iFalse);
-            }
-#endif
             if (touch->edge && !isStationary_Touch_(touch)) {
                 const iFloat3 gesture = gestureVector_Touch_(touch);
                 const uint32_t duration = gestureSpan_Touch_(touch);
Proxy Information
Original URL
gemini://git.skyjake.fi/lagrange/work%2Fv1.12/cdiff/fcebf3ede89e9a64a095c0deef4526addff09397
Status Code
Success (20)
Meta
text/gemini; charset=utf-8
Capsule Response Time
65.059343 milliseconds
Gemini-to-HTML Time
0.279537 milliseconds

This content has been proxied by September (3851b).