summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-06-10 12:36:42 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-06-10 12:36:42 +0300
commitb7f40b587087ce4d594ef10af509a5ab92f20466 (patch)
tree9fc55a0409cb8ad9d038d6bd02e07d7aebe75506 /src
parent77ecd8cb2fec2c61f37f4c5561b18fad6fe6137a (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.c41
-rw-r--r--src/app.h1
-rw-r--r--src/history.c48
-rw-r--r--src/history.h7
-rw-r--r--src/prefs.c1
-rw-r--r--src/prefs.h1
-rw-r--r--src/ui/root.c1
-rw-r--r--src/ui/util.c11
8 files changed, 107 insertions, 4 deletions
diff --git a/src/app.c b/src/app.c
index 1ea33dd4..e2e16252 100644
--- a/src/app.c
+++ b/src/app.c
@@ -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
995void 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
994iLocalDef iBool isWaitingAllowed_App_(iApp *d) { 1022iLocalDef 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);
diff --git a/src/app.h b/src/app.h
index 918cd396..2dd5198d 100644
--- a/src/app.h
+++ b/src/app.h
@@ -96,6 +96,7 @@ iObjectList * listDocuments_App (const iRoot *rootOrNull); /* NULL for a
96iStringSet * listOpenURLs_App (void); /* all tabs */ 96iStringSet * listOpenURLs_App (void); /* all tabs */
97iDocumentWidget * newTab_App (const iDocumentWidget *duplicateOf, iBool switchToNew); 97iDocumentWidget * newTab_App (const iDocumentWidget *duplicateOf, iBool switchToNew);
98void trimCache_App (void); 98void trimCache_App (void);
99void trimMemory_App (void);
99 100
100iDocumentWidget * document_Root (iRoot *); 101iDocumentWidget * 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
369size_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
369void clearCache_History(iHistory *d) { 380void 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
423size_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
411const iStringArray *searchContents_History(const iHistory *d, const iRegExp *pattern) { 457const 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 *);
66iRecentUrl *recentUrl_History (iHistory *, size_t pos); 66iRecentUrl *recentUrl_History (iHistory *, size_t pos);
67iRecentUrl *mostRecentUrl_History (iHistory *); 67iRecentUrl *mostRecentUrl_History (iHistory *);
68iRecentUrl *findUrl_History (iHistory *, const iString *url); 68iRecentUrl *findUrl_History (iHistory *, const iString *url);
69void clearCache_History (iHistory *); 69
70size_t pruneLeastImportant_History (iHistory *); 70void clearCache_History (iHistory *);
71size_t pruneLeastImportant_History (iHistory *);
72size_t pruneLeastImportantMemory_History (iHistory *);
71 73
72iBool atLatest_History (const iHistory *); 74iBool atLatest_History (const iHistory *);
73iBool atOldest_History (const iHistory *); 75iBool atOldest_History (const iHistory *);
@@ -83,6 +85,7 @@ const iRecentUrl *
83const iGmResponse * 85const iGmResponse *
84 cachedResponse_History (const iHistory *); 86 cachedResponse_History (const iHistory *);
85size_t cacheSize_History (const iHistory *); 87size_t cacheSize_History (const iHistory *);
88size_t memorySize_History (const iHistory *);
86 89
87iString * debugInfo_History (const iHistory *); 90iString * debugInfo_History (const iHistory *);
88iMemInfo memoryUsage_History (const iHistory *); 91iMemInfo 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)));