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

index bff4c495..6647324e 100644

--- a/po/en.po

+++ b/po/en.po

@@ -148,6 +148,9 @@ msgstr "Identity"

msgid "menu.title.help"

msgstr "Help"



+msgid "menu.newwindow"

+msgstr "New Window"

+

msgid "menu.newtab"

msgstr "New Tab"



@@ -519,9 +522,6 @@ msgstr "%b. %d, %Y"

msgid "feeds.today"

msgstr "Today"



-msgid "feeds.entry.newtab"

-msgstr "Open Entry in New Tab"

-

msgid "feeds.entry.markread"

msgstr "Mark as Read"



@@ -558,6 +558,9 @@ msgstr "Open in New Tab"

msgid "menu.opentab.background"

msgstr "Open in Background Tab"



+msgid "menu.openwindow"

+msgstr "Open in New Window"

+

msgid "menu.openfile"

msgstr "Open File…"



@@ -870,6 +873,9 @@ msgstr "Open Link to the Side"

msgid "link.side.newtab"

msgstr "Open Link in New Tab to the Side"



+msgid "link.newwindow"

+msgstr "Open Link in New Window"

+

msgid "link.browser"

msgstr "Open Link in Default Browser"



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

index 010c6d74..543467ef 100644

--- a/src/app.c

+++ b/src/app.c

@@ -1878,7 +1878,7 @@ void postCommand_Root(iRoot *d, const char *command) {

 ev.user.data2 = d; /* all events are root-specific */

 ev.user.windowID = d ? id_Window(d->window) : 0; /* root-specific means window-specific */

 SDL_PushEvent(&ev);

- iWindow *win = get_Window();

+ iWindow *win = d ? d->window : NULL;

#if defined (iPlatformAndroid)

 SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "%s[command] {%d} %s",

             app_.isLoadingPrefs ? "[Prefs] " : "",

@@ -1979,6 +1979,13 @@ size_t windowIndex_App(const iMainWindow *win) {

 return indexOf_PtrArray(&app_.mainWindows, win); 

}



+iMainWindow *newMainWindow_App(void) {

+ iApp *d = &app_;

+ iMainWindow *win = new_MainWindow(initialWindowRect_App_(d, size_PtrArray(&d->mainWindows)));

+ addWindow_App(win);

+ return win;

+}

+

const iPtrArray *mainWindows_App(void) {

 return &app_.mainWindows;

}

@@ -3038,7 +3045,18 @@ iBool handleCommand_App(const char *cmd) {

         return iTrue; /* invalid command */

     }

     if (findWidget_App("prefs")) {

- postCommand_App("prefs.dismiss"); 

+ postCommand_App("prefs.dismiss");

+ }

+ if (argLabel_Command(cmd, "newwindow")) {

+ const iRangecc gotoheading = range_Command(cmd, "gotoheading");

+ const iRangecc gotourlheading = range_Command(cmd, "gotourlheading");

+ postCommandf_Root(get_Root(), "window.new%s%s%s%s url:%s",

+ isEmpty_Range(&gotoheading) ? "" : " gotoheading:",

+ isEmpty_Range(&gotoheading) ? "" : cstr_Rangecc(gotoheading),

+ isEmpty_Range(&gotourlheading) ? "" : " gotourlheading:",

+ isEmpty_Range(&gotourlheading) ? "" : cstr_Rangecc(gotourlheading),

+ urlArg);

+ return iTrue;

     }

     iString    *url     = collectNewCStr_String(urlArg);

     const iBool noProxy = argLabel_Command(cmd, "noproxy") != 0;

@@ -3187,7 +3205,12 @@ iBool handleCommand_App(const char *cmd) {

     addWindow_App(newWin); /* takes ownership */

     SDL_ShowWindow(newWin->base.win);

     setCurrent_Window(newWin);

- postCommand_Root(newWin->base.roots[0], "~navigate.home");

+ 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;

 }

@@ -3745,21 +3768,7 @@ void revealPath_App(const iString *path) {

}



iObjectList *listDocuments_App(const iRoot *rootOrNull) {

- iWindow *win = get_Window();

- iObjectList *docs = new_ObjectList();

- iForIndices(i, win->roots) {

- iRoot *root = win->roots[i];

- if (!root) continue;

- if (!rootOrNull || root == rootOrNull) {

- const iWidget *tabs = findChild_Widget(root->widget, "doctabs");

- iForEach(ObjectList, i, children_Widget(findChild_Widget(tabs, "tabs.pages"))) {

- if (isInstance_Object(i.object, &Class_DocumentWidget)) {

- pushBack_ObjectList(docs, i.object);

- }

- }

- }

- }

- return docs;

+ return listDocuments_MainWindow(get_MainWindow(), rootOrNull);

}



iStringSet *listOpenURLs_App(void) {

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

index 63a477a5..5f7b506f 100644

--- a/src/app.h

+++ b/src/app.h

@@ -129,6 +129,7 @@ void setActiveWindow_App (iMainWindow *win);

void closeWindow_App (iMainWindow *win);

size_t numWindows_App (void);

size_t windowIndex_App (const iMainWindow *win);

+iMainWindow *newMainWindow_App (void);

const iPtrArray *mainWindows_App(void);

void addPopup_App (iWindow *popup);

void removePopup_App (iWindow *popup);

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

index be5280fa..c3480bc2 100644

--- a/src/defs.h

+++ b/src/defs.h

@@ -157,8 +157,9 @@ iLocalDef int acceptKeyMod_ReturnKeyBehavior(int behavior) {

#define bookmark_Icon "\U0001f516"

#define folder_Icon "\U0001f4c1"

#define file_Icon "\U0001f5ce"

-#define openTab_Icon "\u2750"

-#define openTabBg_Icon "\u2b1a"

+#define openWindow_Icon "\u2b1a" //"\U0001F5d4"

+#define openTab_Icon add_Icon

+#define openTabBg_Icon "\u2750" //"\u2b1a"

#define openExt_Icon "\u27a0"

#define add_Icon "\u2795"

#define page_Icon "\U00010117"

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

index e862b18a..b32722ac 100644

--- a/src/gmutil.c

+++ b/src/gmutil.c

@@ -780,7 +780,7 @@ iRangecc mediaTypeWithoutParameters_Rangecc(iRangecc mime) {

 return part;

}



-const iString *feedEntryOpenCommand_String(const iString *url, int newTab) {

+const iString *feedEntryOpenCommand_String(const iString *url, int newTab, int newWindow) {

 if (!isEmpty_String(url)) {

     iString *cmd = collectNew_String();

     const size_t fragPos = indexOf_String(url, '#');

@@ -788,15 +788,20 @@ const iString *feedEntryOpenCommand_String(const iString *url, int newTab) {

         iString *head = newRange_String(

             (iRangecc){ constBegin_String(url) + fragPos + 1, constEnd_String(url) });

         format_String(cmd,

- "open fromsidebar:1 newtab:%d gotourlheading:%s url:%s",

+ "open fromsidebar:1 newtab:%d newwindow:%d gotourlheading:%s url:%s",

                       newTab,

+ newWindow,

                       cstr_String(head),

                       cstr_Rangecc((iRangecc){ constBegin_String(url),

                                                constBegin_String(url) + fragPos }));

         delete_String(head);

     }

     else {

- format_String(cmd, "open fromsidebar:1 newtab:%d url:%s", newTab, cstr_String(url));

+ format_String(cmd,

+ "open fromsidebar:1 newtab:%d newwindow:%d url:%s",

+ newTab,

+ newWindow,

+ cstr_String(url));

     }

     return cmd;

 }

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

index 01eb8e52..e4284cfd 100644

--- a/src/gmutil.h

+++ b/src/gmutil.h

@@ -151,4 +151,4 @@ iRangecc mediaTypeWithoutParameters_Rangecc (iRangecc mime);

const iString * findContainerArchive_Path (const iString *path);





-const iString * feedEntryOpenCommand_String (const iString url, int newTab); / checks fragment */

+const iString * feedEntryOpenCommand_String (const iString url, int newTab, int newWindow); / checks fragment */

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

index 76c26e27..99039ff5 100644

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

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

@@ -5071,10 +5071,9 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e

             iArray items;

             init_Array(&items, sizeof(iMenuItem));

             if (d->contextLink) {

- /* Context menu for a link. */

+ /* Construct the link context menu, depending on what kind of link was clicked. */

                 interactingWithLink_DocumentWidget_(d, d->contextLink->linkId); /* perhaps will be triggered */

                 const iString *linkUrl  = linkUrl_GmDocument(view->doc, d->contextLink->linkId);

-// const int linkFlags = linkFlags_GmDocument(d->doc, d->contextLink->linkId);

                 const iRangecc scheme   = urlScheme_String(linkUrl);

                 const iBool    isGemini = equalCase_Rangecc(scheme, "gemini");

                 iBool          isNative = iFalse;

@@ -5086,39 +5085,48 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e

                         format_CStr("```%s", cstr_String(infoText)),

                         0, 0, NULL });

                 }

- if (willUseProxy_App(scheme) || isGemini ||

+ if (isGemini ||

+ willUseProxy_App(scheme) ||

+ equalCase_Rangecc(scheme, "data") ||

                     equalCase_Rangecc(scheme, "file") ||

                     equalCase_Rangecc(scheme, "finger") ||

                     equalCase_Rangecc(scheme, "gopher")) {

                     isNative = iTrue;

                     /* Regular links that we can open. */

- pushBackN_Array(

- &items,

- (iMenuItem[]){ { openTab_Icon " ${link.newtab}",

- 0,

- 0,

- format_CStr("!open newtab:1 origin:%s url:%s",

- cstr_String(id_Widget(w)),

- cstr_String(linkUrl)) },

- { openTabBg_Icon " ${link.newtab.background}",

- 0,

- 0,

- format_CStr("!open newtab:2 origin:%s url:%s",

- cstr_String(id_Widget(w)),

- cstr_String(linkUrl)) },

- { "${link.side}",

- 0,

- 0,

- format_CStr("!open newtab:4 origin:%s url:%s",

- cstr_String(id_Widget(w)),

- cstr_String(linkUrl)) },

- { "${link.side.newtab}",

- 0,

- 0,

- format_CStr("!open newtab:5 origin:%s url:%s",

- cstr_String(id_Widget(w)),

- cstr_String(linkUrl)) } },

- 4);

+ pushBackN_Array(&items,

+ (iMenuItem[]){

+ { openTab_Icon " ${link.newtab}",

+ 0,

+ 0,

+ format_CStr("!open newtab:1 origin:%s url:%s",

+ cstr_String(id_Widget(w)),

+ cstr_String(linkUrl)) },

+ { openTabBg_Icon " ${link.newtab.background}",

+ 0,

+ 0,

+ format_CStr("!open newtab:2 origin:%s url:%s",

+ cstr_String(id_Widget(w)),

+ cstr_String(linkUrl)) },

+ { "${link.side}",

+ 0,

+ 0,

+ format_CStr("!open newtab:4 origin:%s url:%s",

+ cstr_String(id_Widget(w)),

+ cstr_String(linkUrl)) },

+ { "${link.side.newtab}",

+ 0,

+ 0,

+ format_CStr("!open newtab:5 origin:%s url:%s",

+ cstr_String(id_Widget(w)),

+ cstr_String(linkUrl)) },

+ { openWindow_Icon " ${link.newwindow}",

+ 0,

+ 0,

+ format_CStr("!open newwindow:1 origin:%s url:%s",

+ cstr_String(id_Widget(w)),

+ cstr_String(linkUrl)) },

+ },

+ 5);

                     if (deviceType_App() == phone_AppDeviceType) {

                         removeN_Array(&items, size_Array(&items) - 2, iInvalidSize);

                     }

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

index f14170ad..dc3264a2 100644

--- a/src/ui/lookupwidget.c

+++ b/src/ui/lookupwidget.c

@@ -568,7 +568,7 @@ static void presentResults_LookupWidget_(iLookupWidget *d) {

                           cstr_String(&res->label),

                           uiText_ColorEscape,

                           cstr_String(&res->meta));

- const iString *cmd = feedEntryOpenCommand_String(&res->url, 0);

+ const iString *cmd = feedEntryOpenCommand_String(&res->url, 0, 0);

             if (cmd) {

                 set_String(&item->command, cmd);

             }

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

index 7e4b4863..9dee50ae 100644

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

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

@@ -56,7 +56,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

#if defined (iPlatformPcDesktop)

/* TODO: Submenus wouldn't hurt here. */

static const iMenuItem navMenuItems_[] = {

- { add_Icon " ${menu.newtab}", 't', KMOD_PRIMARY, "tabs.new" },

+ { openWindow_Icon " ${menu.newwindow}", SDLK_n, KMOD_PRIMARY, "window.new" },

+ { add_Icon " ${menu.newtab}", SDLK_t, KMOD_PRIMARY, "tabs.new" },

 { "${menu.openlocation}", SDLK_l, KMOD_PRIMARY, "navigate.focus" },

 { "---" },

 { download_Icon " " saveToDownloads_Label, SDLK_s, KMOD_PRIMARY, "document.save" },

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

index 73023a4f..0322b2a9 100644

--- a/src/ui/sidebarwidget.c

+++ b/src/ui/sidebarwidget.c

@@ -414,9 +414,13 @@ static void updateItemsWithFlags_SidebarWidget_(iSidebarWidget *d, iBool keepAct

         }

         d->menu = makeMenu_Widget(

             as_Widget(d),

- (iMenuItem[]){ { openTab_Icon " ${feeds.entry.newtab}", 0, 0, "feed.entry.opentab" },

+ (iMenuItem[]){ { openTab_Icon " ${menu.opentab}", 0, 0, "feed.entry.open newtab:1" },

+ { openTabBg_Icon " ${menu.opentab.background}", 0, 0, "feed.entry.open newtab:2" },

+ { openWindow_Icon " ${menu.openwindow}", 0, 0, "feed.entry.open newwindow:1" },

+ { "---", 0, 0, NULL },

                            { circle_Icon " ${feeds.entry.markread}", 0, 0, "feed.entry.toggleread" },

                            { bookmark_Icon " ${feeds.entry.bookmark}", 0, 0, "feed.entry.bookmark" },

+ { "${menu.copyurl}", 0, 0, "feed.entry.copyurl" },

                            { "---", 0, 0, NULL },

                            { page_Icon " ${feeds.entry.openfeed}", 0, 0, "feed.entry.openfeed" },

                            { edit_Icon " ${feeds.edit}", 0, 0, "feed.entry.edit" },

@@ -424,7 +428,7 @@ static void updateItemsWithFlags_SidebarWidget_(iSidebarWidget *d, iBool keepAct

                            { "---", 0, 0, NULL },

                            { check_Icon " ${feeds.markallread}", SDLK_a, KMOD_SHIFT, "feeds.markallread" },

                            { reload_Icon " ${feeds.refresh}", SDLK_r, KMOD_PRIMARY | KMOD_SHIFT, "feeds.refresh" } },

- 10);

+ 13);

         d->modeMenu = makeMenu_Widget(

             as_Widget(d),

             (iMenuItem[]){

@@ -491,6 +495,7 @@ static void updateItemsWithFlags_SidebarWidget_(iSidebarWidget *d, iBool keepAct

             as_Widget(d),

             (iMenuItem[]){ { openTab_Icon " ${menu.opentab}", 0, 0, "bookmark.open newtab:1" },

                            { openTabBg_Icon " ${menu.opentab.background}", 0, 0, "bookmark.open newtab:2" },

+ { openWindow_Icon " ${menu.openwindow}", 0, 0, "bookmark.open newwindow:1" },

                            { "---", 0, 0, NULL },

                            { edit_Icon " ${menu.edit}", 0, 0, "bookmark.edit" },

                            { copy_Icon " ${menu.dup}", 0, 0, "bookmark.dup" },

@@ -502,11 +507,11 @@ static void updateItemsWithFlags_SidebarWidget_(iSidebarWidget *d, iBool keepAct

                            { "---", 0, 0, NULL },

                            { delete_Icon " " uiTextCaution_ColorEscape "${bookmark.delete}", 0, 0, "bookmark.delete" },

                            { "---", 0, 0, NULL },

- { add_Icon " ${menu.newfolder}", 0, 0, "bookmark.addfolder" },

+ { folder_Icon " ${menu.newfolder}", 0, 0, "bookmark.addfolder" },

                            { upDownArrow_Icon " ${menu.sort.alpha}", 0, 0, "bookmark.sortfolder" },

                            { "---", 0, 0, NULL },

                            { reload_Icon " ${bookmarks.reload}", 0, 0, "bookmarks.reload.remote" } },

- 17);

+ 18);

         d->modeMenu = makeMenu_Widget(

             as_Widget(d),

             (iMenuItem[]){ { bookmark_Icon " ${menu.page.bookmark}", SDLK_d, KMOD_PRIMARY, "bookmark.add" },

@@ -571,13 +576,17 @@ static void updateItemsWithFlags_SidebarWidget_(iSidebarWidget *d, iBool keepAct

         d->menu = makeMenu_Widget(

             as_Widget(d),

             (iMenuItem[]){

+ { openTab_Icon " ${menu.opentab}", 0, 0, "history.open newtab:1" },

+ { openTabBg_Icon " ${menu.opentab.background}", 0, 0, "history.open newtab:2" },

+ { openWindow_Icon " ${menu.openwindow}", 0, 0, "history.open newwindow:1" },

+ { "---" },

                 { "${menu.copyurl}", 0, 0, "history.copy" },

                 { bookmark_Icon " ${sidebar.entry.bookmark}", 0, 0, "history.addbookmark" },

                 { "---", 0, 0, NULL },

                 { close_Icon " ${menu.forgeturl}", 0, 0, "history.delete" },

                 { "---", 0, 0, NULL },

                 { delete_Icon " " uiTextCaution_ColorEscape "${history.clear}", 0, 0, "history.clear confirm:1" },

- }, 6);

+ }, 10);

         d->modeMenu = makeMenu_Widget(

             as_Widget(d),

             (iMenuItem[]){

@@ -981,7 +990,7 @@ static void itemClicked_SidebarWidget_(iSidebarWidget *d, iSidebarItem *item, si

     }

     case feeds_SidebarMode: {

         postCommandString_Root(get_Root(),

- feedEntryOpenCommand_String(&item->url, openTabMode_Sym(modState_Keys())));

+ feedEntryOpenCommand_String(&item->url, openTabMode_Sym(modState_Keys()), 0));

         break;

     }

     case bookmarks_SidebarMode:

@@ -1641,8 +1650,11 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)

     else if (startsWith_CStr(cmd, "feed.entry.") && d->mode == feeds_SidebarMode) {

         const iSidebarItem *item = d->contextItem;

         if (item) {

- if (isCommand_Widget(w, ev, "feed.entry.opentab")) {

- postCommandString_Root(get_Root(), feedEntryOpenCommand_String(&item->url, 1));

+ if (isCommand_Widget(w, ev, "feed.entry.open")) {

+ const char *cmd = command_UserEvent(ev);

+ postCommandString_Root(get_Root(), feedEntryOpenCommand_String(&item->url,

+ argLabel_Command(cmd, "newtab"),

+ argLabel_Command(cmd, "newwindow")));

                 return iTrue;

             }

             if (isCommand_Widget(w, ev, "feed.entry.toggleread")) {

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

index 6f680cd4..b0de0557 100644

--- a/src/ui/window.c

+++ b/src/ui/window.c

@@ -1567,6 +1567,23 @@ void setKeyboardHeight_MainWindow(iMainWindow *d, int height) {

 }

}



+iObjectList *listDocuments_MainWindow(iMainWindow *d, const iRoot *rootOrNull) {

+ iObjectList *docs = new_ObjectList();

+ iForIndices(i, d->base.roots) {

+ iRoot *root = d->base.roots[i];

+ if (!root) continue;

+ if (!rootOrNull || root == rootOrNull) {

+ const iWidget *tabs = findChild_Widget(root->widget, "doctabs");

+ iForEach(ObjectList, i, children_Widget(findChild_Widget(tabs, "tabs.pages"))) {

+ if (isInstance_Object(i.object, &Class_DocumentWidget)) {

+ pushBack_ObjectList(docs, i.object);

+ }

+ }

+ }

+ }

+ return docs;

+}

+

void checkPendingSplit_MainWindow(iMainWindow *d) {

 if (d->splitMode != d->pendingSplitMode) {

     setSplitMode_MainWindow(d, d->pendingSplitMode);

diff --git a/src/ui/window.h b/src/ui/window.h

index c7d59380..c3c34e1b 100644

--- a/src/ui/window.h

+++ b/src/ui/window.h

@@ -187,6 +187,7 @@ void setTitle_MainWindow (iMainWindow *, const iString *title

void setSnap_MainWindow (iMainWindow *, int snapMode);

void setFreezeDraw_MainWindow (iMainWindow *, iBool freezeDraw);

void setKeyboardHeight_MainWindow (iMainWindow *, int height);

+iObjectList *listDocuments_MainWindow (iMainWindow *, const iRoot *rootOrNull);

void setSplitMode_MainWindow (iMainWindow *, int splitMode);

void checkPendingSplit_MainWindow (iMainWindow *);

void swapRoots_MainWindow (iMainWindow *);

Proxy Information
Original URL
gemini://git.skyjake.fi/lagrange/work%2Fv1.11/pcdiff/ed14d3467d6046ddfa66c3143a340428aeef66ae
Status Code
Success (20)
Meta
text/plain
Capsule Response Time
113.828513 milliseconds
Gemini-to-HTML Time
11.097929 milliseconds

This content has been proxied by September (ba2dc).