diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-06-10 12:36:42 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-06-10 12:36:42 +0300 |
commit | b7f40b587087ce4d594ef10af509a5ab92f20466 (patch) | |
tree | 9fc55a0409cb8ad9d038d6bd02e07d7aebe75506 /src | |
parent | 77ecd8cb2fec2c61f37f4c5561b18fad6fe6137a (diff) |
Preferences: Memory size limit
Memory used for RAM storage of media along with navigation history so it can be restored instantly.
Diffstat (limited to 'src')
-rw-r--r-- | src/app.c | 41 | ||||
-rw-r--r-- | src/app.h | 1 | ||||
-rw-r--r-- | src/history.c | 48 | ||||
-rw-r--r-- | src/history.h | 7 | ||||
-rw-r--r-- | src/prefs.c | 1 | ||||
-rw-r--r-- | src/prefs.h | 1 | ||||
-rw-r--r-- | src/ui/root.c | 1 | ||||
-rw-r--r-- | src/ui/util.c | 11 |
8 files changed, 107 insertions, 4 deletions
@@ -210,6 +210,7 @@ static iString *serializePrefs_App_(const iApp *d) { | |||
210 | appendFormat_String(str, "smoothscroll arg:%d\n", d->prefs.smoothScrolling); | 210 | appendFormat_String(str, "smoothscroll arg:%d\n", d->prefs.smoothScrolling); |
211 | appendFormat_String(str, "imageloadscroll arg:%d\n", d->prefs.loadImageInsteadOfScrolling); | 211 | appendFormat_String(str, "imageloadscroll arg:%d\n", d->prefs.loadImageInsteadOfScrolling); |
212 | appendFormat_String(str, "cachesize.set arg:%d\n", d->prefs.maxCacheSize); | 212 | appendFormat_String(str, "cachesize.set arg:%d\n", d->prefs.maxCacheSize); |
213 | appendFormat_String(str, "memorysize.set arg:%d\n", d->prefs.maxMemorySize); | ||
213 | appendFormat_String(str, "decodeurls arg:%d\n", d->prefs.decodeUserVisibleURLs); | 214 | appendFormat_String(str, "decodeurls arg:%d\n", d->prefs.decodeUserVisibleURLs); |
214 | appendFormat_String(str, "linewidth.set arg:%d\n", d->prefs.lineWidth); | 215 | appendFormat_String(str, "linewidth.set arg:%d\n", d->prefs.lineWidth); |
215 | /* TODO: Set up an array of booleans in Prefs and do these in a loop. */ | 216 | /* TODO: Set up an array of booleans in Prefs and do these in a loop. */ |
@@ -991,6 +992,33 @@ void trimCache_App(void) { | |||
991 | iRelease(docs); | 992 | iRelease(docs); |
992 | } | 993 | } |
993 | 994 | ||
995 | void trimMemory_App(void) { | ||
996 | iApp *d = &app_; | ||
997 | size_t memorySize = 0; | ||
998 | const size_t limit = d->prefs.maxMemorySize * 1000000; | ||
999 | iObjectList *docs = listDocuments_App(NULL); | ||
1000 | iForEach(ObjectList, i, docs) { | ||
1001 | memorySize += memorySize_History(history_DocumentWidget(i.object)); | ||
1002 | } | ||
1003 | init_ObjectListIterator(&i, docs); | ||
1004 | iBool wasPruned = iFalse; | ||
1005 | while (memorySize > limit) { | ||
1006 | iDocumentWidget *doc = i.object; | ||
1007 | const size_t pruned = pruneLeastImportantMemory_History(history_DocumentWidget(doc)); | ||
1008 | if (pruned) { | ||
1009 | memorySize -= pruned; | ||
1010 | wasPruned = iTrue; | ||
1011 | } | ||
1012 | next_ObjectListIterator(&i); | ||
1013 | if (!i.value) { | ||
1014 | if (!wasPruned) break; | ||
1015 | wasPruned = iFalse; | ||
1016 | init_ObjectListIterator(&i, docs); | ||
1017 | } | ||
1018 | } | ||
1019 | iRelease(docs); | ||
1020 | } | ||
1021 | |||
994 | iLocalDef iBool isWaitingAllowed_App_(iApp *d) { | 1022 | iLocalDef iBool isWaitingAllowed_App_(iApp *d) { |
995 | if (!isEmpty_Periodic(&d->periodic)) { | 1023 | if (!isEmpty_Periodic(&d->periodic)) { |
996 | return iFalse; | 1024 | return iFalse; |
@@ -1577,7 +1605,9 @@ static iBool handlePrefsCommands_(iWidget *d, const char *cmd) { | |||
1577 | postCommandf_App("searchurl address:%s", | 1605 | postCommandf_App("searchurl address:%s", |
1578 | cstrText_InputWidget(findChild_Widget(d, "prefs.searchurl"))); | 1606 | cstrText_InputWidget(findChild_Widget(d, "prefs.searchurl"))); |
1579 | postCommandf_App("cachesize.set arg:%d", | 1607 | postCommandf_App("cachesize.set arg:%d", |
1580 | toInt_String(text_InputWidget(findChild_Widget(d, "prefs.cachesize")))); | 1608 | toInt_String(text_InputWidget(findChild_Widget(d, "prefs.cachesize")))); |
1609 | postCommandf_App("memorysize.set arg:%d", | ||
1610 | toInt_String(text_InputWidget(findChild_Widget(d, "prefs.memorysize")))); | ||
1581 | postCommandf_App("ca.file path:%s", | 1611 | postCommandf_App("ca.file path:%s", |
1582 | cstrText_InputWidget(findChild_Widget(d, "prefs.ca.file"))); | 1612 | cstrText_InputWidget(findChild_Widget(d, "prefs.ca.file"))); |
1583 | postCommandf_App("ca.path path:%s", | 1613 | postCommandf_App("ca.path path:%s", |
@@ -2139,6 +2169,13 @@ iBool handleCommand_App(const char *cmd) { | |||
2139 | } | 2169 | } |
2140 | return iTrue; | 2170 | return iTrue; |
2141 | } | 2171 | } |
2172 | else if (equal_Command(cmd, "memorysize.set")) { | ||
2173 | d->prefs.maxMemorySize = arg_Command(cmd); | ||
2174 | if (d->prefs.maxMemorySize <= 0) { | ||
2175 | d->prefs.maxMemorySize = 0; | ||
2176 | } | ||
2177 | return iTrue; | ||
2178 | } | ||
2142 | else if (equal_Command(cmd, "searchurl")) { | 2179 | else if (equal_Command(cmd, "searchurl")) { |
2143 | iString *url = &d->prefs.searchUrl; | 2180 | iString *url = &d->prefs.searchUrl; |
2144 | setCStr_String(url, suffixPtr_Command(cmd, "address")); | 2181 | setCStr_String(url, suffixPtr_Command(cmd, "address")); |
@@ -2417,6 +2454,8 @@ iBool handleCommand_App(const char *cmd) { | |||
2417 | iTrue); | 2454 | iTrue); |
2418 | setText_InputWidget(findChild_Widget(dlg, "prefs.cachesize"), | 2455 | setText_InputWidget(findChild_Widget(dlg, "prefs.cachesize"), |
2419 | collectNewFormat_String("%d", d->prefs.maxCacheSize)); | 2456 | collectNewFormat_String("%d", d->prefs.maxCacheSize)); |
2457 | setText_InputWidget(findChild_Widget(dlg, "prefs.memorysize"), | ||
2458 | collectNewFormat_String("%d", d->prefs.maxMemorySize)); | ||
2420 | setToggle_Widget(findChild_Widget(dlg, "prefs.decodeurls"), d->prefs.decodeUserVisibleURLs); | 2459 | setToggle_Widget(findChild_Widget(dlg, "prefs.decodeurls"), d->prefs.decodeUserVisibleURLs); |
2421 | setText_InputWidget(findChild_Widget(dlg, "prefs.searchurl"), &d->prefs.searchUrl); | 2460 | setText_InputWidget(findChild_Widget(dlg, "prefs.searchurl"), &d->prefs.searchUrl); |
2422 | setText_InputWidget(findChild_Widget(dlg, "prefs.ca.file"), &d->prefs.caFile); | 2461 | setText_InputWidget(findChild_Widget(dlg, "prefs.ca.file"), &d->prefs.caFile); |
@@ -96,6 +96,7 @@ iObjectList * listDocuments_App (const iRoot *rootOrNull); /* NULL for a | |||
96 | iStringSet * listOpenURLs_App (void); /* all tabs */ | 96 | iStringSet * listOpenURLs_App (void); /* all tabs */ |
97 | iDocumentWidget * newTab_App (const iDocumentWidget *duplicateOf, iBool switchToNew); | 97 | iDocumentWidget * newTab_App (const iDocumentWidget *duplicateOf, iBool switchToNew); |
98 | void trimCache_App (void); | 98 | void trimCache_App (void); |
99 | void trimMemory_App (void); | ||
99 | 100 | ||
100 | iDocumentWidget * document_Root (iRoot *); | 101 | iDocumentWidget * document_Root (iRoot *); |
101 | 102 | ||
diff --git a/src/history.c b/src/history.c index fdd0ff55..740830e9 100644 --- a/src/history.c +++ b/src/history.c | |||
@@ -366,6 +366,17 @@ size_t cacheSize_History(const iHistory *d) { | |||
366 | return cached; | 366 | return cached; |
367 | } | 367 | } |
368 | 368 | ||
369 | size_t memorySize_History(const iHistory *d) { | ||
370 | size_t bytes = 0; | ||
371 | lock_Mutex(d->mtx); | ||
372 | iConstForEach(Array, i, &d->recent) { | ||
373 | const iRecentUrl *url = i.value; | ||
374 | bytes += memorySize_RecentUrl(url); | ||
375 | } | ||
376 | unlock_Mutex(d->mtx); | ||
377 | return bytes; | ||
378 | } | ||
379 | |||
369 | void clearCache_History(iHistory *d) { | 380 | void clearCache_History(iHistory *d) { |
370 | lock_Mutex(d->mtx); | 381 | lock_Mutex(d->mtx); |
371 | iForEach(Array, i, &d->recent) { | 382 | iForEach(Array, i, &d->recent) { |
@@ -374,6 +385,7 @@ void clearCache_History(iHistory *d) { | |||
374 | delete_GmResponse(url->cachedResponse); | 385 | delete_GmResponse(url->cachedResponse); |
375 | url->cachedResponse = NULL; | 386 | url->cachedResponse = NULL; |
376 | } | 387 | } |
388 | iReleasePtr(&url->cachedDoc); /* release all cached documents and media as well */ | ||
377 | } | 389 | } |
378 | unlock_Mutex(d->mtx); | 390 | unlock_Mutex(d->mtx); |
379 | } | 391 | } |
@@ -387,7 +399,7 @@ size_t pruneLeastImportant_History(iHistory *d) { | |||
387 | lock_Mutex(d->mtx); | 399 | lock_Mutex(d->mtx); |
388 | iConstForEach(Array, i, &d->recent) { | 400 | iConstForEach(Array, i, &d->recent) { |
389 | const iRecentUrl *url = i.value; | 401 | const iRecentUrl *url = i.value; |
390 | if (url->cachedResponse || url->cachedDoc) { | 402 | if (url->cachedResponse) { |
391 | const double urlScore = | 403 | const double urlScore = |
392 | cacheSize_RecentUrl(url) * | 404 | cacheSize_RecentUrl(url) * |
393 | pow(secondsSince_Time(&now, &url->cachedResponse->when) / 60.0, 1.25); | 405 | pow(secondsSince_Time(&now, &url->cachedResponse->when) / 60.0, 1.25); |
@@ -408,6 +420,40 @@ size_t pruneLeastImportant_History(iHistory *d) { | |||
408 | return delta; | 420 | return delta; |
409 | } | 421 | } |
410 | 422 | ||
423 | size_t pruneLeastImportantMemory_History(iHistory *d) { | ||
424 | size_t delta = 0; | ||
425 | size_t chosen = iInvalidPos; | ||
426 | double score = 0.0f; | ||
427 | iTime now; | ||
428 | initCurrent_Time(&now); | ||
429 | lock_Mutex(d->mtx); | ||
430 | iConstForEach(Array, i, &d->recent) { | ||
431 | const iRecentUrl *url = i.value; | ||
432 | if (d->recentPos == size_Array(&d->recent) - index_ArrayConstIterator(&i) - 1) { | ||
433 | continue; /* Not the current navigation position. */ | ||
434 | } | ||
435 | if (url->cachedDoc) { | ||
436 | const double urlScore = | ||
437 | memorySize_RecentUrl(url) * | ||
438 | (url->cachedResponse | ||
439 | ? pow(secondsSince_Time(&now, &url->cachedResponse->when) / 60.0, 1.25) | ||
440 | : 1.0); | ||
441 | if (urlScore > score) { | ||
442 | chosen = index_ArrayConstIterator(&i); | ||
443 | score = urlScore; | ||
444 | } | ||
445 | } | ||
446 | } | ||
447 | if (chosen != iInvalidPos) { | ||
448 | iRecentUrl *url = at_Array(&d->recent, chosen); | ||
449 | const size_t before = memorySize_RecentUrl(url); | ||
450 | iReleasePtr(&url->cachedDoc); | ||
451 | delta = before - memorySize_RecentUrl(url); | ||
452 | } | ||
453 | unlock_Mutex(d->mtx); | ||
454 | return delta; | ||
455 | } | ||
456 | |||
411 | const iStringArray *searchContents_History(const iHistory *d, const iRegExp *pattern) { | 457 | const iStringArray *searchContents_History(const iHistory *d, const iRegExp *pattern) { |
412 | iStringArray *urls = iClob(new_StringArray()); | 458 | iStringArray *urls = iClob(new_StringArray()); |
413 | lock_Mutex(d->mtx); | 459 | lock_Mutex(d->mtx); |
diff --git a/src/history.h b/src/history.h index ccc19d27..eb35b1df 100644 --- a/src/history.h +++ b/src/history.h | |||
@@ -66,8 +66,10 @@ iBool goForward_History (iHistory *); | |||
66 | iRecentUrl *recentUrl_History (iHistory *, size_t pos); | 66 | iRecentUrl *recentUrl_History (iHistory *, size_t pos); |
67 | iRecentUrl *mostRecentUrl_History (iHistory *); | 67 | iRecentUrl *mostRecentUrl_History (iHistory *); |
68 | iRecentUrl *findUrl_History (iHistory *, const iString *url); | 68 | iRecentUrl *findUrl_History (iHistory *, const iString *url); |
69 | void clearCache_History (iHistory *); | 69 | |
70 | size_t pruneLeastImportant_History (iHistory *); | 70 | void clearCache_History (iHistory *); |
71 | size_t pruneLeastImportant_History (iHistory *); | ||
72 | size_t pruneLeastImportantMemory_History (iHistory *); | ||
71 | 73 | ||
72 | iBool atLatest_History (const iHistory *); | 74 | iBool atLatest_History (const iHistory *); |
73 | iBool atOldest_History (const iHistory *); | 75 | iBool atOldest_History (const iHistory *); |
@@ -83,6 +85,7 @@ const iRecentUrl * | |||
83 | const iGmResponse * | 85 | const iGmResponse * |
84 | cachedResponse_History (const iHistory *); | 86 | cachedResponse_History (const iHistory *); |
85 | size_t cacheSize_History (const iHistory *); | 87 | size_t cacheSize_History (const iHistory *); |
88 | size_t memorySize_History (const iHistory *); | ||
86 | 89 | ||
87 | iString * debugInfo_History (const iHistory *); | 90 | iString * debugInfo_History (const iHistory *); |
88 | iMemInfo memoryUsage_History (const iHistory *); | 91 | iMemInfo memoryUsage_History (const iHistory *); |
diff --git a/src/prefs.c b/src/prefs.c index 385dee78..f1842e9a 100644 --- a/src/prefs.c +++ b/src/prefs.c | |||
@@ -46,6 +46,7 @@ void init_Prefs(iPrefs *d) { | |||
46 | d->openArchiveIndexPages = iTrue; | 46 | d->openArchiveIndexPages = iTrue; |
47 | d->decodeUserVisibleURLs = iTrue; | 47 | d->decodeUserVisibleURLs = iTrue; |
48 | d->maxCacheSize = 10; | 48 | d->maxCacheSize = 10; |
49 | d->maxMemorySize = 200; | ||
49 | d->font = nunito_TextFont; | 50 | d->font = nunito_TextFont; |
50 | d->headingFont = nunito_TextFont; | 51 | d->headingFont = nunito_TextFont; |
51 | d->monospaceGemini = iFalse; | 52 | d->monospaceGemini = iFalse; |
diff --git a/src/prefs.h b/src/prefs.h index 7185c8f9..655ec949 100644 --- a/src/prefs.h +++ b/src/prefs.h | |||
@@ -66,6 +66,7 @@ struct Impl_Prefs { | |||
66 | iString caPath; | 66 | iString caPath; |
67 | iBool decodeUserVisibleURLs; | 67 | iBool decodeUserVisibleURLs; |
68 | int maxCacheSize; /* MB */ | 68 | int maxCacheSize; /* MB */ |
69 | int maxMemorySize; /* MB */ | ||
69 | iString geminiProxy; | 70 | iString geminiProxy; |
70 | iString gopherProxy; | 71 | iString gopherProxy; |
71 | iString httpProxy; | 72 | iString httpProxy; |
diff --git a/src/ui/root.c b/src/ui/root.c index 23a7d670..52bc7364 100644 --- a/src/ui/root.c +++ b/src/ui/root.c | |||
@@ -698,6 +698,7 @@ static iBool handleNavBarCommands_(iWidget *navBar, const char *cmd) { | |||
698 | iInputWidget *url = findWidget_Root("url"); | 698 | iInputWidget *url = findWidget_Root("url"); |
699 | const iString *urlStr = collect_String(suffix_Command(cmd, "url")); | 699 | const iString *urlStr = collect_String(suffix_Command(cmd, "url")); |
700 | trimCache_App(); | 700 | trimCache_App(); |
701 | trimMemory_App(); | ||
701 | visitUrl_Visited(visited_App(), withSpacesEncoded_String(urlStr), 0); /* TODO: internal URI normalization */ | 702 | visitUrl_Visited(visited_App(), withSpacesEncoded_String(urlStr), 0); /* TODO: internal URI normalization */ |
702 | postCommand_App("visited.changed"); /* sidebar will update */ | 703 | postCommand_App("visited.changed"); /* sidebar will update */ |
703 | setText_InputWidget(url, urlStr); | 704 | setText_InputWidget(url, urlStr); |
diff --git a/src/ui/util.c b/src/ui/util.c index 6eef544b..6c6e62a5 100644 --- a/src/ui/util.c +++ b/src/ui/util.c | |||
@@ -1834,6 +1834,17 @@ iWidget *makePreferences_Widget(void) { | |||
1834 | resizeToParentHeight_WidgetFlag); | 1834 | resizeToParentHeight_WidgetFlag); |
1835 | setContentPadding_InputWidget(cache, 0, width_Widget(unit) - 4 * gap_UI); | 1835 | setContentPadding_InputWidget(cache, 0, width_Widget(unit) - 4 * gap_UI); |
1836 | } | 1836 | } |
1837 | /* Memory size. */ { | ||
1838 | iInputWidget *mem = new_InputWidget(4); | ||
1839 | setSelectAllOnFocus_InputWidget(mem, iTrue); | ||
1840 | addPrefsInputWithHeading_(headings, values, "prefs.memorysize", iClob(mem)); | ||
1841 | iWidget *unit = | ||
1842 | addChildFlags_Widget(as_Widget(mem), | ||
1843 | iClob(new_LabelWidget("${mb}", NULL)), | ||
1844 | frameless_WidgetFlag | moveToParentRightEdge_WidgetFlag | | ||
1845 | resizeToParentHeight_WidgetFlag); | ||
1846 | setContentPadding_InputWidget(mem, 0, width_Widget(unit) - 4 * gap_UI); | ||
1847 | } | ||
1837 | makeTwoColumnHeading_("${heading.prefs.certs}", headings, values); | 1848 | makeTwoColumnHeading_("${heading.prefs.certs}", headings, values); |
1838 | addPrefsInputWithHeading_(headings, values, "prefs.ca.file", iClob(new_InputWidget(0))); | 1849 | addPrefsInputWithHeading_(headings, values, "prefs.ca.file", iClob(new_InputWidget(0))); |
1839 | addPrefsInputWithHeading_(headings, values, "prefs.ca.path", iClob(new_InputWidget(0))); | 1850 | addPrefsInputWithHeading_(headings, values, "prefs.ca.path", iClob(new_InputWidget(0))); |