summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-01-27 21:28:25 +0200
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-01-27 21:28:25 +0200
commiteda45fcd34189e6844babde1ebc60c083b1b09da (patch)
tree40a5aa0671a59a4180913cee518735a3c72f3f5c
parent688fe6c5882e7493f0e2750f0ff8f20d3613e270 (diff)
Added preference for maximum cache size
Rather than simply limiting each tab's cache to 50 most recent URLs, there is now a user-configurable maximum size. If more content is cached, the oldest/largest responses will be removed from memory. The default maximum cache size is 10 MB. IssueID #109
-rw-r--r--src/app.c42
-rw-r--r--src/app.h18
-rw-r--r--src/history.c43
-rw-r--r--src/history.h2
-rw-r--r--src/prefs.c1
-rw-r--r--src/prefs.h1
-rw-r--r--src/ui/util.c19
-rw-r--r--src/ui/window.c1
8 files changed, 113 insertions, 14 deletions
diff --git a/src/app.c b/src/app.c
index 5d27618b..82628c9c 100644
--- a/src/app.c
+++ b/src/app.c
@@ -194,6 +194,7 @@ static iString *serializePrefs_App_(const iApp *d) {
194 appendFormat_String(str, "zoom.set arg:%d\n", d->prefs.zoomPercent); 194 appendFormat_String(str, "zoom.set arg:%d\n", d->prefs.zoomPercent);
195 appendFormat_String(str, "smoothscroll arg:%d\n", d->prefs.smoothScrolling); 195 appendFormat_String(str, "smoothscroll arg:%d\n", d->prefs.smoothScrolling);
196 appendFormat_String(str, "imageloadscroll arg:%d\n", d->prefs.loadImageInsteadOfScrolling); 196 appendFormat_String(str, "imageloadscroll arg:%d\n", d->prefs.loadImageInsteadOfScrolling);
197 appendFormat_String(str, "cachesize.set arg:%d\n", d->prefs.maxCacheSize);
197 appendFormat_String(str, "decodeurls arg:%d\n", d->prefs.decodeUserVisibleURLs); 198 appendFormat_String(str, "decodeurls arg:%d\n", d->prefs.decodeUserVisibleURLs);
198 appendFormat_String(str, "linewidth.set arg:%d\n", d->prefs.lineWidth); 199 appendFormat_String(str, "linewidth.set arg:%d\n", d->prefs.lineWidth);
199 appendFormat_String(str, "prefs.biglede.changed arg:%d\n", d->prefs.bigFirstParagraph); 200 appendFormat_String(str, "prefs.biglede.changed arg:%d\n", d->prefs.bigFirstParagraph);
@@ -321,6 +322,7 @@ iObjectList *listDocuments_App(void) {
321 322
322static void saveState_App_(const iApp *d) { 323static void saveState_App_(const iApp *d) {
323 iUnused(d); 324 iUnused(d);
325 trimCache_App();
324 iFile *f = newCStr_File(concatPath_CStr(dataDir_App_, stateFileName_App_)); 326 iFile *f = newCStr_File(concatPath_CStr(dataDir_App_, stateFileName_App_));
325 if (open_File(f, writeOnly_FileMode)) { 327 if (open_File(f, writeOnly_FileMode)) {
326 writeData_File(f, magicState_App_, 4); 328 writeData_File(f, magicState_App_, 4);
@@ -503,7 +505,7 @@ const iString *debugInfo_App(void) {
503 iString *msg = collectNew_String(); 505 iString *msg = collectNew_String();
504 format_String(msg, "# Debug information\n"); 506 format_String(msg, "# Debug information\n");
505 appendFormat_String(msg, "## Documents\n"); 507 appendFormat_String(msg, "## Documents\n");
506 iForEach(ObjectList, k, listDocuments_App()) { 508 iForEach(ObjectList, k, iClob(listDocuments_App())) {
507 iDocumentWidget *doc = k.object; 509 iDocumentWidget *doc = k.object;
508 appendFormat_String(msg, "### Tab %zu: %s\n", 510 appendFormat_String(msg, "### Tab %zu: %s\n",
509 childIndex_Widget(constAs_Widget(doc)->parent, k.object), 511 childIndex_Widget(constAs_Widget(doc)->parent, k.object),
@@ -857,6 +859,8 @@ static iBool handlePrefsCommands_(iWidget *d, const char *cmd) {
857 isSelected_Widget(findChild_Widget(d, "prefs.ostheme"))); 859 isSelected_Widget(findChild_Widget(d, "prefs.ostheme")));
858 postCommandf_App("decodeurls arg:%d", 860 postCommandf_App("decodeurls arg:%d",
859 isSelected_Widget(findChild_Widget(d, "prefs.decodeurls"))); 861 isSelected_Widget(findChild_Widget(d, "prefs.decodeurls")));
862 postCommandf_App("cachesize.set arg:%d",
863 toInt_String(text_InputWidget(findChild_Widget(d, "prefs.cachesize"))));
860 postCommandf_App("proxy.gemini address:%s", 864 postCommandf_App("proxy.gemini address:%s",
861 cstr_String(text_InputWidget(findChild_Widget(d, "prefs.proxy.gemini")))); 865 cstr_String(text_InputWidget(findChild_Widget(d, "prefs.proxy.gemini"))));
862 postCommandf_App("proxy.gopher address:%s", 866 postCommandf_App("proxy.gopher address:%s",
@@ -940,6 +944,33 @@ iDocumentWidget *newTab_App(const iDocumentWidget *duplicateOf, iBool switchToNe
940 return doc; 944 return doc;
941} 945}
942 946
947void trimCache_App(void) {
948 iApp *d = &app_;
949 size_t cacheSize = 0;
950 const size_t limit = d->prefs.maxCacheSize * 1000000;
951 iObjectList *docs = listDocuments_App();
952 iForEach(ObjectList, i, docs) {
953 cacheSize += cacheSize_History(history_DocumentWidget(i.object));
954 }
955 init_ObjectListIterator(&i, docs);
956 iBool wasPruned = iFalse;
957 while (cacheSize > limit) {
958 iDocumentWidget *doc = i.object;
959 const size_t pruned = pruneLeastImportant_History(history_DocumentWidget(doc));
960 if (pruned) {
961 cacheSize -= pruned;
962 wasPruned = iTrue;
963 }
964 next_ObjectListIterator(&i);
965 if (!i.value) {
966 if (!wasPruned) break;
967 wasPruned = iFalse;
968 init_ObjectListIterator(&i, docs);
969 }
970 }
971 iRelease(docs);
972}
973
943static iBool handleIdentityCreationCommands_(iWidget *dlg, const char *cmd) { 974static iBool handleIdentityCreationCommands_(iWidget *dlg, const char *cmd) {
944 iApp *d = &app_; 975 iApp *d = &app_;
945 if (equal_Command(cmd, "ident.temp.changed")) { 976 if (equal_Command(cmd, "ident.temp.changed")) {
@@ -1154,6 +1185,13 @@ iBool handleCommand_App(const char *cmd) {
1154 postCommandf_App("theme.changed auto:1"); 1185 postCommandf_App("theme.changed auto:1");
1155 return iTrue; 1186 return iTrue;
1156 } 1187 }
1188 else if (equal_Command(cmd, "cachesize.set")) {
1189 d->prefs.maxCacheSize = arg_Command(cmd);
1190 if (d->prefs.maxCacheSize <= 0) {
1191 d->prefs.maxCacheSize = 0;
1192 }
1193 return iTrue;
1194 }
1157 else if (equal_Command(cmd, "proxy.gemini")) { 1195 else if (equal_Command(cmd, "proxy.gemini")) {
1158 setCStr_String(&d->prefs.geminiProxy, suffixPtr_Command(cmd, "address")); 1196 setCStr_String(&d->prefs.geminiProxy, suffixPtr_Command(cmd, "address"));
1159 return iTrue; 1197 return iTrue;
@@ -1331,6 +1369,8 @@ iBool handleCommand_App(const char *cmd) {
1331 dlg, format_CStr("prefs.saturation.%d", (int) (d->prefs.saturation * 3.99f))), 1369 dlg, format_CStr("prefs.saturation.%d", (int) (d->prefs.saturation * 3.99f))),
1332 selected_WidgetFlag, 1370 selected_WidgetFlag,
1333 iTrue); 1371 iTrue);
1372 setText_InputWidget(findChild_Widget(dlg, "prefs.cachesize"),
1373 collectNewFormat_String("%d", d->prefs.maxCacheSize));
1334 setToggle_Widget(findChild_Widget(dlg, "prefs.decodeurls"), d->prefs.decodeUserVisibleURLs); 1374 setToggle_Widget(findChild_Widget(dlg, "prefs.decodeurls"), d->prefs.decodeUserVisibleURLs);
1335 setText_InputWidget(findChild_Widget(dlg, "prefs.proxy.gemini"), &d->prefs.geminiProxy); 1375 setText_InputWidget(findChild_Widget(dlg, "prefs.proxy.gemini"), &d->prefs.geminiProxy);
1336 setText_InputWidget(findChild_Widget(dlg, "prefs.proxy.gopher"), &d->prefs.gopherProxy); 1376 setText_InputWidget(findChild_Widget(dlg, "prefs.proxy.gopher"), &d->prefs.gopherProxy);
diff --git a/src/app.h b/src/app.h
index 0e8351aa..efaf0a3e 100644
--- a/src/app.h
+++ b/src/app.h
@@ -61,20 +61,20 @@ void refresh_App (void);
61iBool isRefreshPending_App (void); 61iBool isRefreshPending_App (void);
62uint32_t elapsedSinceLastTicker_App (void); /* milliseconds */ 62uint32_t elapsedSinceLastTicker_App (void); /* milliseconds */
63 63
64const iPrefs * prefs_App (void);
65iBool forceSoftwareRender_App(void);
66enum iColorTheme colorTheme_App (void);
67const iString * schemeProxy_App (iRangecc scheme);
68iBool willUseProxy_App (const iRangecc scheme);
69
70iMimeHooks * mimeHooks_App (void);
71iGmCerts * certs_App (void); 64iGmCerts * certs_App (void);
72iVisited * visited_App (void); 65iVisited * visited_App (void);
73iBookmarks * bookmarks_App (void); 66iBookmarks * bookmarks_App (void);
67iMimeHooks * mimeHooks_App (void);
74iDocumentWidget * document_App (void); 68iDocumentWidget * document_App (void);
75iObjectList * listDocuments_App (void); 69iObjectList * listDocuments_App (void);
76iDocumentWidget * document_Command (const char *cmd);
77iDocumentWidget * newTab_App (const iDocumentWidget *duplicateOf, iBool switchToNew); 70iDocumentWidget * newTab_App (const iDocumentWidget *duplicateOf, iBool switchToNew);
71void trimCache_App (void);
72
73const iPrefs * prefs_App (void);
74iBool forceSoftwareRender_App(void);
75enum iColorTheme colorTheme_App (void);
76const iString * schemeProxy_App (iRangecc scheme);
77iBool willUseProxy_App (const iRangecc scheme);
78 78
79typedef void (*iTickerFunc)(iAny *); 79typedef void (*iTickerFunc)(iAny *);
80 80
@@ -91,5 +91,7 @@ iLocalDef void postCommandString_App(const iString *command) {
91 } 91 }
92} 92}
93 93
94iDocumentWidget * document_Command (const char *cmd);
95
94void openInDefaultBrowser_App (const iString *url); 96void openInDefaultBrowser_App (const iString *url);
95void revealPath_App (const iString *path); 97void revealPath_App (const iString *path);
diff --git a/src/history.c b/src/history.c
index 202549a9..59d515dc 100644
--- a/src/history.c
+++ b/src/history.c
@@ -27,6 +27,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
27#include <the_Foundation/mutex.h> 27#include <the_Foundation/mutex.h>
28#include <the_Foundation/path.h> 28#include <the_Foundation/path.h>
29#include <the_Foundation/stringset.h> 29#include <the_Foundation/stringset.h>
30#include <math.h>
30 31
31static const size_t maxStack_History_ = 50; /* back/forward navigable items */ 32static const size_t maxStack_History_ = 50; /* back/forward navigable items */
32 33
@@ -285,6 +286,48 @@ void setCachedResponse_History(iHistory *d, const iGmResponse *response) {
285 unlock_Mutex(d->mtx); 286 unlock_Mutex(d->mtx);
286} 287}
287 288
289size_t cacheSize_History(const iHistory *d) {
290 size_t cached = 0;
291 lock_Mutex(d->mtx);
292 iConstForEach(Array, i, &d->recent) {
293 const iRecentUrl *url = i.value;
294 if (url->cachedResponse) {
295 cached += size_Block(&url->cachedResponse->body);
296 }
297 }
298 unlock_Mutex(d->mtx);
299 return cached;
300}
301
302size_t pruneLeastImportant_History(iHistory *d) {
303 size_t delta = 0;
304 size_t chosen = iInvalidPos;
305 double score = 0.0f;
306 iTime now;
307 initCurrent_Time(&now);
308 lock_Mutex(d->mtx);
309 iConstForEach(Array, i, &d->recent) {
310 const iRecentUrl *url = i.value;
311 if (url->cachedResponse) {
312 const double urlScore =
313 size_Block(&url->cachedResponse->body) *
314 pow(secondsSince_Time(&now, &url->cachedResponse->when) / 60.0, 1.25);
315 if (urlScore > score) {
316 chosen = index_ArrayConstIterator(&i);
317 score = urlScore;
318 }
319 }
320 }
321 if (chosen != iInvalidPos) {
322 iRecentUrl *url = at_Array(&d->recent, chosen);
323 delta = size_Block(&url->cachedResponse->body);
324 delete_GmResponse(url->cachedResponse);
325 url->cachedResponse = NULL;
326 }
327 unlock_Mutex(d->mtx);
328 return delta;
329}
330
288const iStringArray *searchContents_History(const iHistory *d, const iRegExp *pattern) { 331const iStringArray *searchContents_History(const iHistory *d, const iRegExp *pattern) {
289 iStringArray *urls = iClob(new_StringArray()); 332 iStringArray *urls = iClob(new_StringArray());
290 lock_Mutex(d->mtx); 333 lock_Mutex(d->mtx);
diff --git a/src/history.h b/src/history.h
index 4c6507e3..7c2684f1 100644
--- a/src/history.h
+++ b/src/history.h
@@ -56,6 +56,7 @@ iBool goForward_History (iHistory *);
56iRecentUrl *recentUrl_History (iHistory *, size_t pos); 56iRecentUrl *recentUrl_History (iHistory *, size_t pos);
57iRecentUrl *mostRecentUrl_History (iHistory *); 57iRecentUrl *mostRecentUrl_History (iHistory *);
58iRecentUrl *findUrl_History (iHistory *, const iString *url); 58iRecentUrl *findUrl_History (iHistory *, const iString *url);
59size_t pruneLeastImportant_History (iHistory *);
59 60
60const iStringArray * searchContents_History (const iHistory *, const iRegExp *pattern); /* chronologically ascending */ 61const iStringArray * searchContents_History (const iHistory *, const iRegExp *pattern); /* chronologically ascending */
61 62
@@ -67,6 +68,7 @@ const iRecentUrl *
67 constMostRecentUrl_History (const iHistory *); 68 constMostRecentUrl_History (const iHistory *);
68const iGmResponse * 69const iGmResponse *
69 cachedResponse_History (const iHistory *); 70 cachedResponse_History (const iHistory *);
71size_t cacheSize_History (const iHistory *);
70 72
71iString * debugInfo_History (const iHistory *); 73iString * debugInfo_History (const iHistory *);
72 74
diff --git a/src/prefs.c b/src/prefs.c
index 188938a2..ce32962b 100644
--- a/src/prefs.c
+++ b/src/prefs.c
@@ -34,6 +34,7 @@ void init_Prefs(iPrefs *d) {
34 d->smoothScrolling = iTrue; 34 d->smoothScrolling = iTrue;
35 d->loadImageInsteadOfScrolling = iFalse; 35 d->loadImageInsteadOfScrolling = iFalse;
36 d->decodeUserVisibleURLs = iTrue; 36 d->decodeUserVisibleURLs = iTrue;
37 d->maxCacheSize = 10;
37 d->font = nunito_TextFont; 38 d->font = nunito_TextFont;
38 d->headingFont = nunito_TextFont; 39 d->headingFont = nunito_TextFont;
39 d->monospaceGemini = iFalse; 40 d->monospaceGemini = iFalse;
diff --git a/src/prefs.h b/src/prefs.h
index 07298eac..1c3274d9 100644
--- a/src/prefs.h
+++ b/src/prefs.h
@@ -49,6 +49,7 @@ struct Impl_Prefs {
49 iBool loadImageInsteadOfScrolling; 49 iBool loadImageInsteadOfScrolling;
50 /* Network */ 50 /* Network */
51 iBool decodeUserVisibleURLs; 51 iBool decodeUserVisibleURLs;
52 int maxCacheSize; /* MB */
52 iString geminiProxy; 53 iString geminiProxy;
53 iString gopherProxy; 54 iString gopherProxy;
54 iString httpProxy; 55 iString httpProxy;
diff --git a/src/ui/util.c b/src/ui/util.c
index 7fc27130..91945db8 100644
--- a/src/ui/util.c
+++ b/src/ui/util.c
@@ -1090,7 +1090,7 @@ iWidget *makePreferences_Widget(void) {
1090 } 1090 }
1091 /* Colors. */ { 1091 /* Colors. */ {
1092 appendTwoColumnPage_(tabs, "Colors", '3', &headings, &values); 1092 appendTwoColumnPage_(tabs, "Colors", '3', &headings, &values);
1093 makeTwoColumnHeading_("PAGE CONTENTS", headings, values); 1093 makeTwoColumnHeading_("PAGE CONTENT", headings, values);
1094 for (int i = 0; i < 2; ++i) { 1094 for (int i = 0; i < 2; ++i) {
1095 const iBool isDark = (i == 0); 1095 const iBool isDark = (i == 0);
1096 const char *mode = isDark ? "dark" : "light"; 1096 const char *mode = isDark ? "dark" : "light";
@@ -1121,6 +1121,7 @@ iWidget *makePreferences_Widget(void) {
1121 } 1121 }
1122 /* Layout. */ { 1122 /* Layout. */ {
1123 appendTwoColumnPage_(tabs, "Style", '4', &headings, &values); 1123 appendTwoColumnPage_(tabs, "Style", '4', &headings, &values);
1124 makeTwoColumnHeading_("FONTS", headings, values);
1124 /* Fonts. */ { 1125 /* Fonts. */ {
1125 iWidget *fonts; 1126 iWidget *fonts;
1126 addChild_Widget(headings, iClob(makeHeading_Widget("Heading font:"))); 1127 addChild_Widget(headings, iClob(makeHeading_Widget("Heading font:")));
@@ -1140,8 +1141,7 @@ iWidget *makePreferences_Widget(void) {
1140 addChild_Widget(mono, iClob(makeToggle_Widget("prefs.mono.gopher"))), "Gopher"); 1141 addChild_Widget(mono, iClob(makeToggle_Widget("prefs.mono.gopher"))), "Gopher");
1141 addChildFlags_Widget(values, iClob(mono), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag); 1142 addChildFlags_Widget(values, iClob(mono), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag);
1142 } 1143 }
1143 addChild_Widget(headings, iClob(makePadding_Widget(2 * gap_UI))); 1144 makeTwoColumnHeading_("PARAGRAPH", headings, values);
1144 addChild_Widget(values, iClob(makePadding_Widget(2 * gap_UI)));
1145 addChild_Widget(headings, iClob(makeHeading_Widget("Line width:"))); 1145 addChild_Widget(headings, iClob(makeHeading_Widget("Line width:")));
1146 iWidget *widths = new_Widget(); 1146 iWidget *widths = new_Widget();
1147 /* Line widths. */ { 1147 /* Line widths. */ {
@@ -1162,10 +1162,19 @@ iWidget *makePreferences_Widget(void) {
1162 addChild_Widget(headings, iClob(makeHeading_Widget("Big 1st paragaph:"))); 1162 addChild_Widget(headings, iClob(makeHeading_Widget("Big 1st paragaph:")));
1163 addChild_Widget(values, iClob(makeToggle_Widget("prefs.biglede"))); 1163 addChild_Widget(values, iClob(makeToggle_Widget("prefs.biglede")));
1164 } 1164 }
1165 /* Proxies. */ { 1165 /* Network. */ {
1166 appendTwoColumnPage_(tabs, "Network", '5', &headings, &values); 1166 appendTwoColumnPage_(tabs, "Network", '5', &headings, &values);
1167 addChild_Widget(headings, iClob(makeHeading_Widget("Decode paths:"))); 1167 addChild_Widget(headings, iClob(makeHeading_Widget("Cache size:")));
1168 iWidget *cacheGroup = new_Widget(); {
1169 iInputWidget *cache = new_InputWidget(4);
1170 setSelectAllOnFocus_InputWidget(cache, iTrue);
1171 setId_Widget(addChild_Widget(cacheGroup, iClob(cache)), "prefs.cachesize");
1172 addChildFlags_Widget(cacheGroup, iClob(new_LabelWidget("MB", NULL)), frameless_WidgetFlag);
1173 }
1174 addChildFlags_Widget(values, iClob(cacheGroup), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag);
1175 addChild_Widget(headings, iClob(makeHeading_Widget("Decode URLs:")));
1168 addChild_Widget(values, iClob(makeToggle_Widget("prefs.decodeurls"))); 1176 addChild_Widget(values, iClob(makeToggle_Widget("prefs.decodeurls")));
1177 makeTwoColumnHeading_("PROXIES", headings, values);
1169 addChild_Widget(headings, iClob(makeHeading_Widget("Gemini proxy:"))); 1178 addChild_Widget(headings, iClob(makeHeading_Widget("Gemini proxy:")));
1170 setId_Widget(addChild_Widget(values, iClob(new_InputWidget(0))), "prefs.proxy.gemini"); 1179 setId_Widget(addChild_Widget(values, iClob(new_InputWidget(0))), "prefs.proxy.gemini");
1171 addChild_Widget(headings, iClob(makeHeading_Widget("Gopher proxy:"))); 1180 addChild_Widget(headings, iClob(makeHeading_Widget("Gopher proxy:")));
diff --git a/src/ui/window.c b/src/ui/window.c
index 2e38512b..66994e79 100644
--- a/src/ui/window.c
+++ b/src/ui/window.c
@@ -397,6 +397,7 @@ static iBool handleNavBarCommands_(iWidget *navBar, const char *cmd) {
397 if (equal_Command(cmd, "document.changed")) { 397 if (equal_Command(cmd, "document.changed")) {
398 iInputWidget *url = findWidget_App("url"); 398 iInputWidget *url = findWidget_App("url");
399 const iString *urlStr = collect_String(suffix_Command(cmd, "url")); 399 const iString *urlStr = collect_String(suffix_Command(cmd, "url"));
400 trimCache_App();
400 visitUrl_Visited(visited_App(), urlStr, 0); 401 visitUrl_Visited(visited_App(), urlStr, 0);
401 postCommand_App("visited.changed"); /* sidebar will update */ 402 postCommand_App("visited.changed"); /* sidebar will update */
402 setText_InputWidget(url, urlStr); 403 setText_InputWidget(url, urlStr);