[1mdiff --git a/po/en.po b/po/en.po[m
[1mindex e9bdd590..37777559 100644[m
[1m--- a/po/en.po[m
[1m+++ b/po/en.po[m
[36m@@ -154,6 +154,9 @@[m [mmsgstr "New Window"[m
msgid "menu.newtab"[m
msgstr "New Tab"[m
[m
[32m+[m[32mmsgid "menu.reopentab"[m
[32m+[m[32mmsgstr "Reopen Last Closed Tab"[m
[32m+[m
msgid "menu.closetab"[m
msgstr "Close Tab"[m
[m
[1mdiff --git a/src/app.c b/src/app.c[m
[1mindex 89c60698..4055916a 100644[m
[1m--- a/src/app.c[m
[1m+++ b/src/app.c[m
[36m@@ -134,6 +134,7 @@[m [mstruct Impl_App {[m
iCommandLine args;[m
iString * execPath;[m
iStringSet * tempFilesPendingDeletion;[m
[32m+[m[32m iStringList recentlyClosedTabUrls; / for reopening, like an undo stack */[m
iMimeHooks * mimehooks;[m
iGmCerts * certs;[m
iVisited * visited;[m
[36m@@ -168,7 +169,6 @@[m [mstruct Impl_App {[m
/* Preferences: */[m
iBool commandEcho; /* --echo */[m
iBool forceSoftwareRender; /* --sw */[m
[31m- //iRect initialWindowRect;[m
iArray initialWindowRects; /* one per window */[m
iPrefs prefs;[m
};[m
[36m@@ -907,7 +907,8 @@[m [mstatic void init_App_(iApp *d, int argc, char **argv) {[m
d->isDarkSystemTheme = iTrue; /* will be updated by system later on, if supported */[m
d->isSuspended = iFalse;[m
d->tempFilesPendingDeletion = new_StringSet();[m
[31m- init_Array(&d->initialWindowRects, sizeof(iRect));[m
[32m+[m[32m d->recentlyClosedTabUrls = new_StringList();[m
[32m+[m[32m init_Array(&d->initialWindowRects, sizeof(iRect));[m[41m [m
init_CommandLine(&d->args, argc, argv);[m
/* Where was the app started from? We ask SDL first because the command line alone[m
cannot be relied on (behavior differs depending on OS). */ {[m
[36m@@ -1211,6 +1212,7 @@[m [mstatic void deinit_App(iApp *d) {[m
remove(cstr_String(tmp.value));[m
}[m
deinit_Array(&d->initialWindowRects);[m
[32m+[m[32m iRelease(d->recentlyClosedTabUrls);[m
iRelease(d->tempFilesPendingDeletion);[m
}[m
[m
[36m@@ -2616,6 +2618,20 @@[m [mstatic void invalidateCachedDocuments_App_(void) {[m
}[m
}[m
[m
[32m+[m[32mstatic void pushClosedTabUrl_App_(iApp *d, const iString *url) {[m
[32m+[m[32m pushBack_StringList(d->recentlyClosedTabUrls, url);[m
[32m+[m[32m if (size_StringList(d->recentlyClosedTabUrls) > 50) { /* not an infinite number */[m
[32m+[m[32m popFront_StringList(d->recentlyClosedTabUrls);[m
[32m+[m[32m }[m
[32m+[m[32m}[m
[32m+[m
[32m+[m[32mstatic const iString *popClosedTabUrl_App_(iApp *d) {[m
[32m+[m[32m if (isEmpty_StringList(d->recentlyClosedTabUrls)) {[m
[32m+[m[32m return NULL;[m
[32m+[m[32m }[m
[32m+[m[32m return collect_String(takeLast_StringList(d->recentlyClosedTabUrls));[m[41m [m
[32m+[m[32m}[m
[32m+[m
static iBool handleNonWindowRelatedCommand_App_(iApp *d, const char *cmd) {[m
const iBool isFrozen = !d->window || d->window->isDrawFrozen;[m
/* Commands related to preferences. */[m
[36m@@ -3524,8 +3540,16 @@[m [miBool handleCommand_App(const char *cmd) {[m
return iFalse;[m
}[m
else if (equal_Command(cmd, "tabs.new")) {[m
[32m+[m[32m if (argLabel_Command(cmd, "reopen")) {[m
[32m+[m[32m const iString *reopenUrl = popClosedTabUrl_App_(d);[m
[32m+[m[32m if (reopenUrl) {[m
[32m+[m[32m newTab_App(NULL, iTrue);[m
[32m+[m[32m postCommandf_App("open url:%s", cstr_String(reopenUrl));[m
[32m+[m[32m }[m
[32m+[m[32m return iTrue;[m
[32m+[m[32m }[m
const iBool isDuplicate = argLabel_Command(cmd, "duplicate") != 0;[m
[31m- newTab_App(isDuplicate ? document_App() : NULL, iTrue);[m
[32m+[m[32m newTab_App(isDuplicate ? document_App() : NULL, iTrue);[m[41m [m
if (!isDuplicate) {[m
postCommandf_App("navigate.home focus:%d", deviceType_App() == desktop_AppDeviceType);[m
}[m
[36m@@ -3549,13 +3573,19 @@[m [miBool handleCommand_App(const char *cmd) {[m
postCommand_App("document.openurls.changed");[m
if (argLabel_Command(cmd, "toright")) {[m
while (tabCount_Widget(tabs) > index + 1) {[m
[31m- destroy_Widget(removeTabPage_Widget(tabs, index + 1));[m
[32m+[m[32m iDocumentWidget *closed = (iDocumentWidget *) removeTabPage_Widget(tabs, index + 1);[m
[32m+[m[32m pushClosedTabUrl_App_(d, url_DocumentWidget(closed));[m
[32m+[m[32m cancelAllRequests_DocumentWidget(closed);[m
[32m+[m[32m destroy_Widget(as_Widget(closed));[m
}[m
wasClosed = iTrue;[m
}[m
if (argLabel_Command(cmd, "toleft")) {[m
while (index-- > 0) {[m
[31m- destroy_Widget(removeTabPage_Widget(tabs, 0));[m
[32m+[m[32m iDocumentWidget *closed = (iDocumentWidget *) removeTabPage_Widget(tabs, 0);[m
[32m+[m[32m pushClosedTabUrl_App_(d, url_DocumentWidget(closed));[m
[32m+[m[32m cancelAllRequests_DocumentWidget(closed);[m
[32m+[m[32m destroy_Widget(as_Widget(closed));[m
}[m
postCommandf_App("tabs.switch page:%p", tabPage_Widget(tabs, 0));[m
wasClosed = iTrue;[m
[36m@@ -3566,9 +3596,10 @@[m [miBool handleCommand_App(const char *cmd) {[m
}[m
const iBool isSplit = numRoots_Window(get_Window()) > 1;[m
if (tabCount_Widget(tabs) > 1 || isSplit) {[m
[31m- iWidget *closed = removeTabPage_Widget(tabs, index);[m
[31m- cancelAllRequests_DocumentWidget((iDocumentWidget *) closed);[m
[31m- destroy_Widget(closed); /* released later */[m
[32m+[m[32m iDocumentWidget *closed = (iDocumentWidget *) removeTabPage_Widget(tabs, index);[m
[32m+[m[32m pushClosedTabUrl_App_(d, url_DocumentWidget(closed));[m
[32m+[m[32m cancelAllRequests_DocumentWidget(closed);[m
[32m+[m[32m destroy_Widget(as_Widget(closed)); /* released later */[m
if (index == tabCount_Widget(tabs)) {[m
index--;[m
}[m
[1mdiff --git a/src/app.h b/src/app.h[m
[1mindex 60421e2b..98d49fbb 100644[m
[1m--- a/src/app.h[m
[1m+++ b/src/app.h[m
[36m@@ -126,6 +126,7 @@[m [miAny * findWidget_App (const char *id);[m
void addTicker_App (iTickerFunc ticker, iAny *context);[m
void addTickerRoot_App (iTickerFunc ticker, iRoot *root, iAny *context);[m
void removeTicker_App (iTickerFunc ticker, iAny *context);[m
[32m+[m
void addWindow_App (iMainWindow *win);[m
void removeWindow_App (iMainWindow *win);[m
void setActiveWindow_App (iMainWindow *win);[m
[36m@@ -134,8 +135,11 @@[m [msize_t numWindows_App (void);[m
size_t windowIndex_App (const iMainWindow *win);[m
iMainWindow *newMainWindow_App (void);[m
const iPtrArray *mainWindows_App(void);[m
[32m+[m[32miMainWindow * mainWindow_App (void); /* currently active main window */[m
void addPopup_App (iWindow *popup);[m
void removePopup_App (iWindow *popup);[m
[32m+[m[32mvoid closePopups_App (iBool doForce);[m
[32m+[m
void postRefresh_App (void);[m
void postCommand_Root (iRoot *, const char *command);[m
void postCommandf_Root (iRoot *, const char *command, ...);[m
[36m@@ -156,6 +160,3 @@[m [mvoid openInDefaultBrowser_App(const iString *url);[m
void revealPath_App (const iString *path);[m
void resetFonts_App (void);[m
void availableFontsChanged_App(void);[m
[31m-[m
[31m-iMainWindow * mainWindow_App (void);[m
[31m-void closePopups_App (iBool doForce);[m
[1mdiff --git a/src/ui/keys.c b/src/ui/keys.c[m
[1mindex 6a12b5e7..c3b68316 100644[m
[1m--- a/src/ui/keys.c[m
[1m+++ b/src/ui/keys.c[m
[36m@@ -227,7 +227,8 @@[m [mstatic const struct { int id; iMenuItem bind; int flags; } defaultBindings_[] =[m
#endif[m
{ 76, { "${keys.tab.new}", newTab_KeyShortcut, "tabs.new" }, 0 },[m
{ 77, { "${keys.tab.close}", closeTab_KeyShortcut, "tabs.close" }, 0 },[m
[31m- { 78, { "${keys.tab.close.other}", SDLK_w, KMOD_SECONDARY, "tabs.close toleft:1 toright:1" }, 0 },[m
[32m+[m[32m { 78, { "${keys.tab.close.other}", SDLK_w, KMOD_SECONDARY, "tabs.close toleft:1 toright:1" }, 0 },[m
[32m+[m[32m { 79, { "${LC:menu.reopentab}", SDLK_t, KMOD_SECONDARY, "tabs.new reopen:1" }, 0 },[m[41m [m
{ 80, { "${keys.tab.prev}", prevTab_KeyShortcut, "tabs.prev" }, 0 },[m
{ 81, { "${keys.tab.next}", nextTab_KeyShortcut, "tabs.next" }, 0 },[m
{ 90, { "${keys.split.menu}", SDLK_j, KMOD_PRIMARY, "splitmenu.open" }, 0 },[m
[1mdiff --git a/src/ui/window.c b/src/ui/window.c[m
[1mindex 0d1923c6..c773bc96 100644[m
[1m--- a/src/ui/window.c[m
[1m+++ b/src/ui/window.c[m
[36m@@ -73,6 +73,7 @@[m [miDefineTypeConstructionArgs(MainWindow, (iRect rect), rect)[m
static const iMenuItem fileMenuItems_[] = {[m
{ "${menu.newwindow}", SDLK_n, KMOD_PRIMARY, "window.new" },[m
{ "${menu.newtab}", SDLK_t, KMOD_PRIMARY, "tabs.new" },[m
[32m+[m[32m { "${menu.reopentab}", SDLK_t, KMOD_SECONDARY, "tabs.new reopen:1" },[m
{ "${menu.openlocation}", SDLK_l, KMOD_PRIMARY, "navigate.focus" },[m
{ "---" },[m
{ saveToDownloads_Label, SDLK_s, KMOD_PRIMARY, "document.save" },[m
text/plain
This content has been proxied by September (ba2dc).