From b280600222a395c0018b61c04aed7987eab07745 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Kera=CC=88nen?= Date: Sun, 31 Aug 2025 08:09:14 +0300 Subject: [PATCH 1/1] App: Ensure history gets written eventually The visited file is written periodically when using the app. `visited.changed` gets triggered quite often, so avoid writing everything each time. Instead, do it periodically but be more careful about actually getting around to it, especially if the app goes to the background. IssueID #649 --- res/about/ios-version.gmi | 1 + src/app.c | 57 ++++++++++++++++++++++++++++++--------- src/app.h | 1 + src/ui/root.c | 4 +++ src/ui/util.c | 2 ++ src/ui/window.c | 1 - 6 files changed, 53 insertions(+), 13 deletions(-) diff --git a/res/about/ios-version.gmi b/res/about/ios-version.gmi index d5861544..209268c4 100644 --- a/res/about/ios-version.gmi +++ b/res/about/ios-version.gmi @@ -11,6 +11,7 @@ * Added setting for hiding the tab bar. You can manage open tabs in the toolbar "Tabs" tab. * Added settings to choose which toolbar tabs are shown. * Modernized appearance of UI widgets and layout. +* Fixed saving history (i.e., feed entry read status) when app goes to background. * Fixed updating the page context menu so it reflects the state of the current page. * Fixed minor UI glitches. diff --git a/src/app.c b/src/app.c index 173161de..cd54779d 100644 --- a/src/app.c +++ b/src/app.c @@ -179,6 +179,7 @@ struct Impl_App { iBool isFinishedLaunching; iTime lastDropTime; /* for detecting drops of multiple items */ uint32_t lastVisitedSaveTime; + iBool pendingVisitedSave; /* need to save visited URLs soon */ int autoReloadTimer; /* TODO: only start this when tabs are autoreloading */ iPeriodic periodic; int warmupFrames; /* forced refresh just after resuming from background; FIXME: shouldn't be needed */ @@ -1052,6 +1053,34 @@ void commitFile_App(const char *path, const char *tempPathWithNewContents) { remove(cstr_String(oldPath)); } + void deferVisitedSave_App(void) { + iApp *d = &app_; + /* This gets called after the visited URLs have changed, but we want to avoid + writing them constantly to the file. */ + const uint32_t now = SDL_GetTicks(); + const uint32_t seconds = (now - d->lastVisitedSaveTime) / 1000; + iRoot **roots = d->window->roots; + if (seconds >= 60) { + d->lastVisitedSaveTime = now; + if (d->pendingVisitedSave) { + d->pendingVisitedSave = iFalse; + save_Visited(d->visited, dataDir_App_()); + } + } + else if (d->pendingVisitedSave) { + /* Do it later. */ + addDelay_Periodic(&d->periodic, + (60 - seconds) * 1000, roots[0]->widget, + "visited.save"); + return; + } + iForIndices(i, roots) { + if (roots[i]) { + remove_Periodic(&d->periodic, roots[i]->widget); + } + } +} + #if defined (LAGRANGE_ENABLE_IDLE_SLEEP) static uint32_t checkAsleep_App_(uint32_t interval, void *param) { iApp *d = param; @@ -1396,6 +1425,7 @@ static void init_App_(iApp *d, int argc, char **argv) { d->visited = new_Visited(); d->bookmarks = new_Bookmarks(); d->lastVisitedSaveTime = 0; + d->pendingVisitedSave = iFalse; /* Dumping requested pages. */ if (doDump) { const iGmIdentity *ident = NULL; @@ -2046,13 +2076,16 @@ void processEvents_App(enum iAppEventMode eventMode) { #endif switch (ev.type) { case SDL_QUIT: - d->isRunning = iFalse; - if (findWidget_App("prefs")) { - /* Make sure changed preferences get saved. */ - postCommand_Root(NULL, "prefs.dismiss"); - processEvents_App(postedEventsOnly_AppEventMode); + if (!isMobile_Platform()) { + d->isRunning = iFalse; + if (findWidget_App("prefs")) { + /* Make sure changed preferences get saved. */ + postCommand_Root(NULL, "prefs.dismiss"); + processEvents_App(postedEventsOnly_AppEventMode); + } + goto backToMainLoop; } - goto backToMainLoop; + break; case SDL_APP_TERMINATING: { iForEach(PtrArray, i, &d->mainWindows) { setFreezeDraw_MainWindow(*i.value, iTrue); @@ -2099,6 +2132,10 @@ void processEvents_App(enum iAppEventMode eventMode) { iForEach(PtrArray, i, &d->mainWindows) { setFreezeDraw_MainWindow(*i.value, iTrue); } + if (d->pendingVisitedSave) { + save_Visited(visited_App(), dataDir_App_()); + d->pendingVisitedSave = iFalse; + } savePrefs_App_(d); saveState_App_(d, iTrue); d->isSuspended = iTrue; @@ -4385,12 +4422,8 @@ static iBool handleNonWindowRelatedCommand_App_(iApp *d, const char *cmd) { } else if (equal_Command(cmd, "visited.changed")) { /* The visited file can grow large, so don't keep rewriting it after every navigation. */ - const uint32_t now = SDL_GetTicks(); - unsigned seconds = (now - d->lastVisitedSaveTime) / 1000; - if (seconds > 60) { - d->lastVisitedSaveTime = now; - save_Visited(d->visited, dataDir_App_()); - } + d->pendingVisitedSave = iTrue; + deferVisitedSave_App(); return iFalse; } else if (equal_Command(cmd, "idents.changed")) { diff --git a/src/app.h b/src/app.h index cc995e6f..7b92239a 100644 --- a/src/app.h +++ b/src/app.h @@ -138,6 +138,7 @@ iDocumentWidget * newTab_App (const iDocumentWidget *duplicat void trimCache_App (void); void trimMemory_App (void); void saveStateQuickly_App (void); +void deferVisitedSave_App (void); void setTextInputActive_App (iBool); const iStringArray *recentlySubmittedInput_App (void); diff --git a/src/ui/root.c b/src/ui/root.c index 283604ed..4c00fc71 100644 --- a/src/ui/root.c +++ b/src/ui/root.c @@ -760,6 +760,10 @@ iBool handleRootCommands_Widget(iWidget *root, const char *cmd) { refresh_Widget(findWidget_App("toolbar")); return iFalse; } + else if (equal_Command(cmd, "visited.save")) { + deferVisitedSave_App(); + return iTrue; + } return iFalse; } diff --git a/src/ui/util.c b/src/ui/util.c index 0845b5c6..0a546bcb 100644 --- a/src/ui/util.c +++ b/src/ui/util.c @@ -794,6 +794,7 @@ static iBool isCommandIgnoredByMenus_(const char *cmd) { equal_Command(cmd, "android.input.selrange") || equal_Command(cmd, "scrollbar.fade") || equal_Command(cmd, "visited.changed") || + equal_Command(cmd, "visited.save") || (deviceType_App() == desktop_AppDeviceType && equal_Command(cmd, "window.resized")) || equal_Command(cmd, "widget.overflow") || equal_Command(cmd, "metrics.changed") || @@ -2814,6 +2815,7 @@ static iBool messageHandler_(iWidget *msg, const char *cmd) { equal_Command(cmd, "menu.opened") || equal_Command(cmd, "menu.closed") || equal_Command(cmd, "input.backup") || + startsWith_CStr(cmd, "visited.") || startsWith_CStr(cmd, "cancel menu:") || startsWith_CStr(cmd, "feeds.update.") || startsWith_CStr(cmd, "window."))) { diff --git a/src/ui/window.c b/src/ui/window.c index c48a10e5..78dc1412 100644 --- a/src/ui/window.c +++ b/src/ui/window.c @@ -917,7 +917,6 @@ iBool isFullscreen_MainWindow(const iMainWindow *d) { } iRoot *findRoot_Window(const iWindow *d, const iWidget *widget) { - while (widget->parent) { widget = widget->parent; } -- 2.34.1