From ab3ed41e6d6a2f30e781c7202741e066a2b21d7b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jaakko=20Kera=CC=88nen?= jaakko.keranen@iki.fi
Date: Fri, 8 Apr 2022 06:31:47 +0300
Subject: [PATCH 1/1] macOS: Running without windows
Work in progress...
src/app.c | 986 ++++++++++++++++++++++++------------------------
src/ui/keys.c | 2 +-
src/ui/widget.c | 3 +
src/ui/window.c | 17 +-
4 files changed, 515 insertions(+), 493 deletions(-)
diff --git a/src/app.c b/src/app.c
index 3c354438..a6a2a0a2 100644
--- a/src/app.c
+++ b/src/app.c
@@ -1645,19 +1645,21 @@ void processEvents_App(enum iAppEventMode eventMode) {
}
}
#endif
/* Per-window processing. */
iBool wasUsed = iFalse;
listWindows_App_(d, &windows);
iConstForEach(PtrArray, iter, &windows) {
iWindow *window = iter.ptr;
setCurrent_Window(window);
window->lastHover = window->hover;
wasUsed = processEvent_Window(window, &ev);
if (ev.type == SDL_MOUSEMOTION) {
/* Only offered to the frontmost window. */
break;
/* Per-window processing. */
if (!isEmpty_PtrArray(&d->mainWindows)) {
listWindows_App_(d, &windows);
iConstForEach(PtrArray, iter, &windows) {
iWindow *window = iter.ptr;
setCurrent_Window(window);
window->lastHover = window->hover;
wasUsed = processEvent_Window(window, &ev);
if (ev.type == SDL_MOUSEMOTION) {
/* Only offered to the frontmost window. */
break;
}
if (wasUsed) break;
}
if (wasUsed) break;
}
setCurrent_Window(d->window);
if (!wasUsed) {
@@ -1778,7 +1780,14 @@ static int resizeWatcher_(void *user, SDL_Event *event) {
dispatchEvent_Window(as_Window(d->window), &u);
}
#endif
drawWhileResizing_MainWindow(d->window, winev->data1, winev->data2);
/* Find the window that is being resized and redraw it immediately. */
iConstForEach(PtrArray, i, &d->mainWindows) {
const iMainWindow *win = i.ptr;
if (SDL_GetWindowID(win->base.win) == winev->windowID) {
drawWhileResizing_MainWindow(d->window, winev->data1, winev->data2);
break;
}
}
}
return 0;
}
@@ -2051,6 +2060,9 @@ void addWindow_App(iMainWindow *win) {
void removeWindow_App(iMainWindow *win) {
iApp *d = &app_;
removeOne_PtrArray(&d->mainWindows, win);
d->window = NULL;
}
size_t numWindows_App(void) {
@@ -2386,11 +2398,6 @@ void closeWindow_App(iMainWindow *win) {
}
}
}
d->window = NULL;
setActiveWindow_App(NULL);
setCurrent_Window(NULL);
}
static iBool handleIdentityCreationCommands_(iWidget *dlg, const char *cmd) {
@@ -2552,36 +2559,10 @@ static void invalidateCachedDocuments_App_(void) {
}
}
-iBool handleCommand_App(const char *cmd) {
+static iBool handleNonWindowRelatedCommand_App_(iApp *d, const char *cmd) {
const iBool isFrozen = !d->window || d->window->isDrawFrozen;
makeSimpleMessage_Widget(uiTextCaution_ColorEscape "CONFIG ERROR",
format_CStr("Error in config file: %s\n"
"See \"about:debug\" for details.",
suffixPtr_Command(cmd, "where")));
return iTrue;
-#if 0 /* disabled in v1.11 */
/* TODO: Don't use this when system fonts are accessible. */
if (!isInstalled_Fonts("classic-set") && !isInstalled_Fonts("cjk")) {
makeQuestion_Widget(
uiHeading_ColorEscape "${heading.fontpack.classic}",
"${dlg.fontpack.classic.msg}",
(iMenuItem[]){
{ "${cancel}" },
{ uiTextAction_ColorEscape "${dlg.fontpack.classic}",
0,
0,
"!open newtab:1 url:gemini://skyjake.fi/fonts/classic-set.fontpack" } },
2);
}
return iTrue;
-#endif
savePrefs_App_(d);
return iTrue;
}
@@ -2641,28 +2622,6 @@ iBool handleCommand_App(const char *cmd) {
d->prefs.langTo = argLabel_Command(cmd, "to");
return iTrue;
}
if (argLabel_Command(cmd, "swap")) {
swapRoots_MainWindow(d->window);
return iTrue;
}
if (argLabel_Command(cmd, "focusother")) {
iWindow *baseWin = &d->window->base;
if (baseWin->roots[1]) {
baseWin->keyRoot =
(baseWin->keyRoot == baseWin->roots[1] ? baseWin->roots[0] : baseWin->roots[1]);
}
}
d->window->pendingSplitMode =
(argLabel_Command(cmd, "axis") ? vertical_WindowSplit : 0) | (arg_Command(cmd) << 1);
const char *url = suffixPtr_Command(cmd, "url");
setCStr_String(d->window->pendingSplitUrl, url ? url : "");
if (hasLabel_Command(cmd, "origin")) {
set_String(d->window->pendingSplitOrigin, string_Command(cmd, "origin"));
}
postRefresh_App();
return iTrue;
else if (equal_Command(cmd, "window.retain")) {
d->prefs.retainWindowSize = arg_Command(cmd);
return iTrue;
@@ -2671,186 +2630,174 @@ iBool handleCommand_App(const char *cmd) {
d->prefs.customFrame = arg_Command(cmd);
return iTrue;
}
const size_t winIndex = argU32Label_Command(cmd, "index");
if (winIndex < size_PtrArray(&d->mainWindows)) {
iMainWindow *win = at_PtrArray(&d->mainWindows, winIndex);
if (!argLabel_Command(cmd, "toggle")) {
setSnap_MainWindow(win, maximized_WindowSnap);
}
else {
setSnap_MainWindow(
win, snap_MainWindow(win) == maximized_WindowSnap ? 0 : maximized_WindowSnap);
}
}
return iTrue;
const iBool wasFull = snap_MainWindow(d->window) == fullscreen_WindowSnap;
setSnap_MainWindow(d->window, wasFull ? 0 : fullscreen_WindowSnap);
postCommandf_App("window.fullscreen.changed arg:%d", !wasFull);
return iTrue;
else if (equal_Command(cmd, "prefs.retaintabs.changed")) {
d->prefs.retainTabs = arg_Command(cmd);
return iTrue;
}
resetFonts_App();
if (!isFrozen) {
setFreezeDraw_MainWindow(get_MainWindow(), iTrue);
}
d->prefs.fontSmoothing = arg_Command(cmd) != 0;
if (!isFrozen) {
resetFontCache_Text(text_Window(get_MainWindow())); /* clear the glyph cache */
postCommand_App("font.changed");
postCommand_App("window.unfreeze");
}
return iTrue;
}
reload_Fonts(); /* also does font cache reset, window invalidation */
iChangeFlags(d->prefs.gemtextAnsiEscapes, allowFg_AnsiFlag, arg_Command(cmd));
return iTrue;
}
searchOnlineLibraryForCharacters_Fonts(string_Command(cmd, "chars"));
iChangeFlags(d->prefs.gemtextAnsiEscapes, allowBg_AnsiFlag, arg_Command(cmd));
return iTrue;
}
if (hasLabel_Command(cmd, "error")) {
makeSimpleMessage_Widget("${heading.glyphfinder}",
format_CStr("%d %s",
argLabel_Command(cmd, "error"),
suffixPtr_Command(cmd, "msg")));
return iTrue;
}
iString *src = collectNew_String();
setCStr_String(src, "# ${heading.glyphfinder.results}\n\n");
iRangecc path = iNullRange;
iBool isFirst = iTrue;
while (nextSplit_Rangecc(range_Command(cmd, "packs"), ",", &path)) {
if (isFirst) {
appendCStr_String(src, "${glyphfinder.results}\n\n");
}
iRangecc fpath = path;
iRangecc fsize = path;
fpath.end = strchr(fpath.start, ';');
fsize.start = fpath.end + 1;
const uint32_t size = strtoul(fsize.start, NULL, 10);
appendFormat_String(src, "=> gemini://skyjake.fi/fonts/%s %s (%.1f MB)\n",
cstr_Rangecc(fpath),
cstr_Rangecc(fpath),
(double) size / 1.0e6);
isFirst = iFalse;
}
if (isFirst) {
appendFormat_String(src, "${glyphfinder.results.empty}\n");
}
appendCStr_String(src, "\n=> about:fonts ${menu.fonts}");
iDocumentWidget *page = newTab_App(NULL, iTrue);
translate_Lang(src);
setUrlAndSource_DocumentWidget(page,
collectNewCStr_String(""),
collectNewCStr_String("text/gemini"),
utf8_String(src));
iChangeFlags(d->prefs.gemtextAnsiEscapes, allowFontStyle_AnsiFlag, arg_Command(cmd));
return iTrue;
}
equal_Command(cmd, "prefs.mono.gopher.changed")) {
const iBool isSet = (arg_Command(cmd) != 0);
if (!isFrozen) {
setFreezeDraw_MainWindow(get_MainWindow(), iTrue);
}
struct {
const char *label;
enum iPrefsString ps;
int fontId;
} params[] = {
{ "ui", uiFont_PrefsString, default_FontId },
{ "mono", monospaceFont_PrefsString, monospace_FontId },
{ "heading", headingFont_PrefsString, documentHeading_FontId },
{ "body", bodyFont_PrefsString, documentBody_FontId },
{ "monodoc", monospaceDocumentFont_PrefsString, documentMonospace_FontId },
};
iBool wasChanged = iFalse;
iForIndices(i, params) {
if (hasLabel_Command(cmd, params[i].label)) {
iString *ps = &d->prefs.strings[params[i].ps];
const iString *newFont = string_Command(cmd, params[i].label);
if (!equal_String(ps, newFont)) {
set_String(ps, newFont);
wasChanged = iTrue;
}
}
if (startsWith_CStr(cmd, "prefs.mono.gemini")) {
d->prefs.monospaceGemini = isSet;
}
if (wasChanged) {
if (isFinishedLaunching_App()) { /* there's a reset when launch is finished */
resetFonts_Text(text_Window(get_MainWindow()));
}
postCommand_App("font.changed");
else {
d->prefs.monospaceGopher = isSet;
}
if (!isFrozen) {
postCommand_App("font.changed");
postCommand_App("window.unfreeze");
}
return iTrue;
}
if (!isFrozen) {
setFreezeDraw_MainWindow(get_MainWindow(), iTrue); /* no intermediate draws before docs updated */
equal_Command(cmd, "prefs.boldlink.light.changed") ||
equal_Command(cmd, "prefs.boldlink.visited.changed")) {
const iBool isSet = (arg_Command(cmd) != 0);
if (startsWith_CStr(cmd, "prefs.boldlink.visited")) {
d->prefs.boldLinkVisited = isSet;
}
if (arg_Command(cmd) != d->prefs.zoomPercent) {
d->prefs.zoomPercent = arg_Command(cmd);
invalidateCachedDocuments_App_();
else if (startsWith_CStr(cmd, "prefs.boldlink.dark")) {
d->prefs.boldLinkDark = isSet;
}
setDocumentFontSize_Text(text_Window(d->window), (float) d->prefs.zoomPercent / 100.0f);
if (!isFrozen) {
else {
d->prefs.boldLinkLight = isSet;
}
if (!d->isLoadingPrefs) {
postCommand_App("font.changed");
postCommand_App("window.unfreeze");
}
return iTrue;
}
if (!isFrozen) {
setFreezeDraw_MainWindow(get_MainWindow(), iTrue); /* no intermediate draws before docs updated */
}
int delta = arg_Command(cmd);
if (d->prefs.zoomPercent < 100 || (delta < 0 && d->prefs.zoomPercent == 100)) {
delta /= 2;
}
d->prefs.zoomPercent = iClamp(d->prefs.zoomPercent + delta, 50, 200);
invalidateCachedDocuments_App_();
setDocumentFontSize_Text(text_Window(d->window), (float) d->prefs.zoomPercent / 100.0f);
if (!isFrozen) {
postCommand_App("font.changed");
postCommand_App("window.unfreeze");
d->prefs.bigFirstParagraph = arg_Command(cmd) != 0;
if (!d->isLoadingPrefs) {
postCommand_App("document.layout.changed");
}
return iTrue;
}
d->prefs.smoothScrolling = arg_Command(cmd);
d->prefs.justifyParagraph = arg_Command(cmd) != 0;
if (!d->isLoadingPrefs) {
postCommand_App("document.layout.changed");
}
return iTrue;
}
const int type = argLabel_Command(cmd, "type");
if (type == keyboard_ScrollType || type == mouse_ScrollType) {
d->prefs.smoothScrollSpeed[type] = iClamp(arg_Command(cmd), 1, 40);
d->prefs.plainTextWrap = arg_Command(cmd) != 0;
if (!d->isLoadingPrefs) {
postCommand_App("document.layout.changed");
}
return iTrue;
}
d->prefs.decodeUserVisibleURLs = arg_Command(cmd);
d->prefs.sideIcon = arg_Command(cmd) != 0;
postRefresh_App();
return iTrue;
}
d->prefs.loadImageInsteadOfScrolling = arg_Command(cmd);
d->prefs.centerShortDocs = arg_Command(cmd) != 0;
if (!isFrozen) {
invalidate_Window(d->window);
}
return iTrue;
}
d->prefs.hideToolbarOnScroll = arg_Command(cmd);
if (!d->prefs.hideToolbarOnScroll) {
showToolbar_Root(get_Root(), iTrue);
}
d->prefs.collapsePreOnLoad = arg_Command(cmd) != 0;
return iTrue;
}
d->prefs.returnKey = arg_Command(cmd);
d->prefs.hoverLink = arg_Command(cmd) != 0;
postRefresh_App();
return iTrue;
}
d->prefs.pinSplit = arg_Command(cmd);
d->prefs.hoverLink = !d->prefs.hoverLink;
postRefresh_App();
return iTrue;
}
const int isAuto = argLabel_Command(cmd, "auto");
d->prefs.openDataUrlImagesOnLoad = arg_Command(cmd) != 0;
return iTrue;
d->prefs.openArchiveIndexPages = arg_Command(cmd) != 0;
return iTrue;
d->prefs.addBookmarksToBottom = arg_Command(cmd) != 0;
return iTrue;
d->prefs.warnAboutMissingGlyphs = arg_Command(cmd) != 0;
return iTrue;
d->prefs.uiAnimations = arg_Command(cmd) != 0;
return iTrue;
d->prefs.blinkingCursor = arg_Command(cmd) != 0;
return iTrue;
d->prefs.time24h = arg_Command(cmd) != 0;
return iTrue;
d->prefs.smoothScrolling = arg_Command(cmd);
return iTrue;
const int type = argLabel_Command(cmd, "type");
if (type == keyboard_ScrollType || type == mouse_ScrollType) {
d->prefs.smoothScrollSpeed[type] = iClamp(arg_Command(cmd), 1, 40);
}
return iTrue;
d->prefs.decodeUserVisibleURLs = arg_Command(cmd);
return iTrue;
d->prefs.loadImageInsteadOfScrolling = arg_Command(cmd);
return iTrue;
d->prefs.returnKey = arg_Command(cmd);
return iTrue;
d->prefs.pinSplit = arg_Command(cmd);
return iTrue;
const int isAuto = argLabel_Command(cmd, "auto");
d->prefs.theme = arg_Command(cmd);
if (!isAuto) {
if (isDark_ColorTheme(d->prefs.theme) && d->isDarkSystemTheme) {
@@ -2923,246 +2870,426 @@ iBool handleCommand_App(const char *cmd) {
postCommand_App("document.layout.changed redo:1");
return iTrue;
}
d->prefs.gemtextAnsiEscapes = arg_Command(cmd);
return iTrue;
d->prefs.saturation = (float) arg_Command(cmd) / 100.0f;
if (!isFrozen) {
setFreezeDraw_MainWindow(get_MainWindow(), iTrue);
invalidate_Window(d->window);
}
d->prefs.fontSmoothing = arg_Command(cmd) != 0;
if (!isFrozen) {
resetFontCache_Text(text_Window(get_MainWindow())); /* clear the glyph cache */
postCommand_App("font.changed");
postCommand_App("window.unfreeze");
return iTrue;
d->prefs.maxCacheSize = arg_Command(cmd);
if (d->prefs.maxCacheSize <= 0) {
d->prefs.maxCacheSize = 0;
}
return iTrue;
}
d->prefs.gemtextAnsiEscapes = arg_Command(cmd);
d->prefs.maxMemorySize = arg_Command(cmd);
if (d->prefs.maxMemorySize <= 0) {
d->prefs.maxMemorySize = 0;
}
return iTrue;
}
iChangeFlags(d->prefs.gemtextAnsiEscapes, allowFg_AnsiFlag, arg_Command(cmd));
d->prefs.maxUrlSize = arg_Command(cmd);
if (d->prefs.maxUrlSize < 1024) {
d->prefs.maxUrlSize = 1024; /* Gemini protocol requirement */
}
return iTrue;
}
iChangeFlags(d->prefs.gemtextAnsiEscapes, allowBg_AnsiFlag, arg_Command(cmd));
iString *url = &d->prefs.strings[searchUrl_PrefsString];
setCStr_String(url, suffixPtr_Command(cmd, "address"));
if (startsWith_String(url, "//")) {
prependCStr_String(url, "gemini:");
}
if (!isEmpty_String(url) && !startsWithCase_String(url, "gemini://")) {
prependCStr_String(url, "gemini://");
}
return iTrue;
}
iChangeFlags(d->prefs.gemtextAnsiEscapes, allowFontStyle_AnsiFlag, arg_Command(cmd));
setCStr_String(&d->prefs.strings[geminiProxy_PrefsString], suffixPtr_Command(cmd, "address"));
return iTrue;
}
equal_Command(cmd, "prefs.mono.gopher.changed")) {
const iBool isSet = (arg_Command(cmd) != 0);
if (!isFrozen) {
setFreezeDraw_MainWindow(get_MainWindow(), iTrue);
setCStr_String(&d->prefs.strings[gopherProxy_PrefsString], suffixPtr_Command(cmd, "address"));
return iTrue;
setCStr_String(&d->prefs.strings[httpProxy_PrefsString], suffixPtr_Command(cmd, "address"));
return iTrue;
+#if defined (LAGRANGE_ENABLE_DOWNLOAD_EDIT)
setCStr_String(&d->prefs.strings[downloadDir_PrefsString], suffixPtr_Command(cmd, "path"));
return iTrue;
+#endif
postCommandf_App("open newtab:%d url:%s",
argLabel_Command(cmd, "newtab"),
cstrCollect_String(makeFileUrl_String(downloadDir_App())));
return iTrue;
setCStr_String(&d->prefs.strings[caFile_PrefsString], suffixPtr_Command(cmd, "path"));
if (!argLabel_Command(cmd, "noset")) {
setCACertificates_TlsRequest(&d->prefs.strings[caFile_PrefsString], &d->prefs.strings[caPath_PrefsString]);
}
if (startsWith_CStr(cmd, "prefs.mono.gemini")) {
d->prefs.monospaceGemini = isSet;
return iTrue;
setCStr_String(&d->prefs.strings[caPath_PrefsString], suffixPtr_Command(cmd, "path"));
if (!argLabel_Command(cmd, "noset")) {
setCACertificates_TlsRequest(&d->prefs.strings[caFile_PrefsString], &d->prefs.strings[caPath_PrefsString]);
}
else {
d->prefs.monospaceGopher = isSet;
return iTrue;
const int newTab = argLabel_Command(cmd, "newtab");
const iString *query = collect_String(suffix_Command(cmd, "query"));
if (!isLikelyUrl_String(query)) {
const iString *url = searchQueryUrl_App(query);
if (!isEmpty_String(url)) {
postCommandf_App("open newtab:%d url:%s", newTab, cstr_String(url));
}
}
if (!isFrozen) {
postCommand_App("font.changed");
postCommand_App("window.unfreeze");
else {
postCommandf_App("open newtab:%d url:%s", newTab, cstr_String(query));
}
return iTrue;
}
equal_Command(cmd, "prefs.boldlink.light.changed") ||
equal_Command(cmd, "prefs.boldlink.visited.changed")) {
const iBool isSet = (arg_Command(cmd) != 0);
if (startsWith_CStr(cmd, "prefs.boldlink.visited")) {
d->prefs.boldLinkVisited = isSet;
}
else if (startsWith_CStr(cmd, "prefs.boldlink.dark")) {
d->prefs.boldLinkDark = isSet;
const iString *path = NULL;
if (hasLabel_Command(cmd, "path")) {
path = suffix_Command(cmd, "path");
}
else {
d->prefs.boldLinkLight = isSet;
else if (hasLabel_Command(cmd, "url")) {
path = collect_String(localFilePathFromUrl_String(suffix_Command(cmd, "url")));
}
if (!d->isLoadingPrefs) {
postCommand_App("font.changed");
if (path) {
revealPath_App(path);
}
return iTrue;
}
d->prefs.bigFirstParagraph = arg_Command(cmd) != 0;
if (!d->isLoadingPrefs) {
postCommand_App("document.layout.changed");
iMainWindow *newWin = new_MainWindow(initialWindowRect_App_(d, numWindows_App()));
addWindow_App(newWin); /* takes ownership */
SDL_ShowWindow(newWin->base.win);
setCurrent_Window(newWin);
if (hasLabel_Command(cmd, "url")) {
postCommandf_Root(newWin->base.roots[0], "~open %s", cmd + 11 /* all arguments passed on */);
}
else {
postCommand_Root(newWin->base.roots[0], "~navigate.home");
}
postCommand_Root(newWin->base.roots[0], "~window.unfreeze");
return iTrue;
}
d->prefs.justifyParagraph = arg_Command(cmd) != 0;
if (!d->isLoadingPrefs) {
postCommand_App("document.layout.changed");
save_Bookmarks(d->bookmarks, dataDir_App_());
return iFalse;
sort_Bookmarks(d->bookmarks, arg_Command(cmd), cmpTitleAscending_Bookmark);
postCommand_App("bookmarks.changed");
return iTrue;
fetchRemote_Bookmarks(bookmarks_App());
return iTrue;
requestFinished_Bookmarks(bookmarks_App(), pointerLabel_Command(cmd, "req"));
return iTrue;
refresh_Feeds();
return iTrue;
save_Visited(d->visited, dataDir_App_());
return iFalse;
saveIdentities_GmCerts(d->certs);
return iFalse;
const iString *url = collect_String(suffix_Command(cmd, "url"));
signIn_GmCerts(
d->certs,
findIdentity_GmCerts(d->certs, collect_Block(hexDecode_Rangecc(range_Command(cmd, "ident")))),
url);
postCommand_App("navigate.reload");
postCommand_App("idents.changed");
return iTrue;
iGmIdentity *ident = findIdentity_GmCerts(
d->certs, collect_Block(hexDecode_Rangecc(range_Command(cmd, "ident"))));
if (arg_Command(cmd)) {
clearUse_GmIdentity(ident);
}
else {
setUse_GmIdentity(ident, collect_String(suffix_Command(cmd, "url")), iFalse);
}
postCommand_App("navigate.reload");
postCommand_App("idents.changed");
return iTrue;
}
d->prefs.plainTextWrap = arg_Command(cmd) != 0;
if (!d->isLoadingPrefs) {
postCommand_App("document.layout.changed");
const int dark = argLabel_Command(cmd, "dark");
d->isDarkSystemTheme = dark;
if (d->prefs.useSystemTheme) {
const int contrast = argLabel_Command(cmd, "contrast");
const int preferred = d->prefs.systemPreferredColorTheme[dark ^ 1];
postCommandf_App("theme.set arg:%d auto:1",
preferred >= 0 ? preferred
: dark ? (contrast ? pureBlack_ColorTheme : dark_ColorTheme)
: (contrast ? pureWhite_ColorTheme : light_ColorTheme));
}
return iFalse;
checkNow_Updater();
return iTrue;
}
d->prefs.sideIcon = arg_Command(cmd) != 0;
postRefresh_App();
const iString *packId = collect_String(suffix_Command(cmd, "id"));
enablePack_Fonts(packId, arg_Command(cmd));
postCommand_App("navigate.reload");
return iTrue;
}
d->prefs.centerShortDocs = arg_Command(cmd) != 0;
if (!isFrozen) {
invalidate_Window(d->window);
+#if defined (LAGRANGE_ENABLE_IPC)
iProcessId pid = argLabel_Command(cmd, "pid");
if (pid) {
iString *urls = collectNew_String();
iConstForEach(ObjectList, i, iClob(listDocuments_App(NULL))) {
append_String(urls, url_DocumentWidget(i.object));
appendCStr_String(urls, "\n");
}
write_Ipc(pid, urls, response_IpcWrite);
}
return iTrue;
}
d->prefs.collapsePreOnLoad = arg_Command(cmd) != 0;
write_Ipc(argLabel_Command(cmd, "pid"),
collectNewFormat_String(
"%s\n", d->window ? cstr_String(url_DocumentWidget(document_App())) : ""),
response_IpcWrite);
return iTrue;
}
d->prefs.hoverLink = arg_Command(cmd) != 0;
postRefresh_App();
if (argLabel_Command(cmd, "raise")) {
if (d->window && d->window->base.win) {
SDL_RaiseWindow(d->window->base.win);
}
}
signal_Ipc(arg_Command(cmd));
return iTrue;
}
d->prefs.hoverLink = !d->prefs.hoverLink;
postRefresh_App();
return iTrue;
+#endif /* defined (LAGRANGE_ENABLE_IPC) */
SDL_Event ev;
ev.type = SDL_QUIT;
SDL_PushEvent(&ev);
}
d->prefs.openDataUrlImagesOnLoad = arg_Command(cmd) != 0;
+}
+iBool handleCommand_App(const char *cmd) {
return iTrue;
}
d->prefs.openArchiveIndexPages = arg_Command(cmd) != 0;
/* All the subsequent commands assume that a window exists. */
return iFalse;
makeSimpleMessage_Widget(uiTextCaution_ColorEscape "CONFIG ERROR",
format_CStr("Error in config file: %s\n"
"See \"about:debug\" for details.",
suffixPtr_Command(cmd, "where")));
return iTrue;
}
d->prefs.addBookmarksToBottom = arg_Command(cmd) != 0;
if (argLabel_Command(cmd, "swap")) {
swapRoots_MainWindow(d->window);
return iTrue;
}
if (argLabel_Command(cmd, "focusother")) {
iWindow *baseWin = &d->window->base;
if (baseWin->roots[1]) {
baseWin->keyRoot =
(baseWin->keyRoot == baseWin->roots[1] ? baseWin->roots[0] : baseWin->roots[1]);
}
}
d->window->pendingSplitMode =
(argLabel_Command(cmd, "axis") ? vertical_WindowSplit : 0) | (arg_Command(cmd) << 1);
const char *url = suffixPtr_Command(cmd, "url");
setCStr_String(d->window->pendingSplitUrl, url ? url : "");
if (hasLabel_Command(cmd, "origin")) {
set_String(d->window->pendingSplitOrigin, string_Command(cmd, "origin"));
}
postRefresh_App();
return iTrue;
}
d->prefs.warnAboutMissingGlyphs = arg_Command(cmd) != 0;
const size_t winIndex = argU32Label_Command(cmd, "index");
if (winIndex < size_PtrArray(&d->mainWindows)) {
iMainWindow *win = at_PtrArray(&d->mainWindows, winIndex);
if (!argLabel_Command(cmd, "toggle")) {
setSnap_MainWindow(win, maximized_WindowSnap);
}
else {
setSnap_MainWindow(
win, snap_MainWindow(win) == maximized_WindowSnap ? 0 : maximized_WindowSnap);
}
}
return iTrue;
}
d->prefs.uiAnimations = arg_Command(cmd) != 0;
const iBool wasFull = snap_MainWindow(d->window) == fullscreen_WindowSnap;
setSnap_MainWindow(d->window, wasFull ? 0 : fullscreen_WindowSnap);
postCommandf_App("window.fullscreen.changed arg:%d", !wasFull);
return iTrue;
}
d->prefs.blinkingCursor = arg_Command(cmd) != 0;
resetFonts_App();
return iTrue;
}
d->prefs.time24h = arg_Command(cmd) != 0;
reload_Fonts(); /* also does font cache reset, window invalidation */
return iTrue;
}
d->prefs.saturation = (float) arg_Command(cmd) / 100.0f;
if (!isFrozen) {
invalidate_Window(d->window);
}
searchOnlineLibraryForCharacters_Fonts(string_Command(cmd, "chars"));
return iTrue;
}
d->prefs.maxCacheSize = arg_Command(cmd);
if (d->prefs.maxCacheSize <= 0) {
d->prefs.maxCacheSize = 0;
if (hasLabel_Command(cmd, "error")) {
makeSimpleMessage_Widget("${heading.glyphfinder}",
format_CStr("%d %s",
argLabel_Command(cmd, "error"),
suffixPtr_Command(cmd, "msg")));
return iTrue;
}
iString *src = collectNew_String();
setCStr_String(src, "# ${heading.glyphfinder.results}\n\n");
iRangecc path = iNullRange;
iBool isFirst = iTrue;
while (nextSplit_Rangecc(range_Command(cmd, "packs"), ",", &path)) {
if (isFirst) {
appendCStr_String(src, "${glyphfinder.results}\n\n");
}
iRangecc fpath = path;
iRangecc fsize = path;
fpath.end = strchr(fpath.start, ';');
fsize.start = fpath.end + 1;
const uint32_t size = strtoul(fsize.start, NULL, 10);
appendFormat_String(src, "=> gemini://skyjake.fi/fonts/%s %s (%.1f MB)\n",
cstr_Rangecc(fpath),
cstr_Rangecc(fpath),
(double) size / 1.0e6);
isFirst = iFalse;
}
if (isFirst) {
appendFormat_String(src, "${glyphfinder.results.empty}\n");
}
appendCStr_String(src, "\n=> about:fonts ${menu.fonts}");
iDocumentWidget *page = newTab_App(NULL, iTrue);
translate_Lang(src);
setUrlAndSource_DocumentWidget(page,
collectNewCStr_String(""),
collectNewCStr_String("text/gemini"),
utf8_String(src));
return iTrue;
}
d->prefs.maxMemorySize = arg_Command(cmd);
if (d->prefs.maxMemorySize <= 0) {
d->prefs.maxMemorySize = 0;
if (!isFrozen) {
setFreezeDraw_MainWindow(get_MainWindow(), iTrue);
}
return iTrue;
d->prefs.maxUrlSize = arg_Command(cmd);
if (d->prefs.maxUrlSize < 1024) {
d->prefs.maxUrlSize = 1024; /* Gemini protocol requirement */
struct {
const char *label;
enum iPrefsString ps;
int fontId;
} params[] = {
{ "ui", uiFont_PrefsString, default_FontId },
{ "mono", monospaceFont_PrefsString, monospace_FontId },
{ "heading", headingFont_PrefsString, documentHeading_FontId },
{ "body", bodyFont_PrefsString, documentBody_FontId },
{ "monodoc", monospaceDocumentFont_PrefsString, documentMonospace_FontId },
};
iBool wasChanged = iFalse;
iForIndices(i, params) {
if (hasLabel_Command(cmd, params[i].label)) {
iString *ps = &d->prefs.strings[params[i].ps];
const iString *newFont = string_Command(cmd, params[i].label);
if (!equal_String(ps, newFont)) {
set_String(ps, newFont);
wasChanged = iTrue;
}
}
}
return iTrue;
iString *url = &d->prefs.strings[searchUrl_PrefsString];
setCStr_String(url, suffixPtr_Command(cmd, "address"));
if (startsWith_String(url, "//")) {
prependCStr_String(url, "gemini:");
if (wasChanged) {
if (isFinishedLaunching_App()) { /* there's a reset when launch is finished */
resetFonts_Text(text_Window(get_MainWindow()));
}
postCommand_App("font.changed");
}
if (!isEmpty_String(url) && !startsWithCase_String(url, "gemini://")) {
prependCStr_String(url, "gemini://");
if (!isFrozen) {
postCommand_App("window.unfreeze");
}
return iTrue;
}
setCStr_String(&d->prefs.strings[geminiProxy_PrefsString], suffixPtr_Command(cmd, "address"));
return iTrue;
setCStr_String(&d->prefs.strings[gopherProxy_PrefsString], suffixPtr_Command(cmd, "address"));
return iTrue;
setCStr_String(&d->prefs.strings[httpProxy_PrefsString], suffixPtr_Command(cmd, "address"));
return iTrue;
-#if defined (LAGRANGE_ENABLE_DOWNLOAD_EDIT)
setCStr_String(&d->prefs.strings[downloadDir_PrefsString], suffixPtr_Command(cmd, "path"));
return iTrue;
-#endif
postCommandf_App("open newtab:%d url:%s",
argLabel_Command(cmd, "newtab"),
cstrCollect_String(makeFileUrl_String(downloadDir_App())));
return iTrue;
setCStr_String(&d->prefs.strings[caFile_PrefsString], suffixPtr_Command(cmd, "path"));
if (!argLabel_Command(cmd, "noset")) {
setCACertificates_TlsRequest(&d->prefs.strings[caFile_PrefsString], &d->prefs.strings[caPath_PrefsString]);
if (!isFrozen) {
setFreezeDraw_MainWindow(get_MainWindow(), iTrue); /* no intermediate draws before docs updated */
}
return iTrue;
setCStr_String(&d->prefs.strings[caPath_PrefsString], suffixPtr_Command(cmd, "path"));
if (!argLabel_Command(cmd, "noset")) {
setCACertificates_TlsRequest(&d->prefs.strings[caFile_PrefsString], &d->prefs.strings[caPath_PrefsString]);
if (arg_Command(cmd) != d->prefs.zoomPercent) {
d->prefs.zoomPercent = arg_Command(cmd);
invalidateCachedDocuments_App_();
}
setDocumentFontSize_Text(text_Window(d->window), (float) d->prefs.zoomPercent / 100.0f);
if (!isFrozen) {
postCommand_App("font.changed");
postCommand_App("window.unfreeze");
}
return iTrue;
}
const int newTab = argLabel_Command(cmd, "newtab");
const iString *query = collect_String(suffix_Command(cmd, "query"));
if (!isLikelyUrl_String(query)) {
const iString *url = searchQueryUrl_App(query);
if (!isEmpty_String(url)) {
postCommandf_App("open newtab:%d url:%s", newTab, cstr_String(url));
}
if (!isFrozen) {
setFreezeDraw_MainWindow(get_MainWindow(), iTrue); /* no intermediate draws before docs updated */
}
else {
postCommandf_App("open newtab:%d url:%s", newTab, cstr_String(query));
int delta = arg_Command(cmd);
if (d->prefs.zoomPercent < 100 || (delta < 0 && d->prefs.zoomPercent == 100)) {
delta /= 2;
}
d->prefs.zoomPercent = iClamp(d->prefs.zoomPercent + delta, 50, 200);
invalidateCachedDocuments_App_();
setDocumentFontSize_Text(text_Window(d->window), (float) d->prefs.zoomPercent / 100.0f);
if (!isFrozen) {
postCommand_App("font.changed");
postCommand_App("window.unfreeze");
}
return iTrue;
}
const iString *path = NULL;
if (hasLabel_Command(cmd, "path")) {
path = suffix_Command(cmd, "path");
}
else if (hasLabel_Command(cmd, "url")) {
path = collect_String(localFilePathFromUrl_String(suffix_Command(cmd, "url")));
}
if (path) {
revealPath_App(path);
d->prefs.hideToolbarOnScroll = arg_Command(cmd);
if (!d->prefs.hideToolbarOnScroll) {
showToolbar_Root(get_Root(), iTrue);
}
return iTrue;
}
@@ -3337,20 +3464,6 @@ iBool handleCommand_App(const char *cmd) {
#endif
return iFalse;
}
iMainWindow *newWin = new_MainWindow(initialWindowRect_App_(d, numWindows_App()));
addWindow_App(newWin); /* takes ownership */
SDL_ShowWindow(newWin->base.win);
setCurrent_Window(newWin);
if (hasLabel_Command(cmd, "url")) {
postCommandf_Root(newWin->base.roots[0], "~open %s", cmd + 11 /* all arguments passed on */);
}
else {
postCommand_Root(newWin->base.roots[0], "~navigate.home");
}
postCommand_Root(newWin->base.roots[0], "~window.unfreeze");
return iTrue;
else if (equal_Command(cmd, "tabs.new")) {
const iBool isDuplicate = argLabel_Command(cmd, "duplicate") != 0;
newTab_App(isDuplicate ? document_App() : NULL, iTrue);
@@ -3411,12 +3524,16 @@ iBool handleCommand_App(const char *cmd) {
}
}
}
+#if defined (iPlatformAppleDesktop)
closeWindow_App(d->window);
+#else
else if (numWindows_App() > 1) {
closeWindow_App(d->window);
}
else {
postCommand_App("quit");
}
+#endif
return iTrue;
}
else if (equal_Command(cmd, "keyroot.next")) {
@@ -3426,11 +3543,6 @@ iBool handleCommand_App(const char *cmd) {
}
return iTrue;
}
SDL_Event ev;
ev.type = SDL_QUIT;
SDL_PushEvent(&ev);
else if (equal_Command(cmd, "preferences")) {
iWidget *dlg = makePreferences_Widget();
updatePrefsThemeButtons_(dlg);
@@ -3618,27 +3730,6 @@ iBool handleCommand_App(const char *cmd) {
}
return iTrue;
}
sort_Bookmarks(d->bookmarks, arg_Command(cmd), cmpTitleAscending_Bookmark);
postCommand_App("bookmarks.changed");
return iTrue;
fetchRemote_Bookmarks(bookmarks_App());
return iTrue;
requestFinished_Bookmarks(bookmarks_App(), pointerLabel_Command(cmd, "req"));
return iTrue;
save_Bookmarks(d->bookmarks, dataDir_App_());
return iFalse;
refresh_Feeds();
return iTrue;
else if (startsWith_CStr(cmd, "feeds.update.")) {
const iWidget *navBar = findChild_Widget(get_Window()->roots[0]->widget, "navbar");
iAnyObject *prog = findChild_Widget(navBar, "feeds.progress");
@@ -3663,10 +3754,6 @@ iBool handleCommand_App(const char *cmd) {
}
return iFalse;
}
save_Visited(d->visited, dataDir_App_());
return iFalse;
else if (equal_Command(cmd, "document.changed")) {
/* Set of open tabs has changed. */
postCommand_App("document.openurls.changed");
@@ -3691,29 +3778,6 @@ iBool handleCommand_App(const char *cmd) {
postRefresh_App();
return iTrue;
}
const iString *url = collect_String(suffix_Command(cmd, "url"));
signIn_GmCerts(
d->certs,
findIdentity_GmCerts(d->certs, collect_Block(hexDecode_Rangecc(range_Command(cmd, "ident")))),
url);
postCommand_App("navigate.reload");
postCommand_App("idents.changed");
return iTrue;
iGmIdentity *ident = findIdentity_GmCerts(
d->certs, collect_Block(hexDecode_Rangecc(range_Command(cmd, "ident"))));
if (arg_Command(cmd)) {
clearUse_GmIdentity(ident);
}
else {
setUse_GmIdentity(ident, collect_String(suffix_Command(cmd, "url")), iFalse);
}
postCommand_App("navigate.reload");
postCommand_App("idents.changed");
return iTrue;
else if (equal_Command(cmd, "ident.switch")) {
/* This is different than "ident.signin" in that the currently used identity's activation
URL is used instead of the current one. */
@@ -3733,33 +3797,6 @@ iBool handleCommand_App(const char *cmd) {
}
return iTrue;
}
saveIdentities_GmCerts(d->certs);
return iFalse;
const int dark = argLabel_Command(cmd, "dark");
d->isDarkSystemTheme = dark;
if (d->prefs.useSystemTheme) {
const int contrast = argLabel_Command(cmd, "contrast");
const int preferred = d->prefs.systemPreferredColorTheme[dark ^ 1];
postCommandf_App("theme.set arg:%d auto:1",
preferred >= 0 ? preferred
: dark ? (contrast ? pureBlack_ColorTheme : dark_ColorTheme)
: (contrast ? pureWhite_ColorTheme : light_ColorTheme));
}
return iFalse;
checkNow_Updater();
return iTrue;
const iString *packId = collect_String(suffix_Command(cmd, "id"));
enablePack_Fonts(packId, arg_Command(cmd));
postCommand_App("navigate.reload");
return iTrue;
else if (equal_Command(cmd, "fontpack.delete")) {
const iString *packId = collect_String(suffix_Command(cmd, "id"));
if (isEmpty_String(packId)) {
@@ -3840,35 +3877,6 @@ iBool handleCommand_App(const char *cmd) {
}
return iTrue;
}
-#if defined (LAGRANGE_ENABLE_IPC)
iProcessId pid = argLabel_Command(cmd, "pid");
if (pid) {
iString *urls = collectNew_String();
iConstForEach(ObjectList, i, iClob(listDocuments_App(NULL))) {
append_String(urls, url_DocumentWidget(i.object));
appendCStr_String(urls, "\n");
}
write_Ipc(pid, urls, response_IpcWrite);
}
return iTrue;
write_Ipc(argLabel_Command(cmd, "pid"),
collectNewFormat_String("%s\n", cstr_String(url_DocumentWidget(document_App()))),
response_IpcWrite);
return iTrue;
if (argLabel_Command(cmd, "raise")) {
if (d->window && d->window->base.win) {
SDL_RaiseWindow(d->window->base.win);
}
}
signal_Ipc(arg_Command(cmd));
return iTrue;
-#endif /* defined (LAGRANGE_ENABLE_IPC) */
else {
return iFalse;
}
diff --git a/src/ui/keys.c b/src/ui/keys.c
index 3428bcc8..40859f7c 100644
--- a/src/ui/keys.c
+++ b/src/ui/keys.c
@@ -451,7 +451,7 @@ void setLabel_Keys(int id, const char *label) {
iBool processEvent_Keys(const SDL_Event *ev) {
iKeys *d = &keys_;
if (ev->type == SDL_KEYDOWN || ev->type == SDL_KEYUP) {
const iBinding *bind = find_Keys_(d, ev->key.keysym.sym, keyMods_Sym(ev->key.keysym.mod));
if (bind) {
diff --git a/src/ui/widget.c b/src/ui/widget.c
index cb373c43..138b219e 100644
--- a/src/ui/widget.c
+++ b/src/ui/widget.c
@@ -2154,6 +2154,9 @@ static const iWidget *findFocusRoot_Widget_(const iWidget *d) {
}
iAny *findFocusable_Widget(const iWidget *startFrom, enum iWidgetFocusDir focusDir) {
return NULL;
iRoot *uiRoot = (startFrom ? startFrom->root : get_Window()->keyRoot);
const iWidget *focusRoot = findFocusRoot_Widget_(uiRoot->widget);
iAssert(focusRoot != NULL);
diff --git a/src/ui/window.c b/src/ui/window.c
index cbfd0f5c..2ec64f0e 100644
--- a/src/ui/window.c
+++ b/src/ui/window.c
@@ -186,22 +186,32 @@ const iMenuItem topLevelMenus_Window[6] = {
#if defined (LAGRANGE_MAC_MENUBAR)
+static iBool macMenusInserted_;
static void insertMacMenus_(void) {
return;
insertMenuItems_MacOS("${menu.title.file}", 1, fileMenuItems_, iElemCount(fileMenuItems_));
insertMenuItems_MacOS("${menu.title.edit}", 2, editMenuItems_, iElemCount(editMenuItems_));
insertMenuItems_MacOS("${menu.title.view}", 3, viewMenuItems_, iElemCount(viewMenuItems_));
insertMenuItems_MacOS("${menu.title.bookmarks}", 4, bookmarksMenuItems_, iElemCount(bookmarksMenuItems_));
insertMenuItems_MacOS("${menu.title.identity}", 5, identityMenuItems_, iElemCount(identityMenuItems_));
insertMenuItems_MacOS("${menu.title.help}", 7, helpMenuItems_, iElemCount(helpMenuItems_));
}
static void removeMacMenus_(void) {
return;
removeMenu_MacOS(7);
removeMenu_MacOS(5);
removeMenu_MacOS(4);
removeMenu_MacOS(3);
removeMenu_MacOS(2);
removeMenu_MacOS(1);
}
#endif /* LAGRANGE_MAC_MENUBAR */
@@ -246,9 +256,7 @@ static void windowSizeChanged_MainWindow_(iMainWindow *d) {
static void setupUserInterface_MainWindow(iMainWindow *d) {
#if defined (LAGRANGE_MAC_MENUBAR)
insertMacMenus_(); /* TODO: Shouldn't this be in the App? */
#endif
/* One root is created by default. */
d->base.roots[0] = new_Root();
@@ -1652,6 +1660,9 @@ void setKeyboardHeight_MainWindow(iMainWindow *d, int height) {
iObjectList *listDocuments_MainWindow(iMainWindow *d, const iRoot *rootOrNull) {
iObjectList *docs = new_ObjectList();
return docs;
iForIndices(i, d->base.roots) {
iRoot *root = d->base.roots[i];
if (!root) continue;
--
2.25.1
text/plain
This content has been proxied by September (ba2dc).