summaryrefslogtreecommitdiff
path: root/src/app.c
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-10-22 07:22:26 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-10-22 07:22:26 +0300
commitc752568f1cc5cee1d1957644a20482501b96c25c (patch)
tree33e2deacb98db8598ab118158fd1f494fb6adfbd /src/app.c
parentd14f9aebe27cd48a8d21c0eb691c8e7bf94722a8 (diff)
parentb8471251e785c0c41fdb396c1c55a5fe76363dc2 (diff)
Merge branch 'work/v1.8' into dev
Diffstat (limited to 'src/app.c')
-rw-r--r--src/app.c373
1 files changed, 278 insertions, 95 deletions
diff --git a/src/app.c b/src/app.c
index de3f5d74..ebb61c86 100644
--- a/src/app.c
+++ b/src/app.c
@@ -116,7 +116,7 @@ struct Impl_App {
116 iMimeHooks * mimehooks; 116 iMimeHooks * mimehooks;
117 iGmCerts * certs; 117 iGmCerts * certs;
118 iVisited * visited; 118 iVisited * visited;
119 iBookmarks * bookmarks; 119 iBookmarks * bookmarks;
120 iMainWindow *window; 120 iMainWindow *window;
121 iPtrArray popupWindows; 121 iPtrArray popupWindows;
122 iSortedArray tickers; /* per-frame callbacks, used for animations */ 122 iSortedArray tickers; /* per-frame callbacks, used for animations */
@@ -124,6 +124,7 @@ struct Impl_App {
124 uint32_t elapsedSinceLastTicker; 124 uint32_t elapsedSinceLastTicker;
125 iBool isRunning; 125 iBool isRunning;
126 iBool isRunningUnderWindowSystem; 126 iBool isRunningUnderWindowSystem;
127 iBool isDarkSystemTheme;
127#if defined (LAGRANGE_ENABLE_IDLE_SLEEP) 128#if defined (LAGRANGE_ENABLE_IDLE_SLEEP)
128 iBool isIdling; 129 iBool isIdling;
129 uint32_t lastEventTime; 130 uint32_t lastEventTime;
@@ -209,12 +210,16 @@ static iString *serializePrefs_App_(const iApp *d) {
209 } 210 }
210#endif 211#endif
211 } 212 }
212 appendFormat_String(str, "uilang id:%s\n", cstr_String(&d->prefs.uiLanguage)); 213 appendFormat_String(str, "uilang id:%s\n", cstr_String(&d->prefs.strings[uiLanguage_PrefsString]));
213 appendFormat_String(str, "uiscale arg:%f\n", uiScale_Window(as_Window(d->window))); 214 appendFormat_String(str, "uiscale arg:%f\n", uiScale_Window(as_Window(d->window)));
214 appendFormat_String(str, "prefs.dialogtab arg:%d\n", d->prefs.dialogTab); 215 appendFormat_String(str, "prefs.dialogtab arg:%d\n", d->prefs.dialogTab);
215 appendFormat_String(str, "font.set arg:%d\n", d->prefs.font); 216 appendFormat_String(str,
216 appendFormat_String(str, "font.user path:%s\n", cstr_String(&d->prefs.symbolFontPath)); 217 "font.set ui:%s heading:%s body:%s mono:%s monodoc:%s\n",
217 appendFormat_String(str, "headingfont.set arg:%d\n", d->prefs.headingFont); 218 cstr_String(&d->prefs.strings[uiFont_PrefsString]),
219 cstr_String(&d->prefs.strings[headingFont_PrefsString]),
220 cstr_String(&d->prefs.strings[bodyFont_PrefsString]),
221 cstr_String(&d->prefs.strings[monospaceFont_PrefsString]),
222 cstr_String(&d->prefs.strings[monospaceDocumentFont_PrefsString]));
218 appendFormat_String(str, "zoom.set arg:%d\n", d->prefs.zoomPercent); 223 appendFormat_String(str, "zoom.set arg:%d\n", d->prefs.zoomPercent);
219 appendFormat_String(str, "smoothscroll arg:%d\n", d->prefs.smoothScrolling); 224 appendFormat_String(str, "smoothscroll arg:%d\n", d->prefs.smoothScrolling);
220 appendFormat_String(str, "scrollspeed arg:%d type:%d\n", d->prefs.smoothScrollSpeed[keyboard_ScrollType], keyboard_ScrollType); 225 appendFormat_String(str, "scrollspeed arg:%d type:%d\n", d->prefs.smoothScrollSpeed[keyboard_ScrollType], keyboard_ScrollType);
@@ -226,37 +231,54 @@ static iString *serializePrefs_App_(const iApp *d) {
226 appendFormat_String(str, "linewidth.set arg:%d\n", d->prefs.lineWidth); 231 appendFormat_String(str, "linewidth.set arg:%d\n", d->prefs.lineWidth);
227 appendFormat_String(str, "linespacing.set arg:%f\n", d->prefs.lineSpacing); 232 appendFormat_String(str, "linespacing.set arg:%f\n", d->prefs.lineSpacing);
228 appendFormat_String(str, "returnkey.set arg:%d\n", d->prefs.returnKey); 233 appendFormat_String(str, "returnkey.set arg:%d\n", d->prefs.returnKey);
229 /* TODO: Set up an array of booleans in Prefs and do these in a loop. */ 234 iConstForEach(StringSet, fp, d->prefs.disabledFontPacks) {
230 appendFormat_String(str, "prefs.animate.changed arg:%d\n", d->prefs.uiAnimations); 235 appendFormat_String(str, "fontpack.disable id:%s\n", cstr_String(fp.value));
231 appendFormat_String(str, "prefs.mono.gemini.changed arg:%d\n", d->prefs.monospaceGemini); 236 }
232 appendFormat_String(str, "prefs.mono.gopher.changed arg:%d\n", d->prefs.monospaceGopher); 237 appendFormat_String(str, "ansiescape arg:%d\n", d->prefs.gemtextAnsiEscapes);
233 appendFormat_String(str, "prefs.boldlink.dark.changed arg:%d\n", d->prefs.boldLinkDark); 238 /* TODO: This array belongs in Prefs. It can then be used for command handling as well. */
234 appendFormat_String(str, "prefs.boldlink.light.changed arg:%d\n", d->prefs.boldLinkLight); 239 const struct {
235 appendFormat_String(str, "prefs.biglede.changed arg:%d\n", d->prefs.bigFirstParagraph); 240 const char * id;
236 appendFormat_String(str, "prefs.plaintext.wrap.changed arg:%d\n", d->prefs.plainTextWrap); 241 const iBool *value;
237 appendFormat_String(str, "prefs.sideicon.changed arg:%d\n", d->prefs.sideIcon); 242 } boolPrefs[] = {
238 appendFormat_String(str, "prefs.centershort.changed arg:%d\n", d->prefs.centerShortDocs); 243 { "prefs.animate", &d->prefs.uiAnimations },
239 appendFormat_String(str, "prefs.collapsepreonload.changed arg:%d\n", d->prefs.collapsePreOnLoad); 244 { "prefs.font.smooth", &d->prefs.fontSmoothing },
240 appendFormat_String(str, "prefs.hoverlink.changed arg:%d\n", d->prefs.hoverLink); 245 { "prefs.mono.gemini", &d->prefs.monospaceGemini },
241 appendFormat_String(str, "prefs.bookmarks.addbottom.changed arg:%d\n", d->prefs.addBookmarksToBottom); 246 { "prefs.mono.gopher", &d->prefs.monospaceGopher },
242 appendFormat_String(str, "prefs.archive.openindex.changed arg:%d\n", d->prefs.openArchiveIndexPages); 247 { "prefs.boldlink.visited", &d->prefs.boldLinkVisited },
248 { "prefs.boldlink.dark", &d->prefs.boldLinkDark },
249 { "prefs.boldlink.light", &d->prefs.boldLinkLight },
250 { "prefs.biglede", &d->prefs.bigFirstParagraph },
251 { "prefs.plaintext.wrap", &d->prefs.plainTextWrap },
252 { "prefs.sideicon", &d->prefs.sideIcon },
253 { "prefs.centershort", &d->prefs.centerShortDocs },
254 { "prefs.collapsepreonload", &d->prefs.collapsePreOnLoad },
255 { "prefs.hoverlink", &d->prefs.hoverLink },
256 { "prefs.bookmarks.addbottom", &d->prefs.addBookmarksToBottom },
257 { "prefs.archive.openindex", &d->prefs.openArchiveIndexPages },
258 };
259 iForIndices(i, boolPrefs) {
260 appendFormat_String(str, "%s.changed arg:%d\n", boolPrefs[i].id, *boolPrefs[i].value);
261 }
243 appendFormat_String(str, "quoteicon.set arg:%d\n", d->prefs.quoteIcon ? 1 : 0); 262 appendFormat_String(str, "quoteicon.set arg:%d\n", d->prefs.quoteIcon ? 1 : 0);
244 appendFormat_String(str, "theme.set arg:%d auto:1\n", d->prefs.theme); 263 appendFormat_String(str, "theme.set arg:%d auto:1\n", d->prefs.theme);
245 appendFormat_String(str, "accent.set arg:%d\n", d->prefs.accent); 264 appendFormat_String(str, "accent.set arg:%d\n", d->prefs.accent);
246 appendFormat_String(str, "ostheme arg:%d\n", d->prefs.useSystemTheme); 265 appendFormat_String(str, "ostheme arg:%d preferdark:%d preferlight:%d\n",
266 d->prefs.useSystemTheme,
267 d->prefs.systemPreferredColorTheme[0],
268 d->prefs.systemPreferredColorTheme[1]);
247 appendFormat_String(str, "doctheme.dark.set arg:%d\n", d->prefs.docThemeDark); 269 appendFormat_String(str, "doctheme.dark.set arg:%d\n", d->prefs.docThemeDark);
248 appendFormat_String(str, "doctheme.light.set arg:%d\n", d->prefs.docThemeLight); 270 appendFormat_String(str, "doctheme.light.set arg:%d\n", d->prefs.docThemeLight);
249 appendFormat_String(str, "saturation.set arg:%d\n", (int) ((d->prefs.saturation * 100) + 0.5f)); 271 appendFormat_String(str, "saturation.set arg:%d\n", (int) ((d->prefs.saturation * 100) + 0.5f));
250 appendFormat_String(str, "imagestyle.set arg:%d\n", d->prefs.imageStyle); 272 appendFormat_String(str, "imagestyle.set arg:%d\n", d->prefs.imageStyle);
251 appendFormat_String(str, "ca.file noset:1 path:%s\n", cstr_String(&d->prefs.caFile)); 273 appendFormat_String(str, "ca.file noset:1 path:%s\n", cstr_String(&d->prefs.strings[caFile_PrefsString]));
252 appendFormat_String(str, "ca.path path:%s\n", cstr_String(&d->prefs.caPath)); 274 appendFormat_String(str, "ca.path path:%s\n", cstr_String(&d->prefs.strings[caPath_PrefsString]));
253 appendFormat_String(str, "proxy.gemini address:%s\n", cstr_String(&d->prefs.geminiProxy)); 275 appendFormat_String(str, "proxy.gemini address:%s\n", cstr_String(&d->prefs.strings[geminiProxy_PrefsString]));
254 appendFormat_String(str, "proxy.gopher address:%s\n", cstr_String(&d->prefs.gopherProxy)); 276 appendFormat_String(str, "proxy.gopher address:%s\n", cstr_String(&d->prefs.strings[gopherProxy_PrefsString]));
255 appendFormat_String(str, "proxy.http address:%s\n", cstr_String(&d->prefs.httpProxy)); 277 appendFormat_String(str, "proxy.http address:%s\n", cstr_String(&d->prefs.strings[httpProxy_PrefsString]));
256#if defined (LAGRANGE_ENABLE_DOWNLOAD_EDIT) 278#if defined (LAGRANGE_ENABLE_DOWNLOAD_EDIT)
257 appendFormat_String(str, "downloads path:%s\n", cstr_String(&d->prefs.downloadDir)); 279 appendFormat_String(str, "downloads path:%s\n", cstr_String(&d->prefs.strings[downloadDir_PrefsString]));
258#endif 280#endif
259 appendFormat_String(str, "searchurl address:%s\n", cstr_String(&d->prefs.searchUrl)); 281 appendFormat_String(str, "searchurl address:%s\n", cstr_String(&d->prefs.strings[searchUrl_PrefsString]));
260 appendFormat_String(str, "translation.languages from:%d to:%d\n", d->prefs.langFrom, d->prefs.langTo); 282 appendFormat_String(str, "translation.languages from:%d to:%d\n", d->prefs.langFrom, d->prefs.langTo);
261 return str; 283 return str;
262} 284}
@@ -330,7 +352,7 @@ static void loadPrefs_App_(iApp *d) {
330 } 352 }
331 else if (equal_Command(cmd, "uilang")) { 353 else if (equal_Command(cmd, "uilang")) {
332 const char *id = cstr_Rangecc(range_Command(cmd, "id")); 354 const char *id = cstr_Rangecc(range_Command(cmd, "id"));
333 setCStr_String(&d->prefs.uiLanguage, id); 355 setCStr_String(&d->prefs.strings[uiLanguage_PrefsString], id);
334 setCurrent_Lang(id); 356 setCurrent_Lang(id);
335 } 357 }
336 else if (equal_Command(cmd, "ca.file") || equal_Command(cmd, "ca.path")) { 358 else if (equal_Command(cmd, "ca.file") || equal_Command(cmd, "ca.path")) {
@@ -347,6 +369,10 @@ static void loadPrefs_App_(iApp *d) {
347 d->initialWindowRect = init_Rect( 369 d->initialWindowRect = init_Rect(
348 pos.x, pos.y, argLabel_Command(cmd, "width"), argLabel_Command(cmd, "height")); 370 pos.x, pos.y, argLabel_Command(cmd, "width"), argLabel_Command(cmd, "height"));
349 } 371 }
372 else if (equal_Command(cmd, "fontpack.disable")) {
373 insert_StringSet(d->prefs.disabledFontPacks,
374 collect_String(suffix_Command(cmd, "id")));
375 }
350#if !defined (LAGRANGE_ENABLE_DOWNLOAD_EDIT) 376#if !defined (LAGRANGE_ENABLE_DOWNLOAD_EDIT)
351 else if (equal_Command(cmd, "downloads")) { 377 else if (equal_Command(cmd, "downloads")) {
352 continue; /* can't change downloads directory */ 378 continue; /* can't change downloads directory */
@@ -361,7 +387,8 @@ static void loadPrefs_App_(iApp *d) {
361 } 387 }
362 if (!haveCA) { 388 if (!haveCA) {
363 /* Default CA setup. */ 389 /* Default CA setup. */
364 setCACertificates_TlsRequest(&d->prefs.caFile, &d->prefs.caPath); 390 setCACertificates_TlsRequest(&d->prefs.strings[caFile_PrefsString],
391 &d->prefs.strings[caPath_PrefsString]);
365 } 392 }
366#if !defined (LAGRANGE_ENABLE_CUSTOM_FRAME) 393#if !defined (LAGRANGE_ENABLE_CUSTOM_FRAME)
367 d->prefs.customFrame = iFalse; 394 d->prefs.customFrame = iFalse;
@@ -653,6 +680,7 @@ static void init_App_(iApp *d, int argc, char **argv) {
653#else 680#else
654 d->isRunningUnderWindowSystem = iTrue; 681 d->isRunningUnderWindowSystem = iTrue;
655#endif 682#endif
683 d->isDarkSystemTheme = iTrue; /* will be updated by system later on, if supported */
656 init_CommandLine(&d->args, argc, argv); 684 init_CommandLine(&d->args, argc, argv);
657 /* Where was the app started from? We ask SDL first because the command line alone is 685 /* Where was the app started from? We ask SDL first because the command line alone is
658 not a reliable source of this information, particularly when it comes to different 686 not a reliable source of this information, particularly when it comes to different
@@ -759,7 +787,7 @@ static void init_App_(iApp *d, int argc, char **argv) {
759 listen_Ipc(); /* We'll respond to commands from other instances. */ 787 listen_Ipc(); /* We'll respond to commands from other instances. */
760 } 788 }
761#endif 789#endif
762 printf("Lagrange: A Beautiful Gemini Client\n"); 790 puts("Lagrange: A Beautiful Gemini Client");
763 const iBool isFirstRun = 791 const iBool isFirstRun =
764 !fileExistsCStr_FileInfo(cleanedPath_CStr(concatPath_CStr(dataDir_App_(), "prefs.cfg"))); 792 !fileExistsCStr_FileInfo(cleanedPath_CStr(concatPath_CStr(dataDir_App_(), "prefs.cfg")));
765 d->isFinishedLaunching = iFalse; 793 d->isFinishedLaunching = iFalse;
@@ -788,7 +816,7 @@ static void init_App_(iApp *d, int argc, char **argv) {
788#endif 816#endif
789 init_Prefs(&d->prefs); 817 init_Prefs(&d->prefs);
790 init_SiteSpec(dataDir_App_()); 818 init_SiteSpec(dataDir_App_());
791 setCStr_String(&d->prefs.downloadDir, downloadDir_App_()); 819 setCStr_String(&d->prefs.strings[downloadDir_PrefsString], downloadDir_App_());
792 set_Atomic(&d->pendingRefresh, iFalse); 820 set_Atomic(&d->pendingRefresh, iFalse);
793 d->isRunning = iFalse; 821 d->isRunning = iFalse;
794 d->window = NULL; 822 d->window = NULL;
@@ -804,9 +832,11 @@ static void init_App_(iApp *d, int argc, char **argv) {
804 setupApplication_iOS(); 832 setupApplication_iOS();
805#endif 833#endif
806 init_Keys(); 834 init_Keys();
835 init_Fonts(dataDir_App_());
807 loadPalette_Color(dataDir_App_()); 836 loadPalette_Color(dataDir_App_());
808 setThemePalette_Color(d->prefs.theme); /* default UI colors */ 837 setThemePalette_Color(d->prefs.theme); /* default UI colors */
809 loadPrefs_App_(d); 838 loadPrefs_App_(d);
839 updateActive_Fonts();
810 load_Keys(dataDir_App_()); 840 load_Keys(dataDir_App_());
811 /* See if the user wants to override the window size. */ { 841 /* See if the user wants to override the window size. */ {
812 iCommandLineArg *arg = iClob(checkArgument_CommandLine(&d->args, windowWidth_CommandLineOption)); 842 iCommandLineArg *arg = iClob(checkArgument_CommandLine(&d->args, windowWidth_CommandLineOption));
@@ -881,11 +911,14 @@ static void deinit_App(iApp *d) {
881#endif 911#endif
882 SDL_RemoveTimer(d->autoReloadTimer); 912 SDL_RemoveTimer(d->autoReloadTimer);
883 saveState_App_(d); 913 saveState_App_(d);
914 savePrefs_App_(d);
915 delete_MainWindow(d->window);
916 d->window = NULL;
884 deinit_Feeds(); 917 deinit_Feeds();
885 save_Keys(dataDir_App_()); 918 save_Keys(dataDir_App_());
886 deinit_Keys(); 919 deinit_Keys();
920 deinit_Fonts();
887 deinit_SiteSpec(); 921 deinit_SiteSpec();
888 savePrefs_App_(d);
889 deinit_Prefs(&d->prefs); 922 deinit_Prefs(&d->prefs);
890 save_Bookmarks(d->bookmarks, dataDir_App_()); 923 save_Bookmarks(d->bookmarks, dataDir_App_());
891 delete_Bookmarks(d->bookmarks); 924 delete_Bookmarks(d->bookmarks);
@@ -894,7 +927,6 @@ static void deinit_App(iApp *d) {
894 delete_GmCerts(d->certs); 927 delete_GmCerts(d->certs);
895 save_MimeHooks(d->mimehooks); 928 save_MimeHooks(d->mimehooks);
896 delete_MimeHooks(d->mimehooks); 929 delete_MimeHooks(d->mimehooks);
897 delete_MainWindow(d->window);
898 d->window = NULL; 930 d->window = NULL;
899 deinit_CommandLine(&d->args); 931 deinit_CommandLine(&d->args);
900 iRelease(d->launchCommands); 932 iRelease(d->launchCommands);
@@ -917,7 +949,7 @@ const iString *dataDir_App(void) {
917} 949}
918 950
919const iString *downloadDir_App(void) { 951const iString *downloadDir_App(void) {
920 return collect_String(cleaned_Path(&app_.prefs.downloadDir)); 952 return collect_String(cleaned_Path(&app_.prefs.strings[downloadDir_PrefsString]));
921} 953}
922 954
923const iString *downloadPathForUrl_App(const iString *url, const iString *mime) { 955const iString *downloadPathForUrl_App(const iString *url, const iString *mime) {
@@ -1080,6 +1112,20 @@ void trimMemory_App(void) {
1080 iRelease(docs); 1112 iRelease(docs);
1081} 1113}
1082 1114
1115#if 0
1116iBool findCachedContent_App(const iString *url, iString *mime_out, iBlock *data_out) {
1117 /* Cached content can be found in MediaRequests of DocumentWidgets (loaded on the currently
1118 open page) and the DocumentWidget itself. `Media` doesn't store source data, only
1119 presentation data. */
1120 iConstForEach(ObjectList, i, iClob(listDocuments_App(NULL))) {
1121 if (findCachedContent_DocumentWidget(i.object, url, mime_out, data_out)) {
1122 return iTrue;
1123 }
1124 }
1125 return iFalse;
1126}
1127#endif
1128
1083iLocalDef iBool isWaitingAllowed_App_(iApp *d) { 1129iLocalDef iBool isWaitingAllowed_App_(iApp *d) {
1084 if (!isEmpty_Periodic(&d->periodic)) { 1130 if (!isEmpty_Periodic(&d->periodic)) {
1085 return iFalse; 1131 return iFalse;
@@ -1516,13 +1562,13 @@ const iString *schemeProxy_App(iRangecc scheme) {
1516 iApp *d = &app_; 1562 iApp *d = &app_;
1517 const iString *proxy = NULL; 1563 const iString *proxy = NULL;
1518 if (equalCase_Rangecc(scheme, "gemini")) { 1564 if (equalCase_Rangecc(scheme, "gemini")) {
1519 proxy = &d->prefs.geminiProxy; 1565 proxy = &d->prefs.strings[geminiProxy_PrefsString];
1520 } 1566 }
1521 else if (equalCase_Rangecc(scheme, "gopher")) { 1567 else if (equalCase_Rangecc(scheme, "gopher")) {
1522 proxy = &d->prefs.gopherProxy; 1568 proxy = &d->prefs.strings[gopherProxy_PrefsString];
1523 } 1569 }
1524 else if (equalCase_Rangecc(scheme, "http") || equalCase_Rangecc(scheme, "https")) { 1570 else if (equalCase_Rangecc(scheme, "http") || equalCase_Rangecc(scheme, "https")) {
1525 proxy = &d->prefs.httpProxy; 1571 proxy = &d->prefs.strings[httpProxy_PrefsString];
1526 } 1572 }
1527 return isEmpty_String(proxy) ? NULL : proxy; 1573 return isEmpty_String(proxy) ? NULL : proxy;
1528} 1574}
@@ -1726,9 +1772,9 @@ static void updateColorThemeButton_(iLabelWidget *button, int theme) {
1726 updateDropdownSelection_LabelWidget(button, format_CStr(".set arg:%d", theme)); 1772 updateDropdownSelection_LabelWidget(button, format_CStr(".set arg:%d", theme));
1727} 1773}
1728 1774
1729static void updateFontButton_(iLabelWidget *button, int font) { 1775static void updateFontButton_(iLabelWidget *button, const iString *fontId) {
1730 if (!button) return; 1776 if (!button || isEmpty_String(fontId)) return;
1731 updateDropdownSelection_LabelWidget(button, format_CStr(".set arg:%d", font)); 1777 updateDropdownSelection_LabelWidget(button, format_CStr(":%s", cstr_String(fontId)));
1732} 1778}
1733 1779
1734static void updateImageStyleButton_(iLabelWidget *button, int style) { 1780static void updateImageStyleButton_(iLabelWidget *button, int style) {
@@ -1822,11 +1868,11 @@ static iBool handlePrefsCommands_(iWidget *d, const char *cmd) {
1822 return iFalse; 1868 return iFalse;
1823 } 1869 }
1824 else if (equal_Command(cmd, "font.set")) { 1870 else if (equal_Command(cmd, "font.set")) {
1825 updateFontButton_(findChild_Widget(d, "prefs.font"), arg_Command(cmd)); 1871 updateFontButton_(findChild_Widget(d, "prefs.font.ui"), string_Command(cmd, "ui"));
1826 return iFalse; 1872 updateFontButton_(findChild_Widget(d, "prefs.font.heading"), string_Command(cmd, "heading"));
1827 } 1873 updateFontButton_(findChild_Widget(d, "prefs.font.body"), string_Command(cmd, "body"));
1828 else if (equal_Command(cmd, "headingfont.set")) { 1874 updateFontButton_(findChild_Widget(d, "prefs.font.mono"), string_Command(cmd, "mono"));
1829 updateFontButton_(findChild_Widget(d, "prefs.headingfont"), arg_Command(cmd)); 1875 updateFontButton_(findChild_Widget(d, "prefs.font.monodoc"), string_Command(cmd, "monodoc"));
1830 return iFalse; 1876 return iFalse;
1831 } 1877 }
1832 else if (startsWith_CStr(cmd, "input.ended id:prefs.linespacing")) { 1878 else if (startsWith_CStr(cmd, "input.ended id:prefs.linespacing")) {
@@ -1841,7 +1887,7 @@ static iBool handlePrefsCommands_(iWidget *d, const char *cmd) {
1841 else if (equal_Command(cmd, "theme.changed")) { 1887 else if (equal_Command(cmd, "theme.changed")) {
1842 updatePrefsThemeButtons_(d); 1888 updatePrefsThemeButtons_(d);
1843 if (!argLabel_Command(cmd, "auto")) { 1889 if (!argLabel_Command(cmd, "auto")) {
1844 setToggle_Widget(findChild_Widget(d, "prefs.ostheme"), iFalse); 1890 setToggle_Widget(findChild_Widget(d, "prefs.ostheme"), prefs_App()->useSystemTheme);
1845 } 1891 }
1846 } 1892 }
1847 else if (equalWidget_Command(cmd, d, "input.resized")) { 1893 else if (equalWidget_Command(cmd, d, "input.resized")) {
@@ -2040,14 +2086,16 @@ iBool willUseProxy_App(const iRangecc scheme) {
2040 2086
2041const iString *searchQueryUrl_App(const iString *queryStringUnescaped) { 2087const iString *searchQueryUrl_App(const iString *queryStringUnescaped) {
2042 iApp *d = &app_; 2088 iApp *d = &app_;
2043 if (isEmpty_String(&d->prefs.searchUrl)) { 2089 if (isEmpty_String(&d->prefs.strings[searchUrl_PrefsString])) {
2044 return collectNew_String(); 2090 return collectNew_String();
2045 } 2091 }
2046 const iString *escaped = urlEncode_String(queryStringUnescaped); 2092 const iString *escaped = urlEncode_String(queryStringUnescaped);
2047 return collectNewFormat_String("%s?%s", cstr_String(&d->prefs.searchUrl), cstr_String(escaped)); 2093 return collectNewFormat_String(
2094 "%s?%s", cstr_String(&d->prefs.strings[searchUrl_PrefsString]), cstr_String(escaped));
2048} 2095}
2049 2096
2050static void resetFonts_App_(iApp *d) { 2097void resetFonts_App(void) {
2098 iApp *d = &app_;
2051 iConstForEach(PtrArray, win, listWindows_App_(d)) { 2099 iConstForEach(PtrArray, win, listWindows_App_(d)) {
2052 resetFonts_Text(text_Window(win.ptr)); 2100 resetFonts_Text(text_Window(win.ptr));
2053 } 2101 }
@@ -2074,9 +2122,10 @@ iBool handleCommand_App(const char *cmd) {
2074 } 2122 }
2075 else if (equal_Command(cmd, "uilang")) { 2123 else if (equal_Command(cmd, "uilang")) {
2076 const iString *lang = string_Command(cmd, "id"); 2124 const iString *lang = string_Command(cmd, "id");
2077 if (!equal_String(lang, &d->prefs.uiLanguage)) { 2125 iString *val = &d->prefs.strings[uiLanguage_PrefsString];
2078 set_String(&d->prefs.uiLanguage, lang); 2126 if (!equal_String(lang, val)) {
2079 setCurrent_Lang(cstr_String(&d->prefs.uiLanguage)); 2127 set_String(val, lang);
2128 setCurrent_Lang(cstr_String(val));
2080 postCommand_App("lang.changed"); 2129 postCommand_App("lang.changed");
2081 } 2130 }
2082 return iTrue; 2131 return iTrue;
@@ -2123,9 +2172,14 @@ iBool handleCommand_App(const char *cmd) {
2123 return iTrue; 2172 return iTrue;
2124 } 2173 }
2125 else if (equal_Command(cmd, "font.reset")) { 2174 else if (equal_Command(cmd, "font.reset")) {
2126 resetFonts_App_(d); 2175 resetFonts_App();
2176 return iTrue;
2177 }
2178 else if (equal_Command(cmd, "font.reload")) {
2179 reload_Fonts(); /* also does font cache reset, window invalidation */
2127 return iTrue; 2180 return iTrue;
2128 } 2181 }
2182#if 0
2129 else if (equal_Command(cmd, "font.user")) { 2183 else if (equal_Command(cmd, "font.user")) {
2130 const char *path = suffixPtr_Command(cmd, "path"); 2184 const char *path = suffixPtr_Command(cmd, "path");
2131 if (cmp_String(&d->prefs.symbolFontPath, path)) { 2185 if (cmp_String(&d->prefs.symbolFontPath, path)) {
@@ -2134,7 +2188,7 @@ iBool handleCommand_App(const char *cmd) {
2134 } 2188 }
2135 setCStr_String(&d->prefs.symbolFontPath, path); 2189 setCStr_String(&d->prefs.symbolFontPath, path);
2136 loadUserFonts_Text(); 2190 loadUserFonts_Text();
2137 resetFonts_App_(d); 2191 resetFonts_App(d);
2138 if (!isFrozen) { 2192 if (!isFrozen) {
2139 postCommand_App("font.changed"); 2193 postCommand_App("font.changed");
2140 postCommand_App("window.unfreeze"); 2194 postCommand_App("window.unfreeze");
@@ -2142,18 +2196,43 @@ iBool handleCommand_App(const char *cmd) {
2142 } 2196 }
2143 return iTrue; 2197 return iTrue;
2144 } 2198 }
2199#endif
2145 else if (equal_Command(cmd, "font.set")) { 2200 else if (equal_Command(cmd, "font.set")) {
2146 if (!isFrozen) { 2201 if (!isFrozen) {
2147 setFreezeDraw_MainWindow(get_MainWindow(), iTrue); 2202 setFreezeDraw_MainWindow(get_MainWindow(), iTrue);
2148 } 2203 }
2149 d->prefs.font = arg_Command(cmd); 2204 struct {
2150 setContentFont_Text(text_Window(d->window), d->prefs.font); 2205 const char *label;
2206 enum iPrefsString ps;
2207 int fontId;
2208 } params[] = {
2209 { "ui", uiFont_PrefsString, default_FontId },
2210 { "mono", monospaceFont_PrefsString, monospace_FontId },
2211 { "heading", headingFont_PrefsString, documentHeading_FontId },
2212 { "body", bodyFont_PrefsString, documentBody_FontId },
2213 { "monodoc", monospaceDocumentFont_PrefsString, documentMonospace_FontId },
2214 };
2215 iBool wasChanged = iFalse;
2216 iForIndices(i, params) {
2217 if (hasLabel_Command(cmd, params[i].label)) {
2218 iString *ps = &d->prefs.strings[params[i].ps];
2219 const iString *newFont = string_Command(cmd, params[i].label);
2220 if (!equal_String(ps, newFont)) {
2221 set_String(ps, newFont);
2222 wasChanged = iTrue;
2223 }
2224 }
2225 }
2226 if (wasChanged) {
2227 resetFonts_Text(text_Window(get_MainWindow()));
2228 }
2151 if (!isFrozen) { 2229 if (!isFrozen) {
2152 postCommand_App("font.changed"); 2230 postCommand_App("font.changed");
2153 postCommand_App("window.unfreeze"); 2231 postCommand_App("window.unfreeze");
2154 } 2232 }
2155 return iTrue; 2233 return iTrue;
2156 } 2234 }
2235#if 0
2157 else if (equal_Command(cmd, "headingfont.set")) { 2236 else if (equal_Command(cmd, "headingfont.set")) {
2158 if (!isFrozen) { 2237 if (!isFrozen) {
2159 setFreezeDraw_MainWindow(get_MainWindow(), iTrue); 2238 setFreezeDraw_MainWindow(get_MainWindow(), iTrue);
@@ -2166,12 +2245,13 @@ iBool handleCommand_App(const char *cmd) {
2166 } 2245 }
2167 return iTrue; 2246 return iTrue;
2168 } 2247 }
2248#endif
2169 else if (equal_Command(cmd, "zoom.set")) { 2249 else if (equal_Command(cmd, "zoom.set")) {
2170 if (!isFrozen) { 2250 if (!isFrozen) {
2171 setFreezeDraw_MainWindow(get_MainWindow(), iTrue); /* no intermediate draws before docs updated */ 2251 setFreezeDraw_MainWindow(get_MainWindow(), iTrue); /* no intermediate draws before docs updated */
2172 } 2252 }
2173 d->prefs.zoomPercent = arg_Command(cmd); 2253 d->prefs.zoomPercent = arg_Command(cmd);
2174 setContentFontSize_Text(text_Window(d->window), (float) d->prefs.zoomPercent / 100.0f); 2254 setDocumentFontSize_Text(text_Window(d->window), (float) d->prefs.zoomPercent / 100.0f);
2175 if (!isFrozen) { 2255 if (!isFrozen) {
2176 postCommand_App("font.changed"); 2256 postCommand_App("font.changed");
2177 postCommand_App("window.unfreeze"); 2257 postCommand_App("window.unfreeze");
@@ -2187,7 +2267,7 @@ iBool handleCommand_App(const char *cmd) {
2187 delta /= 2; 2267 delta /= 2;
2188 } 2268 }
2189 d->prefs.zoomPercent = iClamp(d->prefs.zoomPercent + delta, 50, 200); 2269 d->prefs.zoomPercent = iClamp(d->prefs.zoomPercent + delta, 50, 200);
2190 setContentFontSize_Text(text_Window(d->window), (float) d->prefs.zoomPercent / 100.0f); 2270 setDocumentFontSize_Text(text_Window(d->window), (float) d->prefs.zoomPercent / 100.0f);
2191 if (!isFrozen) { 2271 if (!isFrozen) {
2192 postCommand_App("font.changed"); 2272 postCommand_App("font.changed");
2193 postCommand_App("window.unfreeze"); 2273 postCommand_App("window.unfreeze");
@@ -2232,7 +2312,15 @@ iBool handleCommand_App(const char *cmd) {
2232 const int isAuto = argLabel_Command(cmd, "auto"); 2312 const int isAuto = argLabel_Command(cmd, "auto");
2233 d->prefs.theme = arg_Command(cmd); 2313 d->prefs.theme = arg_Command(cmd);
2234 if (!isAuto) { 2314 if (!isAuto) {
2235 postCommand_App("ostheme arg:0"); 2315 if (isDark_ColorTheme(d->prefs.theme) && d->isDarkSystemTheme) {
2316 d->prefs.systemPreferredColorTheme[0] = d->prefs.theme;
2317 }
2318 else if (!isDark_ColorTheme(d->prefs.theme) && !d->isDarkSystemTheme) {
2319 d->prefs.systemPreferredColorTheme[1] = d->prefs.theme;
2320 }
2321 else {
2322 postCommand_App("ostheme arg:0");
2323 }
2236 } 2324 }
2237 setThemePalette_Color(d->prefs.theme); 2325 setThemePalette_Color(d->prefs.theme);
2238 postCommandf_App("theme.changed auto:%d", isAuto); 2326 postCommandf_App("theme.changed auto:%d", isAuto);
@@ -2248,6 +2336,12 @@ iBool handleCommand_App(const char *cmd) {
2248 } 2336 }
2249 else if (equal_Command(cmd, "ostheme")) { 2337 else if (equal_Command(cmd, "ostheme")) {
2250 d->prefs.useSystemTheme = arg_Command(cmd); 2338 d->prefs.useSystemTheme = arg_Command(cmd);
2339 if (hasLabel_Command(cmd, "preferdark")) {
2340 d->prefs.systemPreferredColorTheme[0] = argLabel_Command(cmd, "preferdark");
2341 }
2342 if (hasLabel_Command(cmd, "preferlight")) {
2343 d->prefs.systemPreferredColorTheme[1] = argLabel_Command(cmd, "preferlight");
2344 }
2251 return iTrue; 2345 return iTrue;
2252 } 2346 }
2253 else if (equal_Command(cmd, "doctheme.dark.set")) { 2347 else if (equal_Command(cmd, "doctheme.dark.set")) {
@@ -2280,7 +2374,31 @@ iBool handleCommand_App(const char *cmd) {
2280 } 2374 }
2281 else if (equal_Command(cmd, "quoteicon.set")) { 2375 else if (equal_Command(cmd, "quoteicon.set")) {
2282 d->prefs.quoteIcon = arg_Command(cmd) != 0; 2376 d->prefs.quoteIcon = arg_Command(cmd) != 0;
2283 postCommand_App("document.layout.changed"); 2377 postCommand_App("document.layout.changed redo:1");
2378 return iTrue;
2379 }
2380 else if (equal_Command(cmd, "prefs.font.smooth.changed")) {
2381 if (!isFrozen) {
2382 setFreezeDraw_MainWindow(get_MainWindow(), iTrue);
2383 }
2384 d->prefs.fontSmoothing = arg_Command(cmd) != 0;
2385 if (!isFrozen) {
2386 resetFonts_Text(text_Window(get_MainWindow())); /* clear the glyph cache */
2387 postCommand_App("font.changed");
2388 postCommand_App("window.unfreeze");
2389 }
2390 return iTrue;
2391 }
2392 else if (equal_Command(cmd, "ansiescape")) {
2393 d->prefs.gemtextAnsiEscapes = arg_Command(cmd);
2394 return iTrue;
2395 }
2396 else if (equal_Command(cmd, "prefs.gemtext.ansi.fg.changed")) {
2397 iChangeFlags(d->prefs.gemtextAnsiEscapes, allowFg_AnsiFlag, arg_Command(cmd));
2398 return iTrue;
2399 }
2400 else if (equal_Command(cmd, "prefs.gemtext.ansi.fontstyle.changed")) {
2401 iChangeFlags(d->prefs.gemtextAnsiEscapes, allowFontStyle_AnsiFlag, arg_Command(cmd));
2284 return iTrue; 2402 return iTrue;
2285 } 2403 }
2286 else if (equal_Command(cmd, "prefs.mono.gemini.changed") || 2404 else if (equal_Command(cmd, "prefs.mono.gemini.changed") ||
@@ -2303,9 +2421,13 @@ iBool handleCommand_App(const char *cmd) {
2303 return iTrue; 2421 return iTrue;
2304 } 2422 }
2305 else if (equal_Command(cmd, "prefs.boldlink.dark.changed") || 2423 else if (equal_Command(cmd, "prefs.boldlink.dark.changed") ||
2306 equal_Command(cmd, "prefs.boldlink.light.changed")) { 2424 equal_Command(cmd, "prefs.boldlink.light.changed") ||
2425 equal_Command(cmd, "prefs.boldlink.visited.changed")) {
2307 const iBool isSet = (arg_Command(cmd) != 0); 2426 const iBool isSet = (arg_Command(cmd) != 0);
2308 if (startsWith_CStr(cmd, "prefs.boldlink.dark")) { 2427 if (startsWith_CStr(cmd, "prefs.boldlink.visited")) {
2428 d->prefs.boldLinkVisited = isSet;
2429 }
2430 else if (startsWith_CStr(cmd, "prefs.boldlink.dark")) {
2309 d->prefs.boldLinkDark = isSet; 2431 d->prefs.boldLinkDark = isSet;
2310 } 2432 }
2311 else { 2433 else {
@@ -2390,7 +2512,7 @@ iBool handleCommand_App(const char *cmd) {
2390 return iTrue; 2512 return iTrue;
2391 } 2513 }
2392 else if (equal_Command(cmd, "searchurl")) { 2514 else if (equal_Command(cmd, "searchurl")) {
2393 iString *url = &d->prefs.searchUrl; 2515 iString *url = &d->prefs.strings[searchUrl_PrefsString];
2394 setCStr_String(url, suffixPtr_Command(cmd, "address")); 2516 setCStr_String(url, suffixPtr_Command(cmd, "address"));
2395 if (startsWith_String(url, "//")) { 2517 if (startsWith_String(url, "//")) {
2396 prependCStr_String(url, "gemini:"); 2518 prependCStr_String(url, "gemini:");
@@ -2401,20 +2523,20 @@ iBool handleCommand_App(const char *cmd) {
2401 return iTrue; 2523 return iTrue;
2402 } 2524 }
2403 else if (equal_Command(cmd, "proxy.gemini")) { 2525 else if (equal_Command(cmd, "proxy.gemini")) {
2404 setCStr_String(&d->prefs.geminiProxy, suffixPtr_Command(cmd, "address")); 2526 setCStr_String(&d->prefs.strings[geminiProxy_PrefsString], suffixPtr_Command(cmd, "address"));
2405 return iTrue; 2527 return iTrue;
2406 } 2528 }
2407 else if (equal_Command(cmd, "proxy.gopher")) { 2529 else if (equal_Command(cmd, "proxy.gopher")) {
2408 setCStr_String(&d->prefs.gopherProxy, suffixPtr_Command(cmd, "address")); 2530 setCStr_String(&d->prefs.strings[gopherProxy_PrefsString], suffixPtr_Command(cmd, "address"));
2409 return iTrue; 2531 return iTrue;
2410 } 2532 }
2411 else if (equal_Command(cmd, "proxy.http")) { 2533 else if (equal_Command(cmd, "proxy.http")) {
2412 setCStr_String(&d->prefs.httpProxy, suffixPtr_Command(cmd, "address")); 2534 setCStr_String(&d->prefs.strings[httpProxy_PrefsString], suffixPtr_Command(cmd, "address"));
2413 return iTrue; 2535 return iTrue;
2414 } 2536 }
2415#if defined (LAGRANGE_ENABLE_DOWNLOAD_EDIT) 2537#if defined (LAGRANGE_ENABLE_DOWNLOAD_EDIT)
2416 else if (equal_Command(cmd, "downloads")) { 2538 else if (equal_Command(cmd, "downloads")) {
2417 setCStr_String(&d->prefs.downloadDir, suffixPtr_Command(cmd, "path")); 2539 setCStr_String(&d->prefs.strings[downloadDir_PrefsString], suffixPtr_Command(cmd, "path"));
2418 return iTrue; 2540 return iTrue;
2419 } 2541 }
2420#endif 2542#endif
@@ -2423,16 +2545,16 @@ iBool handleCommand_App(const char *cmd) {
2423 return iTrue; 2545 return iTrue;
2424 } 2546 }
2425 else if (equal_Command(cmd, "ca.file")) { 2547 else if (equal_Command(cmd, "ca.file")) {
2426 setCStr_String(&d->prefs.caFile, suffixPtr_Command(cmd, "path")); 2548 setCStr_String(&d->prefs.strings[caFile_PrefsString], suffixPtr_Command(cmd, "path"));
2427 if (!argLabel_Command(cmd, "noset")) { 2549 if (!argLabel_Command(cmd, "noset")) {
2428 setCACertificates_TlsRequest(&d->prefs.caFile, &d->prefs.caPath); 2550 setCACertificates_TlsRequest(&d->prefs.strings[caFile_PrefsString], &d->prefs.strings[caPath_PrefsString]);
2429 } 2551 }
2430 return iTrue; 2552 return iTrue;
2431 } 2553 }
2432 else if (equal_Command(cmd, "ca.path")) { 2554 else if (equal_Command(cmd, "ca.path")) {
2433 setCStr_String(&d->prefs.caPath, suffixPtr_Command(cmd, "path")); 2555 setCStr_String(&d->prefs.strings[caPath_PrefsString], suffixPtr_Command(cmd, "path"));
2434 if (!argLabel_Command(cmd, "noset")) { 2556 if (!argLabel_Command(cmd, "noset")) {
2435 setCACertificates_TlsRequest(&d->prefs.caFile, &d->prefs.caPath); 2557 setCACertificates_TlsRequest(&d->prefs.strings[caFile_PrefsString], &d->prefs.strings[caPath_PrefsString]);
2436 } 2558 }
2437 return iTrue; 2559 return iTrue;
2438 } 2560 }
@@ -2456,18 +2578,29 @@ iBool handleCommand_App(const char *cmd) {
2456 const iBool fromSidebar = argLabel_Command(cmd, "fromsidebar") != 0; 2578 const iBool fromSidebar = argLabel_Command(cmd, "fromsidebar") != 0;
2457 iUrl parts; 2579 iUrl parts;
2458 init_Url(&parts, url); 2580 init_Url(&parts, url);
2581 if (equal_Rangecc(parts.scheme, "about") && equal_Rangecc(parts.path, "command") &&
2582 !isEmpty_Range(&parts.query)) {
2583 /* NOTE: Careful here! `about:command` allows issuing UI events via links on the page.
2584 There is a special set of pages where these are allowed (e.g., "about:fonts").
2585 On every other page, `about:command` links will not be clickable. */
2586 iString *query = collectNewRange_String((iRangecc){
2587 parts.query.start + 1, parts.query.end
2588 });
2589 replace_String(query, "%20", " ");
2590 postCommandString_Root(NULL, query);
2591 return iTrue;
2592 }
2459 if (equalCase_Rangecc(parts.scheme, "titan")) { 2593 if (equalCase_Rangecc(parts.scheme, "titan")) {
2460 iUploadWidget *upload = new_UploadWidget(); 2594 iUploadWidget *upload = new_UploadWidget();
2461 setUrl_UploadWidget(upload, url); 2595 setUrl_UploadWidget(upload, url);
2462 setResponseViewer_UploadWidget(upload, document_App()); 2596 setResponseViewer_UploadWidget(upload, document_App());
2463 addChild_Widget(get_Root()->widget, iClob(upload)); 2597 addChild_Widget(get_Root()->widget, iClob(upload));
2464// finalizeSheet_Mobile(as_Widget(upload));
2465 setupSheetTransition_Mobile(as_Widget(upload), iTrue); 2598 setupSheetTransition_Mobile(as_Widget(upload), iTrue);
2466 postRefresh_App(); 2599 postRefresh_App();
2467 return iTrue; 2600 return iTrue;
2468 } 2601 }
2469 if (argLabel_Command(cmd, "default") || equalCase_Rangecc(parts.scheme, "mailto") || 2602 if (argLabel_Command(cmd, "default") || equalCase_Rangecc(parts.scheme, "mailto") ||
2470 ((noProxy || isEmpty_String(&d->prefs.httpProxy)) && 2603 ((noProxy || isEmpty_String(&d->prefs.strings[httpProxy_PrefsString])) &&
2471 (equalCase_Rangecc(parts.scheme, "http") || 2604 (equalCase_Rangecc(parts.scheme, "http") ||
2472 equalCase_Rangecc(parts.scheme, "https")))) { 2605 equalCase_Rangecc(parts.scheme, "https")))) {
2473 openInDefaultBrowser_App(url); 2606 openInDefaultBrowser_App(url);
@@ -2620,6 +2753,7 @@ iBool handleCommand_App(const char *cmd) {
2620 const iBool isSplit = numRoots_Window(get_Window()) > 1; 2753 const iBool isSplit = numRoots_Window(get_Window()) > 1;
2621 if (tabCount_Widget(tabs) > 1 || isSplit) { 2754 if (tabCount_Widget(tabs) > 1 || isSplit) {
2622 iWidget *closed = removeTabPage_Widget(tabs, index); 2755 iWidget *closed = removeTabPage_Widget(tabs, index);
2756 cancelAllRequests_DocumentWidget((iDocumentWidget *) closed);
2623 destroy_Widget(closed); /* released later */ 2757 destroy_Widget(closed); /* released later */
2624 if (index == tabCount_Widget(tabs)) { 2758 if (index == tabCount_Widget(tabs)) {
2625 index--; 2759 index--;
@@ -2655,7 +2789,7 @@ iBool handleCommand_App(const char *cmd) {
2655 else if (equal_Command(cmd, "preferences")) { 2789 else if (equal_Command(cmd, "preferences")) {
2656 iWidget *dlg = makePreferences_Widget(); 2790 iWidget *dlg = makePreferences_Widget();
2657 updatePrefsThemeButtons_(dlg); 2791 updatePrefsThemeButtons_(dlg);
2658 setText_InputWidget(findChild_Widget(dlg, "prefs.downloads"), &d->prefs.downloadDir); 2792 setText_InputWidget(findChild_Widget(dlg, "prefs.downloads"), &d->prefs.strings[downloadDir_PrefsString]);
2659 setToggle_Widget(findChild_Widget(dlg, "prefs.hoverlink"), d->prefs.hoverLink); 2793 setToggle_Widget(findChild_Widget(dlg, "prefs.hoverlink"), d->prefs.hoverLink);
2660 setToggle_Widget(findChild_Widget(dlg, "prefs.smoothscroll"), d->prefs.smoothScrolling); 2794 setToggle_Widget(findChild_Widget(dlg, "prefs.smoothscroll"), d->prefs.smoothScrolling);
2661 setToggle_Widget(findChild_Widget(dlg, "prefs.imageloadscroll"), d->prefs.loadImageInsteadOfScrolling); 2795 setToggle_Widget(findChild_Widget(dlg, "prefs.imageloadscroll"), d->prefs.loadImageInsteadOfScrolling);
@@ -2665,36 +2799,44 @@ iBool handleCommand_App(const char *cmd) {
2665 setToggle_Widget(findChild_Widget(dlg, "prefs.ostheme"), d->prefs.useSystemTheme); 2799 setToggle_Widget(findChild_Widget(dlg, "prefs.ostheme"), d->prefs.useSystemTheme);
2666 setToggle_Widget(findChild_Widget(dlg, "prefs.customframe"), d->prefs.customFrame); 2800 setToggle_Widget(findChild_Widget(dlg, "prefs.customframe"), d->prefs.customFrame);
2667 setToggle_Widget(findChild_Widget(dlg, "prefs.animate"), d->prefs.uiAnimations); 2801 setToggle_Widget(findChild_Widget(dlg, "prefs.animate"), d->prefs.uiAnimations);
2668 setText_InputWidget(findChild_Widget(dlg, "prefs.userfont"), &d->prefs.symbolFontPath); 2802// setText_InputWidget(findChild_Widget(dlg, "prefs.userfont"), &d->prefs.symbolFontPath);
2669 updatePrefsPinSplitButtons_(dlg, d->prefs.pinSplit); 2803 updatePrefsPinSplitButtons_(dlg, d->prefs.pinSplit);
2670 updateScrollSpeedButtons_(dlg, mouse_ScrollType, d->prefs.smoothScrollSpeed[mouse_ScrollType]); 2804 updateScrollSpeedButtons_(dlg, mouse_ScrollType, d->prefs.smoothScrollSpeed[mouse_ScrollType]);
2671 updateScrollSpeedButtons_(dlg, keyboard_ScrollType, d->prefs.smoothScrollSpeed[keyboard_ScrollType]); 2805 updateScrollSpeedButtons_(dlg, keyboard_ScrollType, d->prefs.smoothScrollSpeed[keyboard_ScrollType]);
2672 updateDropdownSelection_LabelWidget(findChild_Widget(dlg, "prefs.uilang"), cstr_String(&d->prefs.uiLanguage)); 2806 updateDropdownSelection_LabelWidget(findChild_Widget(dlg, "prefs.uilang"), cstr_String(&d->prefs.strings[uiLanguage_PrefsString]));
2673 updateDropdownSelection_LabelWidget( 2807 updateDropdownSelection_LabelWidget(
2674 findChild_Widget(dlg, "prefs.returnkey"), 2808 findChild_Widget(dlg, "prefs.returnkey"),
2675 format_CStr("returnkey.set arg:%d", d->prefs.returnKey)); 2809 format_CStr("returnkey.set arg:%d", d->prefs.returnKey));
2676 setToggle_Widget(findChild_Widget(dlg, "prefs.retainwindow"), d->prefs.retainWindowSize); 2810 setToggle_Widget(findChild_Widget(dlg, "prefs.retainwindow"), d->prefs.retainWindowSize);
2677 setText_InputWidget(findChild_Widget(dlg, "prefs.uiscale"), 2811 setText_InputWidget(findChild_Widget(dlg, "prefs.uiscale"),
2678 collectNewFormat_String("%g", uiScale_Window(as_Window(d->window)))); 2812 collectNewFormat_String("%g", uiScale_Window(as_Window(d->window))));
2679 setFlags_Widget(findChild_Widget(dlg, format_CStr("prefs.font.%d", d->prefs.font)), 2813// setFlags_Widget(findChild_Widget(dlg, format_CStr("prefs.font.%d", d->prefs.font)),
2680 selected_WidgetFlag, 2814// selected_WidgetFlag,
2681 iTrue); 2815// iTrue);
2682 setFlags_Widget( 2816// setFlags_Widget(
2683 findChild_Widget(dlg, format_CStr("prefs.headingfont.%d", d->prefs.headingFont)), 2817// findChild_Widget(dlg, format_CStr("prefs.headingfont.%d", d->prefs.headingFont)),
2684 selected_WidgetFlag, 2818// selected_WidgetFlag,
2685 iTrue); 2819// iTrue);
2686 setFlags_Widget(findChild_Widget(dlg, "prefs.mono.gemini"), 2820 setFlags_Widget(findChild_Widget(dlg, "prefs.mono.gemini"),
2687 selected_WidgetFlag, 2821 selected_WidgetFlag,
2688 d->prefs.monospaceGemini); 2822 d->prefs.monospaceGemini);
2689 setFlags_Widget(findChild_Widget(dlg, "prefs.mono.gopher"), 2823 setFlags_Widget(findChild_Widget(dlg, "prefs.mono.gopher"),
2690 selected_WidgetFlag, 2824 selected_WidgetFlag,
2691 d->prefs.monospaceGopher); 2825 d->prefs.monospaceGopher);
2826 setFlags_Widget(findChild_Widget(dlg, "prefs.boldlink.visited"),
2827 selected_WidgetFlag,
2828 d->prefs.boldLinkVisited);
2692 setFlags_Widget(findChild_Widget(dlg, "prefs.boldlink.dark"), 2829 setFlags_Widget(findChild_Widget(dlg, "prefs.boldlink.dark"),
2693 selected_WidgetFlag, 2830 selected_WidgetFlag,
2694 d->prefs.boldLinkDark); 2831 d->prefs.boldLinkDark);
2695 setFlags_Widget(findChild_Widget(dlg, "prefs.boldlink.light"), 2832 setFlags_Widget(findChild_Widget(dlg, "prefs.boldlink.light"),
2696 selected_WidgetFlag, 2833 selected_WidgetFlag,
2697 d->prefs.boldLinkLight); 2834 d->prefs.boldLinkLight);
2835 setToggle_Widget(findChild_Widget(dlg, "prefs.gemtext.ansi.fg"),
2836 d->prefs.gemtextAnsiEscapes & allowFg_AnsiFlag);
2837 setToggle_Widget(findChild_Widget(dlg, "prefs.gemtext.ansi.fontstyle"),
2838 d->prefs.gemtextAnsiEscapes & allowFontStyle_AnsiFlag);
2839 setToggle_Widget(findChild_Widget(dlg, "prefs.font.smooth"), d->prefs.fontSmoothing);
2698 setFlags_Widget( 2840 setFlags_Widget(
2699 findChild_Widget(dlg, format_CStr("prefs.linewidth.%d", d->prefs.lineWidth)), 2841 findChild_Widget(dlg, format_CStr("prefs.linewidth.%d", d->prefs.lineWidth)),
2700 selected_WidgetFlag, 2842 selected_WidgetFlag,
@@ -2713,8 +2855,11 @@ iBool handleCommand_App(const char *cmd) {
2713 updateColorThemeButton_(findChild_Widget(dlg, "prefs.doctheme.dark"), d->prefs.docThemeDark); 2855 updateColorThemeButton_(findChild_Widget(dlg, "prefs.doctheme.dark"), d->prefs.docThemeDark);
2714 updateColorThemeButton_(findChild_Widget(dlg, "prefs.doctheme.light"), d->prefs.docThemeLight); 2856 updateColorThemeButton_(findChild_Widget(dlg, "prefs.doctheme.light"), d->prefs.docThemeLight);
2715 updateImageStyleButton_(findChild_Widget(dlg, "prefs.imagestyle"), d->prefs.imageStyle); 2857 updateImageStyleButton_(findChild_Widget(dlg, "prefs.imagestyle"), d->prefs.imageStyle);
2716 updateFontButton_(findChild_Widget(dlg, "prefs.font"), d->prefs.font); 2858 updateFontButton_(findChild_Widget(dlg, "prefs.font.ui"), &d->prefs.strings[uiFont_PrefsString]);
2717 updateFontButton_(findChild_Widget(dlg, "prefs.headingfont"), d->prefs.headingFont); 2859 updateFontButton_(findChild_Widget(dlg, "prefs.font.heading"), &d->prefs.strings[headingFont_PrefsString]);
2860 updateFontButton_(findChild_Widget(dlg, "prefs.font.body"), &d->prefs.strings[bodyFont_PrefsString]);
2861 updateFontButton_(findChild_Widget(dlg, "prefs.font.mono"), &d->prefs.strings[monospaceFont_PrefsString]);
2862 updateFontButton_(findChild_Widget(dlg, "prefs.font.monodoc"), &d->prefs.strings[monospaceDocumentFont_PrefsString]);
2718 setFlags_Widget( 2863 setFlags_Widget(
2719 findChild_Widget( 2864 findChild_Widget(
2720 dlg, format_CStr("prefs.saturation.%d", (int) (d->prefs.saturation * 3.99f))), 2865 dlg, format_CStr("prefs.saturation.%d", (int) (d->prefs.saturation * 3.99f))),
@@ -2725,12 +2870,12 @@ iBool handleCommand_App(const char *cmd) {
2725 setText_InputWidget(findChild_Widget(dlg, "prefs.memorysize"), 2870 setText_InputWidget(findChild_Widget(dlg, "prefs.memorysize"),
2726 collectNewFormat_String("%d", d->prefs.maxMemorySize)); 2871 collectNewFormat_String("%d", d->prefs.maxMemorySize));
2727 setToggle_Widget(findChild_Widget(dlg, "prefs.decodeurls"), d->prefs.decodeUserVisibleURLs); 2872 setToggle_Widget(findChild_Widget(dlg, "prefs.decodeurls"), d->prefs.decodeUserVisibleURLs);
2728 setText_InputWidget(findChild_Widget(dlg, "prefs.searchurl"), &d->prefs.searchUrl); 2873 setText_InputWidget(findChild_Widget(dlg, "prefs.searchurl"), &d->prefs.strings[searchUrl_PrefsString]);
2729 setText_InputWidget(findChild_Widget(dlg, "prefs.ca.file"), &d->prefs.caFile); 2874 setText_InputWidget(findChild_Widget(dlg, "prefs.ca.file"), &d->prefs.strings[caFile_PrefsString]);
2730 setText_InputWidget(findChild_Widget(dlg, "prefs.ca.path"), &d->prefs.caPath); 2875 setText_InputWidget(findChild_Widget(dlg, "prefs.ca.path"), &d->prefs.strings[caPath_PrefsString]);
2731 setText_InputWidget(findChild_Widget(dlg, "prefs.proxy.gemini"), &d->prefs.geminiProxy); 2876 setText_InputWidget(findChild_Widget(dlg, "prefs.proxy.gemini"), &d->prefs.strings[geminiProxy_PrefsString]);
2732 setText_InputWidget(findChild_Widget(dlg, "prefs.proxy.gopher"), &d->prefs.gopherProxy); 2877 setText_InputWidget(findChild_Widget(dlg, "prefs.proxy.gopher"), &d->prefs.strings[gopherProxy_PrefsString]);
2733 setText_InputWidget(findChild_Widget(dlg, "prefs.proxy.http"), &d->prefs.httpProxy); 2878 setText_InputWidget(findChild_Widget(dlg, "prefs.proxy.http"), &d->prefs.strings[httpProxy_PrefsString]);
2734 iWidget *tabs = findChild_Widget(dlg, "prefs.tabs"); 2879 iWidget *tabs = findChild_Widget(dlg, "prefs.tabs");
2735 if (tabs) { 2880 if (tabs) {
2736 showTabPage_Widget(tabs, tabPage_Widget(tabs, d->prefs.dialogTab)); 2881 showTabPage_Widget(tabs, tabPage_Widget(tabs, d->prefs.dialogTab));
@@ -2912,15 +3057,53 @@ iBool handleCommand_App(const char *cmd) {
2912 return iFalse; 3057 return iFalse;
2913 } 3058 }
2914 else if (equal_Command(cmd, "os.theme.changed")) { 3059 else if (equal_Command(cmd, "os.theme.changed")) {
3060 const int dark = argLabel_Command(cmd, "dark");
3061 d->isDarkSystemTheme = dark;
2915 if (d->prefs.useSystemTheme) { 3062 if (d->prefs.useSystemTheme) {
2916 const int dark = argLabel_Command(cmd, "dark"); 3063 const int contrast = argLabel_Command(cmd, "contrast");
2917 const int contrast = argLabel_Command(cmd, "contrast"); 3064 const int preferred = d->prefs.systemPreferredColorTheme[dark ^ 1];
2918 postCommandf_App("theme.set arg:%d auto:1", 3065 postCommandf_App("theme.set arg:%d auto:1",
2919 dark ? (contrast ? pureBlack_ColorTheme : dark_ColorTheme) 3066 preferred >= 0 ? preferred
2920 : (contrast ? pureWhite_ColorTheme : light_ColorTheme)); 3067 : dark ? (contrast ? pureBlack_ColorTheme : dark_ColorTheme)
3068 : (contrast ? pureWhite_ColorTheme : light_ColorTheme));
2921 } 3069 }
2922 return iFalse; 3070 return iFalse;
2923 } 3071 }
3072 else if (equal_Command(cmd, "fontpack.enable")) {
3073 const iString *packId = collect_String(suffix_Command(cmd, "id"));
3074 enablePack_Fonts(packId, arg_Command(cmd));
3075 postCommand_App("navigate.reload");
3076 return iTrue;
3077 }
3078 else if (equal_Command(cmd, "fontpack.delete")) {
3079 const iString *packId = collect_String(suffix_Command(cmd, "id"));
3080 if (isEmpty_String(packId)) {
3081 return iTrue;
3082 }
3083 const iFontPack *pack = pack_Fonts(cstr_String(packId));
3084 if (pack && loadPath_FontPack(pack)) {
3085 if (argLabel_Command(cmd, "confirmed")) {
3086 remove_StringSet(d->prefs.disabledFontPacks, packId);
3087 remove(cstr_String(loadPath_FontPack(pack)));
3088 reload_Fonts();
3089 postCommand_App("navigate.reload");
3090 }
3091 else {
3092 makeQuestion_Widget(
3093 uiTextCaution_ColorEscape "${heading.fontpack.delete}",
3094 format_Lang("${dlg.fontpack.delete.confirm}",
3095 cstr_String(packId)),
3096 (iMenuItem[]){ { "${cancel}" },
3097 { uiTextCaution_ColorEscape " ${dlg.fontpack.delete}",
3098 0,
3099 0,
3100 format_CStr("!fontpack.delete confirmed:1 id:%s",
3101 cstr_String(packId)) } },
3102 2);
3103 }
3104 }
3105 return iTrue;
3106 }
2924#if defined (LAGRANGE_ENABLE_IPC) 3107#if defined (LAGRANGE_ENABLE_IPC)
2925 else if (equal_Command(cmd, "ipc.list.urls")) { 3108 else if (equal_Command(cmd, "ipc.list.urls")) {
2926 iProcessId pid = argLabel_Command(cmd, "pid"); 3109 iProcessId pid = argLabel_Command(cmd, "pid");