summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/app.c61
-rw-r--r--src/app.h2
-rw-r--r--src/fontpack.c69
-rw-r--r--src/fontpack.h10
-rw-r--r--src/media.c32
-rw-r--r--src/media.h2
-rw-r--r--src/prefs.c2
-rw-r--r--src/prefs.h3
-rw-r--r--src/ui/documentwidget.c43
-rw-r--r--src/ui/documentwidget.h3
-rw-r--r--src/ui/mediaui.c48
-rw-r--r--src/ui/mediaui.h7
12 files changed, 234 insertions, 48 deletions
diff --git a/src/app.c b/src/app.c
index 6282ade2..70b611c2 100644
--- a/src/app.c
+++ b/src/app.c
@@ -231,6 +231,9 @@ static iString *serializePrefs_App_(const iApp *d) {
231 appendFormat_String(str, "linewidth.set arg:%d\n", d->prefs.lineWidth); 231 appendFormat_String(str, "linewidth.set arg:%d\n", d->prefs.lineWidth);
232 appendFormat_String(str, "linespacing.set arg:%f\n", d->prefs.lineSpacing); 232 appendFormat_String(str, "linespacing.set arg:%f\n", d->prefs.lineSpacing);
233 appendFormat_String(str, "returnkey.set arg:%d\n", d->prefs.returnKey); 233 appendFormat_String(str, "returnkey.set arg:%d\n", d->prefs.returnKey);
234 iConstForEach(StringSet, fp, d->prefs.disabledFontPacks) {
235 appendFormat_String(str, "fontpack.disable id:%s\n", cstr_String(fp.value));
236 }
234 /* TODO: This array belongs in Prefs. It can then be used for command handling as well. */ 237 /* TODO: This array belongs in Prefs. It can then be used for command handling as well. */
235 const struct { 238 const struct {
236 const char * id; 239 const char * id;
@@ -256,21 +259,6 @@ static iString *serializePrefs_App_(const iApp *d) {
256 iForIndices(i, boolPrefs) { 259 iForIndices(i, boolPrefs) {
257 appendFormat_String(str, "%s.changed arg:%d\n", boolPrefs[i].id, *boolPrefs[i].value); 260 appendFormat_String(str, "%s.changed arg:%d\n", boolPrefs[i].id, *boolPrefs[i].value);
258 } 261 }
259// appendFormat_String(str, "prefs.animate.changed arg:%d\n", d->prefs.uiAnimations);
260// appendFormat_String(str, "prefs.font.smooth.changed arg:%d\n", d->prefs.fontSmoothing);
261// appendFormat_String(str, "prefs.gemtext.ansi.changed arg:%d\n", d->prefs.gemtextAnsiEscapes);
262// appendFormat_String(str, "prefs.mono.gemini.changed arg:%d\n", d->prefs.monospaceGemini);
263// appendFormat_String(str, "prefs.mono.gopher.changed arg:%d\n", d->prefs.monospaceGopher);
264// appendFormat_String(str, "prefs.boldlink.dark.changed arg:%d\n", d->prefs.boldLinkDark);
265// appendFormat_String(str, "prefs.boldlink.light.changed arg:%d\n", d->prefs.boldLinkLight);
266// appendFormat_String(str, "prefs.biglede.changed arg:%d\n", d->prefs.bigFirstParagraph);
267// appendFormat_String(str, "prefs.plaintext.wrap.changed arg:%d\n", d->prefs.plainTextWrap);
268// appendFormat_String(str, "prefs.sideicon.changed arg:%d\n", d->prefs.sideIcon);
269// appendFormat_String(str, "prefs.centershort.changed arg:%d\n", d->prefs.centerShortDocs);
270// appendFormat_String(str, "prefs.collapsepreonload.changed arg:%d\n", d->prefs.collapsePreOnLoad);
271// appendFormat_String(str, "prefs.hoverlink.changed arg:%d\n", d->prefs.hoverLink);
272// appendFormat_String(str, "prefs.bookmarks.addbottom arg:%d\n", d->prefs.addBookmarksToBottom);
273// appendFormat_String(str, "prefs.archive.openindex.changed arg:%d\n", d->prefs.openArchiveIndexPages);
274 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);
275 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);
276 appendFormat_String(str, "accent.set arg:%d\n", d->prefs.accent); 264 appendFormat_String(str, "accent.set arg:%d\n", d->prefs.accent);
@@ -381,6 +369,10 @@ static void loadPrefs_App_(iApp *d) {
381 d->initialWindowRect = init_Rect( 369 d->initialWindowRect = init_Rect(
382 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"));
383 } 371 }
372 else if (equal_Command(cmd, "fontpack.disable")) {
373 insert_StringSet(d->prefs.disabledFontPacks,
374 collect_String(suffix_Command(cmd, "id")));
375 }
384#if !defined (LAGRANGE_ENABLE_DOWNLOAD_EDIT) 376#if !defined (LAGRANGE_ENABLE_DOWNLOAD_EDIT)
385 else if (equal_Command(cmd, "downloads")) { 377 else if (equal_Command(cmd, "downloads")) {
386 continue; /* can't change downloads directory */ 378 continue; /* can't change downloads directory */
@@ -1119,6 +1111,18 @@ void trimMemory_App(void) {
1119 iRelease(docs); 1111 iRelease(docs);
1120} 1112}
1121 1113
1114iBool findCachedContent_App(const iString *url, iString *mime_out, iBlock *data_out) {
1115 /* Cached content can be found in MediaRequests of DocumentWidgets (loaded on the currently
1116 open page) and the DocumentWidget itself. `Media` doesn't store source data, only
1117 presentation data. */
1118 iConstForEach(ObjectList, i, iClob(listDocuments_App(NULL))) {
1119 if (findCachedContent_DocumentWidget(i.object, url, mime_out, data_out)) {
1120 return iTrue;
1121 }
1122 }
1123 return iFalse;
1124}
1125
1122iLocalDef iBool isWaitingAllowed_App_(iApp *d) { 1126iLocalDef iBool isWaitingAllowed_App_(iApp *d) {
1123 if (!isEmpty_Periodic(&d->periodic)) { 1127 if (!isEmpty_Periodic(&d->periodic)) {
1124 return iFalse; 1128 return iFalse;
@@ -2086,7 +2090,8 @@ const iString *searchQueryUrl_App(const iString *queryStringUnescaped) {
2086 "%s?%s", cstr_String(&d->prefs.strings[searchUrl_PrefsString]), cstr_String(escaped)); 2090 "%s?%s", cstr_String(&d->prefs.strings[searchUrl_PrefsString]), cstr_String(escaped));
2087} 2091}
2088 2092
2089static void resetFonts_App_(iApp *d) { 2093void resetFonts_App(void) {
2094 iApp *d = &app_;
2090 iConstForEach(PtrArray, win, listWindows_App_(d)) { 2095 iConstForEach(PtrArray, win, listWindows_App_(d)) {
2091 resetFonts_Text(text_Window(win.ptr)); 2096 resetFonts_Text(text_Window(win.ptr));
2092 } 2097 }
@@ -2163,7 +2168,11 @@ iBool handleCommand_App(const char *cmd) {
2163 return iTrue; 2168 return iTrue;
2164 } 2169 }
2165 else if (equal_Command(cmd, "font.reset")) { 2170 else if (equal_Command(cmd, "font.reset")) {
2166 resetFonts_App_(d); 2171 resetFonts_App();
2172 return iTrue;
2173 }
2174 else if (equal_Command(cmd, "font.reload")) {
2175 reload_Fonts(); /* also does font cache reset, window invalidation */
2167 return iTrue; 2176 return iTrue;
2168 } 2177 }
2169#if 0 2178#if 0
@@ -2175,7 +2184,7 @@ iBool handleCommand_App(const char *cmd) {
2175 } 2184 }
2176 setCStr_String(&d->prefs.symbolFontPath, path); 2185 setCStr_String(&d->prefs.symbolFontPath, path);
2177 loadUserFonts_Text(); 2186 loadUserFonts_Text();
2178 resetFonts_App_(d); 2187 resetFonts_App(d);
2179 if (!isFrozen) { 2188 if (!isFrozen) {
2180 postCommand_App("font.changed"); 2189 postCommand_App("font.changed");
2181 postCommand_App("window.unfreeze"); 2190 postCommand_App("window.unfreeze");
@@ -3034,6 +3043,22 @@ iBool handleCommand_App(const char *cmd) {
3034 } 3043 }
3035 return iFalse; 3044 return iFalse;
3036 } 3045 }
3046 else if (equal_Command(cmd, "media.fontpack.enable")) {
3047 const iString *packId = collect_String(suffix_Command(cmd, "packid"));
3048 if (arg_Command(cmd)) {
3049 remove_StringSet(d->prefs.disabledFontPacks, packId);
3050 }
3051 else {
3052 insert_StringSet(d->prefs.disabledFontPacks, packId);
3053 }
3054 resetFonts_App();
3055 const iMedia *media = pointerLabel_Command(cmd, "media");
3056 if (media) {
3057 postCommandf_App("media.fontpack.updated id:%u media:%p",
3058 argU32Label_Command(cmd, "mediaid"), media);
3059 }
3060 return iTrue;
3061 }
3037#if defined (LAGRANGE_ENABLE_IPC) 3062#if defined (LAGRANGE_ENABLE_IPC)
3038 else if (equal_Command(cmd, "ipc.list.urls")) { 3063 else if (equal_Command(cmd, "ipc.list.urls")) {
3039 iProcessId pid = argLabel_Command(cmd, "pid"); 3064 iProcessId pid = argLabel_Command(cmd, "pid");
diff --git a/src/app.h b/src/app.h
index 2313ec15..8543f3b5 100644
--- a/src/app.h
+++ b/src/app.h
@@ -99,6 +99,7 @@ iStringSet * listOpenURLs_App (void); /* all tabs */
99iDocumentWidget * newTab_App (const iDocumentWidget *duplicateOf, iBool switchToNew); 99iDocumentWidget * newTab_App (const iDocumentWidget *duplicateOf, iBool switchToNew);
100void trimCache_App (void); 100void trimCache_App (void);
101void trimMemory_App (void); 101void trimMemory_App (void);
102iBool findCachedContent_App(const iString *url, iString *mime_out, iBlock *data_out);
102 103
103iDocumentWidget * document_Root (iRoot *); 104iDocumentWidget * document_Root (iRoot *);
104 105
@@ -137,6 +138,7 @@ iDocumentWidget * document_Command (const char *cmd);
137 138
138void openInDefaultBrowser_App(const iString *url); 139void openInDefaultBrowser_App(const iString *url);
139void revealPath_App (const iString *path); 140void revealPath_App (const iString *path);
141void resetFonts_App (void);
140 142
141iMainWindow * mainWindow_App (void); 143iMainWindow * mainWindow_App (void);
142void closePopups_App (void); 144void closePopups_App (void);
diff --git a/src/fontpack.c b/src/fontpack.c
index b135ea43..9603bded 100644
--- a/src/fontpack.c
+++ b/src/fontpack.c
@@ -22,6 +22,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
22 22
23#include "fontpack.h" 23#include "fontpack.h"
24#include "embedded.h" 24#include "embedded.h"
25#include "ui/window.h"
25#include "app.h" 26#include "app.h"
26 27
27#include <the_Foundation/archive.h> 28#include <the_Foundation/archive.h>
@@ -396,6 +397,24 @@ static iBool load_FontPack_(iFontPack *d, const iString *ini) {
396 return ok; 397 return ok;
397} 398}
398 399
400iBool detect_FontPack(const iBlock *data) {
401 iBool ok = iFalse;
402 iArchive *zip = new_Archive();
403 if (openData_Archive(zip, data)) {
404 iString ini;
405 initBlock_String(&ini, dataCStr_Archive(zip, "fontpack.ini"));
406 if (isUtf8_Rangecc(range_String(&ini))) {
407 /* Validate the TOML syntax without actually checking any values. */
408 iTomlParser *toml = new_TomlParser();
409 ok = parse_TomlParser(toml, &ini);
410 delete_TomlParser(toml);
411 }
412 deinit_String(&ini);
413 }
414 iRelease(zip);
415 return ok;
416}
417
399iBool loadArchive_FontPack(iFontPack *d, const iArchive *zip) { 418iBool loadArchive_FontPack(iFontPack *d, const iArchive *zip) {
400 d->archive = zip; 419 d->archive = zip;
401 iBool ok = iFalse; 420 iBool ok = iFalse;
@@ -467,16 +486,24 @@ static void sortSpecs_Fonts_(iFonts *d) {
467 clear_PtrArray(&d->specOrder); 486 clear_PtrArray(&d->specOrder);
468 iConstForEach(PtrArray, p, &d->packs) { 487 iConstForEach(PtrArray, p, &d->packs) {
469 const iFontPack *pack = p.ptr; 488 const iFontPack *pack = p.ptr;
470 iConstForEach(Array, i, &pack->fonts) { 489 if (!contains_StringSet(prefs_App()->disabledFontPacks, &pack->id)) {
471 pushBack_PtrArray(&d->specOrder, i.value); 490 iConstForEach(Array, i, &pack->fonts) {
491 pushBack_PtrArray(&d->specOrder, i.value);
492 }
472 } 493 }
473 } 494 }
474 sort_Array(&d->specOrder, cmpPriority_FontSpecPtr_); 495 sort_Array(&d->specOrder, cmpPriority_FontSpecPtr_);
475} 496}
476 497
498static const iString *userFontsDirectory_Fonts_(const iFonts *d) {
499 return collect_String(concatCStr_Path(&d->userDir, "fonts"));
500}
501
477void init_Fonts(const char *userDir) { 502void init_Fonts(const char *userDir) {
478 iFonts *d = &fonts_; 503 iFonts *d = &fonts_;
479 initCStr_String(&d->userDir, userDir); 504 initCStr_String(&d->userDir, userDir);
505 const iString *userFontsDir = userFontsDirectory_Fonts_(d);
506 makeDirs_Path(userFontsDir);
480 init_PtrArray(&d->packs); 507 init_PtrArray(&d->packs);
481 d->files = new_ObjectList(); 508 d->files = new_ObjectList();
482 init_PtrArray(&d->specOrder); 509 init_PtrArray(&d->specOrder);
@@ -496,7 +523,7 @@ void init_Fonts(const char *userDir) {
496 "./fonts", 523 "./fonts",
497 "../share/lagrange", /* Note: These must match CMakeLists.txt install destination */ 524 "../share/lagrange", /* Note: These must match CMakeLists.txt install destination */
498 "../../share/lagrange", 525 "../../share/lagrange",
499 concatPath_CStr(userDir, "fonts"), 526 cstr_String(userFontsDir),
500 userDir, 527 userDir,
501 }; 528 };
502 const iString *execDir = collectNewRange_String(dirName_Path(execPath_App())); 529 const iString *execDir = collectNewRange_String(dirName_Path(execPath_App()));
@@ -555,7 +582,6 @@ void init_Fonts(const char *userDir) {
555void deinit_Fonts(void) { 582void deinit_Fonts(void) {
556 iFonts *d = &fonts_; 583 iFonts *d = &fonts_;
557 unloadFonts_Fonts_(d); 584 unloadFonts_Fonts_(d);
558 //unloadFiles_Fonts_(d);
559 iAssert(isEmpty_ObjectList(d->files)); 585 iAssert(isEmpty_ObjectList(d->files));
560 deinit_PtrArray(&d->specOrder); 586 deinit_PtrArray(&d->specOrder);
561 deinit_PtrArray(&d->packs); 587 deinit_PtrArray(&d->packs);
@@ -617,7 +643,18 @@ const iString *infoPage_Fonts(void) {
617 return str; 643 return str;
618} 644}
619 645
620const iFontPack *findPack_Fonts(const iString *path) { 646const iFontPack *pack_Fonts(const char *packId) {
647 iFonts *d = &fonts_;
648 iConstForEach(PtrArray, i, &d->packs) {
649 const iFontPack *pack = i.ptr;
650 if (!cmp_String(&pack->id, packId)) {
651 return pack;
652 }
653 }
654 return NULL;
655}
656
657const iFontPack *packByPath_Fonts(const iString *path) {
621 iFonts *d = &fonts_; 658 iFonts *d = &fonts_;
622 iConstForEach(PtrArray, i, &d->packs) { 659 iConstForEach(PtrArray, i, &d->packs) {
623 const iFontPack *pack = i.ptr; 660 const iFontPack *pack = i.ptr;
@@ -628,6 +665,28 @@ const iFontPack *findPack_Fonts(const iString *path) {
628 return NULL; 665 return NULL;
629} 666}
630 667
668void reload_Fonts(void) {
669 iFonts *d = &fonts_;
670 iString *userDir = copy_String(&d->userDir);
671 deinit_Fonts(); /* `d->userDir` is freed */
672 init_Fonts(cstr_String(userDir));
673 resetFonts_App();
674 invalidate_Window(get_MainWindow());
675 delete_String(userDir);
676}
677
678void install_Fonts(const iString *fontId, const iBlock *data) {
679 iFonts *d = &fonts_;
680 iFile *f = new_File(collect_String(concatCStr_Path(
681 userFontsDirectory_Fonts_(d), format_CStr("%s.fontpack", cstr_String(fontId)))));
682 if (open_File(f, writeOnly_FileMode)) {
683 write_File(f, data);
684 }
685 iRelease(f);
686 /* Newly installed fontpacks may have a higher priority that overrides other fonts. */
687 reload_Fonts();
688}
689
631iBool preloadLocalFontpackForPreview_Fonts(iGmDocument *doc) { 690iBool preloadLocalFontpackForPreview_Fonts(iGmDocument *doc) {
632 iBool wasLoaded = iFalse; 691 iBool wasLoaded = iFalse;
633 for (size_t linkId = 1; ; linkId++) { 692 for (size_t linkId = 1; ; linkId++) {
diff --git a/src/fontpack.h b/src/fontpack.h
index f69e2adc..2fdfa9ab 100644
--- a/src/fontpack.h
+++ b/src/fontpack.h
@@ -149,6 +149,7 @@ void setReadOnly_FontPack (iFontPack *, iBool readOnly);
149void setStandalone_FontPack (iFontPack *, iBool standalone); 149void setStandalone_FontPack (iFontPack *, iBool standalone);
150void setLoadPath_FontPack (iFontPack *, const iString *path); 150void setLoadPath_FontPack (iFontPack *, const iString *path);
151iBool loadArchive_FontPack (iFontPack *, const iArchive *zip); 151iBool loadArchive_FontPack (iFontPack *, const iArchive *zip);
152iBool detect_FontPack (const iBlock *data);
152 153
153iFontPackId id_FontPack (const iFontPack *); 154iFontPackId id_FontPack (const iFontPack *);
154const iPtrArray * listSpecs_FontPack (const iFontPack *); 155const iPtrArray * listSpecs_FontPack (const iFontPack *);
@@ -159,11 +160,18 @@ iDeclareType(GmDocument)
159void init_Fonts (const char *userDir); 160void init_Fonts (const char *userDir);
160void deinit_Fonts (void); 161void deinit_Fonts (void);
161 162
162const iFontPack * findPack_Fonts (const iString *path); 163const iFontPack * pack_Fonts (const char *packId);
164const iFontPack * packByPath_Fonts (const iString *path);
163const iFontSpec * findSpec_Fonts (const char *fontId); 165const iFontSpec * findSpec_Fonts (const char *fontId);
164const iPtrArray * listPacks_Fonts (void); 166const iPtrArray * listPacks_Fonts (void);
165const iPtrArray * listSpecs_Fonts (iBool (*filterFunc)(const iFontSpec *)); 167const iPtrArray * listSpecs_Fonts (iBool (*filterFunc)(const iFontSpec *));
166const iPtrArray * listSpecsByPriority_Fonts (void); 168const iPtrArray * listSpecsByPriority_Fonts (void);
167const iString * infoPage_Fonts (void); 169const iString * infoPage_Fonts (void);
170void install_Fonts (const iString *fontId, const iBlock *data);
171void reload_Fonts (void);
168 172
169iBool preloadLocalFontpackForPreview_Fonts (iGmDocument *doc); 173iBool preloadLocalFontpackForPreview_Fonts (iGmDocument *doc);
174
175iLocalDef iBool isInstalled_Fonts(const char *packId) {
176 return pack_Fonts(packId) != NULL;
177}
diff --git a/src/media.c b/src/media.c
index 0ce2ac5c..412205a7 100644
--- a/src/media.c
+++ b/src/media.c
@@ -312,15 +312,19 @@ void deinit_GmFontpack(iGmFontpack *d) {
312 312
313static void loadData_GmFontpack_(iGmFontpack *d, const iBlock *data) { 313static void loadData_GmFontpack_(iGmFontpack *d, const iBlock *data) {
314 const iString *loadPath = collect_String(localFilePathFromUrl_String(&d->props.url)); 314 const iString *loadPath = collect_String(localFilePathFromUrl_String(&d->props.url));
315 const iFontPack *pack = findPack_Fonts(loadPath); 315 const iFontPack *pack = packByPath_Fonts(loadPath);
316 d->info.isValid = d->info.isInstalled = pack != NULL; 316 d->info.isValid = d->info.isInstalled = pack != NULL;
317 d->info.isReadOnly = iFalse; 317 d->info.isReadOnly = iFalse;
318 d->info.isDisabled = iFalse;
319 clear_StringList(d->info.names);
320 clear_String(&d->packId);
318 if (!pack) { 321 if (!pack) {
319 /* Let's load it now temporarily and see what's inside. */ 322 /* Let's load it now temporarily and see what's inside. */
320 iArchive *zip = new_Archive(); 323 iArchive *zip = new_Archive();
321 if (openData_Archive(zip, data)) { 324 if (openData_Archive(zip, data)) {
322 iFontPack *fp = collect_FontPack(new_FontPack()); 325 iFontPack *fp = collect_FontPack(new_FontPack());
323 setLoadPath_FontPack(fp, loadPath); 326 setLoadPath_FontPack(fp, loadPath);
327 /* TODO: No need to load all the font files here, just the metadata. */
324 setStandalone_FontPack(fp, iTrue); 328 setStandalone_FontPack(fp, iTrue);
325 if (loadArchive_FontPack(fp, zip)) { 329 if (loadArchive_FontPack(fp, zip)) {
326 d->info.isValid = iTrue; 330 d->info.isValid = iTrue;
@@ -334,6 +338,7 @@ static void loadData_GmFontpack_(iGmFontpack *d, const iBlock *data) {
334 d->info.packId.id = &d->packId; /* we own this String */ 338 d->info.packId.id = &d->packId; /* we own this String */
335 d->info.packId.version = id_FontPack(pack).version; 339 d->info.packId.version = id_FontPack(pack).version;
336 d->info.isReadOnly = isReadOnly_FontPack(pack); 340 d->info.isReadOnly = isReadOnly_FontPack(pack);
341 d->info.isDisabled = contains_StringSet(prefs_App()->disabledFontPacks, &d->packId);
337 } 342 }
338 iPtrSet *unique = new_PtrSet(); 343 iPtrSet *unique = new_PtrSet();
339 iConstForEach(PtrArray, i, listSpecs_FontPack(pack)) { 344 iConstForEach(PtrArray, i, listSpecs_FontPack(pack)) {
@@ -455,7 +460,7 @@ iBool setData_Media(iMedia *d, iGmLinkId linkId, const iString *mime, const iBlo
455 const iBool isPartial = (flags & partialData_MediaFlag) != 0; 460 const iBool isPartial = (flags & partialData_MediaFlag) != 0;
456 const iBool allowHide = (flags & allowHide_MediaFlag) != 0; 461 const iBool allowHide = (flags & allowHide_MediaFlag) != 0;
457 const iBool isDeleting = (!mime || !data); 462 const iBool isDeleting = (!mime || !data);
458 iMediaId existing = findMediaForLink_Media(d, linkId, none_MediaType);// findLinkImage_Media(d, linkId); 463 iMediaId existing = findMediaForLink_Media(d, linkId, none_MediaType);
459 const size_t existingIndex = index_MediaId(existing); 464 const size_t existingIndex = index_MediaId(existing);
460 iBool isNew = iFalse; 465 iBool isNew = iFalse;
461 if (existing.type == image_MediaType) { 466 if (existing.type == image_MediaType) {
@@ -574,17 +579,34 @@ static iMediaId findMediaPtr_Media_(const iPtrArray *items, enum iMediaType medi
574 579
575iMediaId findMediaForLink_Media(const iMedia *d, iGmLinkId linkId, enum iMediaType mediaType) { 580iMediaId findMediaForLink_Media(const iMedia *d, iGmLinkId linkId, enum iMediaType mediaType) {
576 /* TODO: Use hashes, this will get very slow if there is a large number of media items. */ 581 /* TODO: Use hashes, this will get very slow if there is a large number of media items. */
577 iMediaId mid; 582 iMediaId mid = iInvalidMediaId;
578 for (int i = 0; i < max_MediaType; i++) { 583 for (int i = 0; i < max_MediaType; i++) {
579 if (mediaType == i || !mediaType) { 584 if (mediaType == i || !mediaType) {
580 mid = findMediaPtr_Media_(&d->items[i], i, linkId); 585 mid = findMediaPtr_Media_(&d->items[i], i, linkId);
581 if (mid.type) { 586 if (mid.type) {
582 return mid; 587 break;
583 } 588 }
584 } 589 }
585 } 590 }
586 return iInvalidMediaId; 591 return mid;
592}
593
594#if 0
595iMediaId findUrl_Media(const iMedia *d, const iString *url) {
596 iMediaId mid = iInvalidMediaId;
597 for (int i = 0; i < max_MediaType; i++) {
598 for (int j = 0; j < size_PtrArray(&d->items[i]); j++) {
599 const iGmMediaProps *props = constAt_PtrArray(&d->items[i], j);
600 if (equal_String(&props->url, url)) {
601 mid.type = i;
602 mid.id = j + 1;
603 break;
604 }
605 }
606 }
607 return mid;
587} 608}
609#endif
588 610
589size_t numAudio_Media(const iMedia *d) { 611size_t numAudio_Media(const iMedia *d) {
590 return size_PtrArray(&d->items[audio_MediaType]); 612 return size_PtrArray(&d->items[audio_MediaType]);
diff --git a/src/media.h b/src/media.h
index 47a4da93..92a46cd3 100644
--- a/src/media.h
+++ b/src/media.h
@@ -74,6 +74,7 @@ iBool setData_Media (iMedia *, uint16_t linkId, const iStrin
74 74
75size_t memorySize_Media (const iMedia *); 75size_t memorySize_Media (const iMedia *);
76iMediaId findMediaForLink_Media (const iMedia *, uint16_t linkId, enum iMediaType mediaType); 76iMediaId findMediaForLink_Media (const iMedia *, uint16_t linkId, enum iMediaType mediaType);
77//iMediaId findUrl_Media (const iMedia *, const iString *url);
77 78
78iMediaId id_Media (const iMedia *, uint16_t linkId, enum iMediaType type); 79iMediaId id_Media (const iMedia *, uint16_t linkId, enum iMediaType type);
79iBool info_Media (const iMedia *, iMediaId mediaId, iGmMediaInfo *info_out); 80iBool info_Media (const iMedia *, iMediaId mediaId, iGmMediaInfo *info_out);
@@ -114,6 +115,7 @@ struct Impl_FontpackMediaInfo {
114 iFontPackId packId; 115 iFontPackId packId;
115 iBool isValid; 116 iBool isValid;
116 iBool isInstalled; 117 iBool isInstalled;
118 iBool isDisabled;
117 iBool isReadOnly; 119 iBool isReadOnly;
118 size_t sizeInBytes; 120 size_t sizeInBytes;
119 iStringList *names; 121 iStringList *names;
diff --git a/src/prefs.c b/src/prefs.c
index 673470d6..523ec649 100644
--- a/src/prefs.c
+++ b/src/prefs.c
@@ -60,6 +60,7 @@ void init_Prefs(iPrefs *d) {
60 setCStr_String(&d->strings[bodyFont_PrefsString], "default"); 60 setCStr_String(&d->strings[bodyFont_PrefsString], "default");
61 setCStr_String(&d->strings[monospaceFont_PrefsString], "iosevka"); 61 setCStr_String(&d->strings[monospaceFont_PrefsString], "iosevka");
62 setCStr_String(&d->strings[monospaceDocumentFont_PrefsString], "iosevka-body"); 62 setCStr_String(&d->strings[monospaceDocumentFont_PrefsString], "iosevka-body");
63 d->disabledFontPacks = new_StringSet();
63 d->fontSmoothing = iTrue; 64 d->fontSmoothing = iTrue;
64 d->gemtextAnsiEscapes = iFalse; 65 d->gemtextAnsiEscapes = iFalse;
65 d->monospaceGemini = iFalse; 66 d->monospaceGemini = iFalse;
@@ -88,6 +89,7 @@ void init_Prefs(iPrefs *d) {
88} 89}
89 90
90void deinit_Prefs(iPrefs *d) { 91void deinit_Prefs(iPrefs *d) {
92 iRelease(d->disabledFontPacks);
91 iForIndices(i, d->strings) { 93 iForIndices(i, d->strings) {
92 deinit_String(&d->strings[i]); 94 deinit_String(&d->strings[i]);
93 } 95 }
diff --git a/src/prefs.h b/src/prefs.h
index 70846be4..bbf98370 100644
--- a/src/prefs.h
+++ b/src/prefs.h
@@ -22,7 +22,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
22 22
23#pragma once 23#pragma once
24 24
25#include <the_Foundation/string.h> 25#include <the_Foundation/stringset.h>
26 26
27#include "gmdocument.h" 27#include "gmdocument.h"
28#include "ui/color.h" 28#include "ui/color.h"
@@ -87,6 +87,7 @@ struct Impl_Prefs {
87 int maxCacheSize; /* MB */ 87 int maxCacheSize; /* MB */
88 int maxMemorySize; /* MB */ 88 int maxMemorySize; /* MB */
89 /* Style */ 89 /* Style */
90 iStringSet * disabledFontPacks;
90 iBool fontSmoothing; 91 iBool fontSmoothing;
91 iBool gemtextAnsiEscapes; 92 iBool gemtextAnsiEscapes;
92 iBool monospaceGemini; 93 iBool monospaceGemini;
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 924dc0c4..1aca895c 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -2916,6 +2916,27 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
2916 updateMedia_DocumentWidget_(d); 2916 updateMedia_DocumentWidget_(d);
2917 return iFalse; 2917 return iFalse;
2918 } 2918 }
2919 else if (equal_Command(cmd, "media.fontpack.updated")) {
2920 iMedia *media = pointerLabel_Command(cmd, "media");
2921 if (media == media_GmDocument(d->doc)) {
2922 /*iGmMediaInfo info;
2923 if (info_Media(media,
2924 (iMediaId){ fontpack_MediaType, argU32Label_Command(cmd, "id")},
2925 &info)) {
2926
2927 }*/
2928
2929// findCachedContent_App(<#const iString *url#>, <#iString *mime_out#>, <#iBlock *data_out#>)
2930// setData_Media(media,
2931 }
2932 return iFalse;
2933 }
2934 else if (equal_Command(cmd, "media.fontpack.install")) {
2935 if (pointerLabel_Command(cmd, "media") == media_GmDocument(d->doc)) {
2936 /* TODO: This is ours, we may have a MediaRequest with the data in memory. */
2937 }
2938 return iFalse;
2939 }
2919 else if (equal_Command(cmd, "document.stop") && document_App() == d) { 2940 else if (equal_Command(cmd, "document.stop") && document_App() == d) {
2920 if (cancelRequest_DocumentWidget_(d, iTrue /* navigate back */)) { 2941 if (cancelRequest_DocumentWidget_(d, iTrue /* navigate back */)) {
2921 return iTrue; 2942 return iTrue;
@@ -5169,6 +5190,28 @@ void updateSize_DocumentWidget(iDocumentWidget *d) {
5169 invalidate_DocumentWidget_(d); 5190 invalidate_DocumentWidget_(d);
5170} 5191}
5171 5192
5193iBool findCachedContent_DocumentWidget(const iDocumentWidget *d, const iString *url,
5194 iString *mime_out, iBlock *data_out) {
5195 if (equal_String(d->mod.url, url) && !isRequestOngoing_DocumentWidget(d)) {
5196 /* It's the currently open page. */
5197 set_String(mime_out, &d->sourceMime);
5198 set_Block(data_out, &d->sourceContent);
5199 return iTrue;
5200 }
5201 /* Finished media requests are kept in memory while the page is open. */
5202 iConstForEach(ObjectList, i, d->media) {
5203 const iMediaRequest *mr = i.object;
5204 if (mr->req &&
5205 isFinished_GmRequest(mr->req) &&
5206 equal_String(linkUrl_GmDocument(d->doc, mr->linkId), url)) {
5207 set_String(mime_out, meta_GmRequest(mr->req));
5208 set_Block(data_out, body_GmRequest(mr->req));
5209 return iTrue;
5210 }
5211 }
5212 return iFalse;
5213}
5214
5172iBeginDefineSubclass(DocumentWidget, Widget) 5215iBeginDefineSubclass(DocumentWidget, Widget)
5173 .processEvent = (iAny *) processEvent_DocumentWidget_, 5216 .processEvent = (iAny *) processEvent_DocumentWidget_,
5174 .draw = (iAny *) draw_DocumentWidget_, 5217 .draw = (iAny *) draw_DocumentWidget_,
diff --git a/src/ui/documentwidget.h b/src/ui/documentwidget.h
index 1f2ecfc0..9bfab57a 100644
--- a/src/ui/documentwidget.h
+++ b/src/ui/documentwidget.h
@@ -48,6 +48,9 @@ const iString * bookmarkTitle_DocumentWidget (const iDocumentWidget *);
48const iString * feedTitle_DocumentWidget (const iDocumentWidget *); 48const iString * feedTitle_DocumentWidget (const iDocumentWidget *);
49int documentWidth_DocumentWidget (const iDocumentWidget *); 49int documentWidth_DocumentWidget (const iDocumentWidget *);
50 50
51iBool findCachedContent_DocumentWidget(const iDocumentWidget *, const iString *url,
52 iString *mime_out, iBlock *data_out);
53
51enum iDocumentWidgetSetUrlFlags { 54enum iDocumentWidgetSetUrlFlags {
52 useCachedContentIfAvailable_DocumentWidgetSetUrlFlag = iBit(1), 55 useCachedContentIfAvailable_DocumentWidgetSetUrlFlag = iBit(1),
53 openedFromSidebar_DocumentWidgetSetUrlFlag = iBit(2), 56 openedFromSidebar_DocumentWidgetSetUrlFlag = iBit(2),
diff --git a/src/ui/mediaui.c b/src/ui/mediaui.c
index aa45d73a..ac9475dd 100644
--- a/src/ui/mediaui.c
+++ b/src/ui/mediaui.c
@@ -28,6 +28,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
28#include "paint.h" 28#include "paint.h"
29#include "util.h" 29#include "util.h"
30#include "lang.h" 30#include "lang.h"
31#include "app.h"
31 32
32#include <the_Foundation/path.h> 33#include <the_Foundation/path.h>
33#include <the_Foundation/stringlist.h> 34#include <the_Foundation/stringlist.h>
@@ -281,14 +282,28 @@ void draw_DownloadUI(const iDownloadUI *d, iPaint *p) {
281 282
282/*----------------------------------------------------------------------------------------------*/ 283/*----------------------------------------------------------------------------------------------*/
283 284
285static iMenuItem action_FontpackUI_(const iFontpackUI *d) {
286 if (d->info.isInstalled) {
287 return (iMenuItem){ d->info.isDisabled ? "${media.fontpack.enable}"
288 : close_Icon " ${media.fontpack.disable}",
289 0, 0, format_CStr("media.fontpack.enable arg:%d", d->info.isDisabled) };
290 }
291 return (iMenuItem){ d->info.isInstalled ? close_Icon " ${media.fontpack.disable}"
292 : "${media.fontpack.install}",
293 0, 0,
294 d->info.isInstalled ? "media.fontpack.enable arg:0" : "media.fontpack.install" };
295}
296
284void init_FontpackUI(iFontpackUI *d, const iMedia *media, uint16_t mediaId, iRect bounds) { 297void init_FontpackUI(iFontpackUI *d, const iMedia *media, uint16_t mediaId, iRect bounds) {
285 d->media = media; 298 d->media = media;
286 d->mediaId = mediaId; 299 d->mediaId = mediaId;
300 fontpackInfo_Media(d->media, (iMediaId){ fontpack_MediaType, d->mediaId }, &d->info);
287 d->bounds = bounds; 301 d->bounds = bounds;
288 d->installRect.size = add_I2(measure_Text(uiLabel_FontId, "${media.fontpack.install}").bounds.size, 302 iMenuItem action = action_FontpackUI_(d);
289 muli_I2(gap2_UI, 3)); 303 d->buttonRect.size = add_I2(measure_Text(uiLabel_FontId, action.label).bounds.size,
290 d->installRect.pos.x = right_Rect(d->bounds) - gap_UI - d->installRect.size.x; 304 muli_I2(gap2_UI, 3));
291 d->installRect.pos.y = mid_Rect(d->bounds).y - d->installRect.size.y / 2; 305 d->buttonRect.pos.x = right_Rect(d->bounds) - gap_UI - d->buttonRect.size.x;
306 d->buttonRect.pos.y = mid_Rect(d->bounds).y - d->buttonRect.size.y / 2;
292} 307}
293 308
294iBool processEvent_FontpackUI(iFontpackUI *d, const SDL_Event *ev) { 309iBool processEvent_FontpackUI(iFontpackUI *d, const SDL_Event *ev) {
@@ -296,7 +311,12 @@ iBool processEvent_FontpackUI(iFontpackUI *d, const SDL_Event *ev) {
296 case SDL_MOUSEBUTTONDOWN: 311 case SDL_MOUSEBUTTONDOWN:
297 case SDL_MOUSEBUTTONUP: { 312 case SDL_MOUSEBUTTONUP: {
298 const iInt2 pos = init_I2(ev->button.x, ev->button.y); 313 const iInt2 pos = init_I2(ev->button.x, ev->button.y);
299 if (contains_Rect(d->installRect, pos)) { 314 if (contains_Rect(d->buttonRect, pos)) {
315 if (ev->type == SDL_MOUSEBUTTONUP) {
316 postCommandf_App("%s media:%p mediaid:%u packid:%s",
317 action_FontpackUI_(d).command,
318 d->media, d->mediaId, cstr_String(d->info.packId.id));
319 }
300 return iTrue; 320 return iTrue;
301 } 321 }
302 break; 322 break;
@@ -322,24 +342,22 @@ void draw_FontpackUI(const iFontpackUI *d, iPaint *p) {
322 /* Draw a background box. */ 342 /* Draw a background box. */
323 fillRect_Paint(p, d->bounds, uiBackground_ColorId); 343 fillRect_Paint(p, d->bounds, uiBackground_ColorId);
324 drawRect_Paint(p, d->bounds, uiSeparator_ColorId); 344 drawRect_Paint(p, d->bounds, uiSeparator_ColorId);
325 iFontpackMediaInfo info;
326 fontpackInfo_Media(d->media, (iMediaId){ fontpack_MediaType, d->mediaId }, &info);
327 iInt2 pos = topLeft_Rect(d->bounds); 345 iInt2 pos = topLeft_Rect(d->bounds);
328 const char *checks[] = { "\u2610", "\u2611" }; 346 const char *checks[] = { "\u2610", "\u2611" };
329 draw_Text(uiContentBold_FontId, pos, uiHeading_ColorId, "\"%s\" v%d", 347 draw_Text(uiContentBold_FontId, pos,
330 cstr_String(info.packId.id), info.packId.version); 348 d->info.isDisabled ? uiText_ColorId : uiHeading_ColorId, "\"%s\" v%d",
349 cstr_String(d->info.packId.id), d->info.packId.version);
331 pos.y += lineHeight_Text(uiContentBold_FontId); 350 pos.y += lineHeight_Text(uiContentBold_FontId);
332 draw_Text(uiLabelBold_FontId, pos, uiText_ColorId, "%.1f MB, %d fonts %s %s %s", 351 draw_Text(uiLabelBold_FontId, pos, uiText_ColorId, "%.1f MB, %d fonts %s %s %s",
333 info.sizeInBytes / 1.0e6, size_StringList(info.names), 352 d->info.sizeInBytes / 1.0e6, size_StringList(d->info.names),
334// checks[info.isValid], info.isValid ? "No errors" : "Errors detected", 353// checks[info.isValid], info.isValid ? "No errors" : "Errors detected",
335 checks[info.isInstalled], info.isInstalled ? "Installed" : "Not installed", 354 checks[d->info.isInstalled], d->info.isInstalled ? "Installed" : "Not installed",
336 info.isReadOnly ? "Read-Only" : ""); 355 d->info.isReadOnly ? "Read-Only" : "");
337 pos.y += lineHeight_Text(uiLabelBold_FontId); 356 pos.y += lineHeight_Text(uiLabelBold_FontId);
338 iConstForEach(StringList, i, info.names) { 357 iConstForEach(StringList, i, d->info.names) {
339 drawRange_Text(uiLabel_FontId, pos, uiText_ColorId, range_String(i.value)); 358 drawRange_Text(uiLabel_FontId, pos, uiText_ColorId, range_String(i.value));
340 pos.y += lineHeight_Text(uiLabel_FontId); 359 pos.y += lineHeight_Text(uiLabel_FontId);
341 } 360 }
342 /* Buttons. */ 361 /* Buttons. */
343 drawInlineButton_(p, d->installRect, 362 drawInlineButton_(p, d->buttonRect, action_FontpackUI_(d).label, uiLabel_FontId);
344 "${media.fontpack.install}", uiLabel_FontId);
345} 363}
diff --git a/src/ui/mediaui.h b/src/ui/mediaui.h
index 73de1994..03ea0afc 100644
--- a/src/ui/mediaui.h
+++ b/src/ui/mediaui.h
@@ -22,6 +22,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
22 22
23#pragma once 23#pragma once
24 24
25#include "../media.h"
26
25#include <the_Foundation/rect.h> 27#include <the_Foundation/rect.h>
26#include <SDL_events.h> 28#include <SDL_events.h>
27 29
@@ -46,8 +48,6 @@ void draw_PlayerUI (iPlayerUI *, iPaint *p);
46 48
47/*----------------------------------------------------------------------------------------------*/ 49/*----------------------------------------------------------------------------------------------*/
48 50
49iDeclareType(DocumentWidget)
50iDeclareType(Media)
51iDeclareType(DownloadUI) 51iDeclareType(DownloadUI)
52 52
53struct Impl_DownloadUI { 53struct Impl_DownloadUI {
@@ -67,8 +67,9 @@ iDeclareType(FontpackUI)
67struct Impl_FontpackUI { 67struct Impl_FontpackUI {
68 const iMedia *media; 68 const iMedia *media;
69 uint16_t mediaId; 69 uint16_t mediaId;
70 iFontpackMediaInfo info;
70 iRect bounds; 71 iRect bounds;
71 iRect installRect; 72 iRect buttonRect;
72}; 73};
73 74
74void init_FontpackUI (iFontpackUI *, const iMedia *media, uint16_t mediaId, iRect bounds); 75void init_FontpackUI (iFontpackUI *, const iMedia *media, uint16_t mediaId, iRect bounds);