diff --git a/po/en.po b/po/en.po

index 476ed3f1..cc4a765d 100644

--- a/po/en.po

+++ b/po/en.po

@@ -2639,4 +2639,38 @@ msgstr "Content:"

msgid "snip.accept"

msgstr "Save Snippet"



+# Keyboard shortcut for the terminal. Should be very short or abbreviated.

+msgid "term.url"

+msgstr "Enter URL"



+# Keyboard shortcut for the terminal. Should be very short or abbreviated.

+msgid "term.linkkeys"

+msgstr "Open link"

+

+# Keyboard shortcut for the terminal. Should be very short or abbreviated.

+msgid "term.menu"

+msgstr "Context menu"

+

+# Keyboard shortcut for the terminal. Should be very short or abbreviated.

+msgid "term.menubar"

+msgstr "Menubar"

+

+# Keyboard shortcut for the terminal. Should be very short or abbreviated.

+msgid "term.sidebar"

+msgstr "Sidebar"

+

+# Keyboard shortcut for the terminal. Should be very short or abbreviated.

+msgid "term.tab.new"

+msgstr "New tab"

+

+# Keyboard shortcut for the terminal. Should be very short or abbreviated.

+msgid "term.tab.close"

+msgstr "Close tab"

+

+# Keyboard shortcut for the terminal. Should be very short or abbreviated.

+msgid "term.hover"

+msgstr "Focus link"

+

+# Keyboard shortcut for the terminal. Should be very short or abbreviated.

+msgid "term.focus"

+msgstr "Focus"

diff --git a/res/lang/cs.bin b/res/lang/cs.bin

index 11b3db07..69e51914 100644

Binary files a/res/lang/cs.bin and b/res/lang/cs.bin differ

diff --git a/res/lang/de.bin b/res/lang/de.bin

index de4474ad..f30fc5a9 100644

Binary files a/res/lang/de.bin and b/res/lang/de.bin differ

diff --git a/res/lang/en.bin b/res/lang/en.bin

index 0f65af65..8bbb2026 100644

Binary files a/res/lang/en.bin and b/res/lang/en.bin differ

diff --git a/res/lang/eo.bin b/res/lang/eo.bin

index ab5944c7..857dfe5d 100644

Binary files a/res/lang/eo.bin and b/res/lang/eo.bin differ

diff --git a/res/lang/es.bin b/res/lang/es.bin

index 845a1738..395f14fb 100644

Binary files a/res/lang/es.bin and b/res/lang/es.bin differ

diff --git a/res/lang/es_MX.bin b/res/lang/es_MX.bin

index a89c6e88..7faaa660 100644

Binary files a/res/lang/es_MX.bin and b/res/lang/es_MX.bin differ

diff --git a/res/lang/eu.bin b/res/lang/eu.bin

index 6a4aebfc..8b27e451 100644

Binary files a/res/lang/eu.bin and b/res/lang/eu.bin differ

diff --git a/res/lang/fi.bin b/res/lang/fi.bin

index 05a48ac9..3f1b14f0 100644

Binary files a/res/lang/fi.bin and b/res/lang/fi.bin differ

diff --git a/res/lang/fr.bin b/res/lang/fr.bin

index e770bade..26241003 100644

Binary files a/res/lang/fr.bin and b/res/lang/fr.bin differ

diff --git a/res/lang/gl.bin b/res/lang/gl.bin

index 65e28044..018f8641 100644

Binary files a/res/lang/gl.bin and b/res/lang/gl.bin differ

diff --git a/res/lang/hu.bin b/res/lang/hu.bin

index 35bb3d0d..c368d0fa 100644

Binary files a/res/lang/hu.bin and b/res/lang/hu.bin differ

diff --git a/res/lang/ia.bin b/res/lang/ia.bin

index df40df5e..764728a6 100644

Binary files a/res/lang/ia.bin and b/res/lang/ia.bin differ

diff --git a/res/lang/ie.bin b/res/lang/ie.bin

index 56fffd51..b803de9f 100644

Binary files a/res/lang/ie.bin and b/res/lang/ie.bin differ

diff --git a/res/lang/isv.bin b/res/lang/isv.bin

index 44ab74aa..4a223ab5 100644

Binary files a/res/lang/isv.bin and b/res/lang/isv.bin differ

diff --git a/res/lang/it.bin b/res/lang/it.bin

index aafc26ba..ed8d0f77 100644

Binary files a/res/lang/it.bin and b/res/lang/it.bin differ

diff --git a/res/lang/ja.bin b/res/lang/ja.bin

index 324318b3..39bedf71 100644

Binary files a/res/lang/ja.bin and b/res/lang/ja.bin differ

diff --git a/res/lang/nl.bin b/res/lang/nl.bin

index ed6507ca..3b6718b3 100644

Binary files a/res/lang/nl.bin and b/res/lang/nl.bin differ

diff --git a/res/lang/pl.bin b/res/lang/pl.bin

index 0323b8f1..2ea179ba 100644

Binary files a/res/lang/pl.bin and b/res/lang/pl.bin differ

diff --git a/res/lang/ru.bin b/res/lang/ru.bin

index a0775e00..a7725824 100644

Binary files a/res/lang/ru.bin and b/res/lang/ru.bin differ

diff --git a/res/lang/sk.bin b/res/lang/sk.bin

index 11041074..6414aec7 100644

Binary files a/res/lang/sk.bin and b/res/lang/sk.bin differ

diff --git a/res/lang/sr.bin b/res/lang/sr.bin

index 4bdc4370..8d206933 100644

Binary files a/res/lang/sr.bin and b/res/lang/sr.bin differ

diff --git a/res/lang/tok.bin b/res/lang/tok.bin

index 44647694..8b500280 100644

Binary files a/res/lang/tok.bin and b/res/lang/tok.bin differ

diff --git a/res/lang/tr.bin b/res/lang/tr.bin

index c9a52449..34e69087 100644

Binary files a/res/lang/tr.bin and b/res/lang/tr.bin differ

diff --git a/res/lang/uk.bin b/res/lang/uk.bin

index 21504e85..b58b82dd 100644

Binary files a/res/lang/uk.bin and b/res/lang/uk.bin differ

diff --git a/res/lang/zh_Hans.bin b/res/lang/zh_Hans.bin

index e278e641..be83359f 100644

Binary files a/res/lang/zh_Hans.bin and b/res/lang/zh_Hans.bin differ

diff --git a/res/lang/zh_Hant.bin b/res/lang/zh_Hant.bin

index fbb33027..83010daa 100644

Binary files a/res/lang/zh_Hant.bin and b/res/lang/zh_Hant.bin differ

diff --git a/src/app.c b/src/app.c

index a5e417d2..c4b07d44 100644

--- a/src/app.c

+++ b/src/app.c

@@ -2784,7 +2784,7 @@ iBool moveFocusInsideMenu_App(const void *sdlEvent) {

         }

         return iTrue;

     }

- else {

+ else if (menu) {

         setCurrent_Window(window_Widget(focus_Widget()));

         postCommand_Widget(focus_Widget(), "cancel");

     }

diff --git a/src/defs.h b/src/defs.h

index bc5e0b95..3746acb0 100644

--- a/src/defs.h

+++ b/src/defs.h

@@ -332,6 +332,10 @@ iLocalDef int acceptKeyMod_ReturnKeyBehavior(int behavior) {

define LAGRANGE_MENUBAR

#endif



+#if defined (iPlatformDesktop) && !defined (iPlatformTerminal)

+# define LAGRANGE_MULTIPLE_WINDOWS

+#endif

+

/* UI labels that depend on the platform */



#if defined (iPlatformMobile)

diff --git a/src/ui/certlistwidget.c b/src/ui/certlistwidget.c

index 9da7fe6a..dbaefeb1 100644

--- a/src/ui/certlistwidget.c

+++ b/src/ui/certlistwidget.c

@@ -120,7 +120,7 @@ static void updateContextMenu_CertListWidget_(iCertListWidget *d) {

         insert_Array(items, insertPos++, &(iMenuItem){ "---", 0, 0, NULL });

     }

     iBool usedOnCurrentPage = iFalse;

- iConstForEach(StringSet, i, ident->useUrls) { 

+ iConstForEach(StringSet, i, ident->useUrls) {

         const iString *url = i.value;

         usedOnCurrentPage |= startsWithCase_String(docUrl, cstr_String(url));

         iRangecc urlStr = range_String(url);

@@ -141,8 +141,8 @@ static void updateContextMenu_CertListWidget_(iCertListWidget *d) {

         remove_Array(items, firstIndex);

     }

 }

- destroy_Widget(d->menu); 

- d->menu = makeMenu_Widget(as_Widget(d), data_Array(items), size_Array(items)); 

+ destroy_Widget(d->menu);

+ d->menu = makeMenu_Widget(as_Widget(d), data_Array(items), size_Array(items));

}



static void itemClicked_CertListWidget_(iCertListWidget *d, iCertItem *item, size_t itemIndex) {

@@ -180,7 +180,7 @@ static iBool processEvent_CertListWidget_(iCertListWidget *d, const SDL_Event *e

         return iTrue;

     }

     else if (isCommand_Widget(w, ev, "ident.use")) {

- iGmIdentity *ident = menuIdentity_CertListWidget_(d); 

+ iGmIdentity *ident = menuIdentity_CertListWidget_(d);

         const iString *tabUrl = urlQueryStripped_String(url_DocumentWidget(document_App()));

         if (ident) {

             if (argLabel_Command(cmd, "clear")) {

@@ -217,7 +217,16 @@ static iBool processEvent_CertListWidget_(iCertListWidget *d, const SDL_Event *e

         if (ident) {

             const iString *fps = collect_String(

                 hexEncode_Block(collect_Block(fingerprint_TlsCertificate(ident->cert))));

- SDL_SetClipboardText(cstr_String(fps));

+ if (isTerminal_Platform()) {

+ makeMessage_Widget(

+ "${ident.fingerprint}",

+ cstr_String(fps),

+ (iMenuItem[]){ { "${dlg.message.ok}", SDLK_RETURN, 0, "message.ok" } },

+ 1);

+ }

+ else {

+ SDL_SetClipboardText(cstr_String(fps));

+ }

         }

         return iTrue;

     }

@@ -303,7 +312,7 @@ static iBool processEvent_CertListWidget_(iCertListWidget *d, const SDL_Event *e

             invalidateItem_ListWidget(&d->list, d->contextIndex);

         }

         d->contextIndex = hoverItemIndex_ListWidget(&d->list);

- updateContextMenu_CertListWidget_(d); 

+ updateContextMenu_CertListWidget_(d);

         /* TODO: Some callback-based mechanism would be nice for updating menus right

            before they open? At least move these to `updateContextMenu_ */

         const iGmIdentity *ident  = constHoverIdentity_CertListWidget(d);

@@ -365,7 +374,7 @@ static void draw_CertItem_(const iCertItem *d, iPaint *p, iRect itemRect,

     bg = uiBackgroundUnfocusedSelection_ColorId;

     fillRect_Paint(p, itemRect, bg);

 }

-// iInt2 pos = itemRect.pos; 

+// iInt2 pos = itemRect.pos;

 const int fg = isHover ? (isPressing ? uiTextPressed_ColorId : uiTextFramelessHover_ColorId)

                        : uiTextStrong_ColorId;

 const iBool isUsedOnDomain = (d->indent != 0);

diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c

index d48a2fcd..1a547fa7 100644

--- a/src/ui/documentwidget.c

+++ b/src/ui/documentwidget.c

@@ -3154,7 +3154,17 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)

 else if (equal_Command(cmd, "server.copycert") && document_App() == d) {

     const iString *fp = collect_String(

         hexEncode_Block(arg_Command(cmd) ? d->certFullFingerprint : d->certFingerprint));

- SDL_SetClipboardText(cstr_String(fp));

+ if (isTerminal_Platform()) {

+ makeMessage_Widget(

+ arg_Command(cmd) ? "${dlg.cert.fingerprint.full}"

+ : "${dlg.cert.fingerprint.pubkey}",

+ cstr_String(fp),

+ (iMenuItem[]){ { "${dlg.message.ok}", SDLK_RETURN, 0, "message.ok" } },

+ 1);

+ }

+ else {

+ SDL_SetClipboardText(cstr_String(fp));

+ }

     return iTrue;

 }

 else if (equal_Command(cmd, "copy") && document_App() == d && !focus_Widget()) {

diff --git a/src/ui/inputwidget.c b/src/ui/inputwidget.c

index 66201119..355486de 100644

--- a/src/ui/inputwidget.c

+++ b/src/ui/inputwidget.c

@@ -396,7 +396,7 @@ static iRect contentBounds_InputWidget_(const iInputWidget *d) {

 iRect          bounds = adjusted_Rect(bounds_Widget(w),

                              addX_I2(padding_(), d->leftPadding),

                              neg_I2(addX_I2(padding_(), d->rightPadding)));

- shrink_Rect(&bounds, init_I2(gap_UI * (flags_Widget(w) & tight_WidgetFlag ? 1 : 2), 0));

+ shrink_Rect(&bounds, init_I2(gap_UI * (flags_Widget(w) & tight_WidgetFlag ? 1 : 2) * aspect_UI, 0));

 bounds.pos.y += padding_().y / 2;

 if (flags_Widget(w) & extraPadding_WidgetFlag) {

     if (d->sysCtrl && !cmp_String(id_Widget(w), "url")) {

diff --git a/src/ui/root.c b/src/ui/root.c

index ddba9aa2..22289366 100644

--- a/src/ui/root.c

+++ b/src/ui/root.c

@@ -415,6 +415,64 @@ static iBool isBookmarkFolder_(void *context, const iBookmark *bm) {

 return isFolder_Bookmark(bm);

}



+static size_t visibleSize_String(const iString *d) {

+ size_t n = 0;

+ iConstForEach(String, i, d) {

+ if (i.value == '\v') {

+ next_StringConstIterator(&i); /* skip escape */

+ continue;

+ }

+ n += width_Char(i.value);

+ }

+ return n;

+}

+

+static void formatShortcut_(iString *d, int maxLen, const char *label, int key, int mods) {

+ iString str;

+ init_String(&str);

+ iString keyStr;

+ init_String(&keyStr);

+ toString_Sym(key, mods, &keyStr);

+ if (!isEmpty_String(d)) {

+ appendCStr_String(&str, " ");

+ }

+ appendFormat_String(&str,

+ "%s%s%s %s",

+ escape_Color(uiTextShortcut_ColorId),

+ cstr_String(&keyStr),

+ uiText_ColorEscape,

+ label);

+ if (visibleSize_String(d) + visibleSize_String(&str) <= maxLen) {

+ append_String(d, &str);

+ }

+ deinit_String(&keyStr);

+ deinit_String(&str);

+}

+

+static void updateTerminalStatus_(iLabelWidget *term) {

+ const iBinding *bind;

+ iString *str = new_String();

+ const int maxLen = width_Widget(root_Widget(as_Widget(term))) - 2;

+ formatShortcut_(str, maxLen, "${term.url}", SDLK_RETURN, 0);

+ bind = findCommand_Keys("document.linkkeys arg:1");

+ formatShortcut_(str, maxLen, "${term.linkkeys}", bind->key, bind->mods);

+ bind = findCommand_Keys("contextkey");

+ formatShortcut_(str, maxLen, "${term.menu}", bind->key, bind->mods);

+ bind = findCommand_Keys("menubar.focus");

+ formatShortcut_(str, maxLen, "${term.menubar}", bind->key, bind->mods);

+ formatShortcut_(str, maxLen, "${cancel}", 'g', KMOD_CTRL);

+ formatShortcut_(str, maxLen, "${term.focus}", SDLK_TAB, 0);

+ formatShortcut_(str, maxLen, "${term.sidebar}", leftSidebar_KeyShortcut);

+ bind = findCommand_Keys("tabs.new append:1");

+ formatShortcut_(str, maxLen, "${term.tab.new}", bind->key, bind->mods);

+ bind = findCommand_Keys("tabs.close");

+ formatShortcut_(str, maxLen, "${term.tab.close}", bind->key, bind->mods);

+ bind = findCommand_Keys("document.linkkeys arg:1 hover:1");

+ formatShortcut_(str, maxLen, "${term.hover}", bind->key, bind->mods);

+ updateText_LabelWidget(term, str);

+ delete_String(str);

+}

+

iBool handleRootCommands_Widget(iWidget *root, const char *cmd) {

 iUnused(root);

 if (equal_Command(cmd, "menu.open")) {

@@ -527,9 +585,26 @@ iBool handleRootCommands_Widget(iWidget *root, const char *cmd) {

     if (menubar) {

         setFocus_Widget(child_Widget(menubar, prefs_App()->recentMenuBarIndex));

         postCommand_Widget(focus_Widget(), "trigger");

+ if (isTerminal_Platform()) {

+ setFlags_Widget(findChild_Widget(root, "termstatus"), hidden_WidgetFlag, iTrue);

+ }

     }

     return iTrue;

 }

+ else if (isTerminal_Platform() && equal_Command(cmd, "focus.gained")) {

+ if (!cmp_String(id_Widget(parent_Widget(focus_Widget())), "menubar")) {

+ setFlags_Widget(findChild_Widget(root, "termstatus"), hidden_WidgetFlag, iTrue);

+ }

+ return iFalse;

+ }

+ else if (isTerminal_Platform() && equal_Command(cmd, "menu.closed")) {

+ if (!focus_Widget()) {

+ iLabelWidget *status = findChild_Widget(root, "termstatus");

+ setFlags_Widget(as_Widget(status), hidden_WidgetFlag, iFalse);

+ updateTerminalStatus_(status);

+ }

+ return iFalse;

+ }

 else if (equal_Command(cmd, "input.resized")) {

     /* No parent handled this, so do a full rearrangement. */

     /* TODO: Defer this and do a single rearrangement later. */

@@ -591,6 +666,9 @@ iBool handleRootCommands_Widget(iWidget *root, const char *cmd) {

     return iTrue;

 }

 else if (equal_Command(cmd, "window.resized")) {

+ if (isTerminal_Platform()) {

+ updateTerminalStatus_(findWidget_Root("termstatus"));

+ }

     iSidebarWidget *sidebar = findChild_Widget(root, "sidebar");

     iSidebarWidget *sidebar2 = findChild_Widget(root, "sidebar2");

     if (deviceType_App() != phone_AppDeviceType) {

@@ -889,7 +967,7 @@ static void updateUrlInputContentPadding_(iWidget *navBar) {

 const int indicatorsWidth = width_Widget(findChild_Widget(navBar, "url.rightembed"));

 /* The indicators widget has a padding that covers the urlButtons area. */

 setContentPadding_InputWidget(url,

- lockWidth - 2 * gap_UI, // * 0.75f,

+ isTerminal_Platform() ? lockWidth : (lockWidth - 2 * gap_UI),

                               indicatorsWidth);

}



@@ -1490,6 +1568,8 @@ void updateMetrics_Root(iRoot *d) {

     setFixedSize_Widget(appIcon, init_I2(appIconSize_Root(), appMin->rect.size.y));

 }

 iWidget      *navBar     = findChild_Widget(d->widget, "navbar");

+ iWidget *menuBar = findChild_Widget(d->widget, "menubar");

+ iWidget *termStatus = findChild_Widget(d->widget, "termstatus");

 iWidget      *url        = findChild_Widget(d->widget, "url");

 iWidget      *rightEmbed = findChild_Widget(navBar, "url.rightembed");

 iWidget      *embedPad   = findChild_Widget(navBar, "url.embedpad");

@@ -1505,6 +1585,9 @@ void updateMetrics_Root(iRoot *d) {

 if (navBar) {

     updateUrlInputContentPadding_(navBar);

 }

+ if (termStatus) {

+ setFixedSize_Widget(menuBar, menuBar->rect.size);

+ }

 if (idName) {

     setFixedSize_Widget(as_Widget(idName),

                         init_I2(-1, 2 * gap_UI + lineHeight_Text(uiLabelTiny_FontId)));

@@ -1534,8 +1617,9 @@ static iBool updateWindowMenu_(iWidget *menuBarItem, const char *cmd) {

     /* Remove the old dynamic window list items first. See `windowMenuItems_` in window.c

        for the fixed list. */

     iWidget *menu = findChild_Widget(menuBarItem, "menu");

- while (childCount_Widget(menu) > 9) {

- destroy_Widget(removeChild_Widget(menu, child_Widget(menu, 9)));

+ const size_t numFixedItems = numWindowMenuItems_Window() + 1;

+ while (childCount_Widget(menu) > numFixedItems) {

+ destroy_Widget(removeChild_Widget(menu, child_Widget(menu, numFixedItems)));

     }

     iArray winItems;

     init_Array(&winItems, sizeof(iMenuItem));

@@ -1736,16 +1820,19 @@ void createUserInterface_Root(iRoot *d) {

     /* TODO: Use Widget's `updateMenuItems` callback. */

     setCommandHandler_Widget(child_Widget(menuBar, 5), updateWindowMenu_);

     setId_Widget(menuBar, "menubar");

-# if 0

- addChildFlags_Widget(menuBar, iClob(new_Widget()), expand_WidgetFlag);

- /* It's nice to use this space for something, but it should be more valuable than

- just the app version... */

- iLabelWidget *ver = addChildFlags_Widget(menuBar, iClob(new_LabelWidget(LAGRANGE_APP_VERSION, NULL)),

- frameless_WidgetFlag);

- setTextColor_LabelWidget(ver, uiAnnotation_ColorId);

-# endif

 }

#endif

+ /* Terminal status/help indicator. */

+ if (isTerminal_Platform()) {

+ iWidget *termStatus =

+ addChildFlags_Widget(div,

+ iClob(new_LabelWidget("", NULL)),

+ fixedPosition_WidgetFlag | fixedHeight_WidgetFlag |

+ resizeToParentWidth_WidgetFlag);

+ setBackgroundColor_Widget(termStatus, uiBackground_ColorId);

+ updateTerminalStatus_((iLabelWidget *) termStatus);

+ setId_Widget(termStatus, "termstatus");

+ }

 iWidget *navBar;

 /* Navigation bar. */ {

     navBar = new_Widget();

diff --git a/src/ui/util.c b/src/ui/util.c

index 4c2c3bf8..3cacc019 100644

--- a/src/ui/util.c

+++ b/src/ui/util.c

@@ -2783,10 +2783,14 @@ static iBool messageHandler_(iWidget *msg, const char *cmd) {

       equal_Command(cmd, "theme.changed") ||

       equal_Command(cmd, "focus.lost") ||

       equal_Command(cmd, "focus.gained") ||

+ equal_Command(cmd, "menu.open") ||

+ equal_Command(cmd, "menu.opened") ||

       equal_Command(cmd, "menu.closed") ||

+ startsWith_CStr(cmd, "cancel menu:") ||

       startsWith_CStr(cmd, "feeds.update.") ||

       startsWith_CStr(cmd, "window."))) {

- //printf("message dismissed by: %s\n", cmd); fflush(stdout);

+ // printf("message dismissed by: %s\n", cmd); fflush(stdout);

+ // SDL_Delay(5000);

     setupSheetTransition_Mobile(msg, dialogTransitionDir_Widget(msg));

     destroy_Widget(msg);

 }

@@ -3994,6 +3998,9 @@ const iArray *makeBookmarkFolderActions_MenuItem(const char *command, iBool with

}



void enableResizing_Widget(iWidget *d, int minWidth, const char *resizeId) {

+ if (isTerminal_Platform()) {

+ return; /* cannot grab edges */

+ }

 if (deviceType_App() == desktop_AppDeviceType) {

     iChangeFlags(d->flags, arrangeWidth_WidgetFlag, iFalse);

     d->flags2 |= horizontallyResizable_WidgetFlag2;

@@ -4138,7 +4145,7 @@ iWidget *makeBookmarkEditor_Widget(uint32_t folderId, iBool withDup) {

         addDialogToggle_(headings, values, "${bookmark.tag.linksplit}:", "bmed.tag.linksplit");

     }

     arrange_Widget(dlg);

- const int inputWidth = 100 * gap_UI - headings->rect.size.x;

+ const int inputWidth = iMin(100 * gap_UI, width_Rect(rect_Root(dlg->root))) - headings->rect.size.x;

     for (int i = 0; i < 4; ++i) {

         if (inputs[i]) {

             as_Widget(inputs[i])->rect.size.x = inputWidth;

Proxy Information
Original URL
gemini://git.skyjake.fi/lagrange/dev/pcdiff/852cc782f198e250ba30f8b3974a39a66cbd1164
Status Code
Success (20)
Meta
text/plain
Capsule Response Time
29.496878 milliseconds
Gemini-to-HTML Time
14.404086 milliseconds

This content has been proxied by September (ba2dc).