Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 41 additions & 5 deletions locales/en-US/browser/browser/preferences/zen-preferences.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,43 @@ zen-settings-normal-tabs-sync =
zen-settings-workspaces-sync-unpinned-tabs =
.label = Sync only pinned tabs in workspaces

zen-tabs-cycle-by-attribute =
.label = Ctrl+Tab cycles within Essential or Workspace tabs only
zen-tabs-cycle-ignore-pending-tabs =
.label = Ignore Pending tabs when cycling with Ctrl+Tab
zen-tabs-cycle-by-attribute-warning = Ctrl+Tab will cycle by recently used order, as it is enabled
pane-zen-tab-switcher-title = Tab Switcher
zen-tab-switcher-header = Switching between tabs

# Variables:
# $shortcut (String) - The shortcut that cycles through tabs, like "Ctrl+Tab", or "none" when it has no shortcut.
zen-tab-switcher-description =
{ $shortcut ->
[none] Choose which tabs the tab switcher cycles through. <a data-l10n-name="keyboard-shortcuts">Set a shortcut</a>
*[other] Choose which tabs <kbd>{ $shortcut }</kbd> cycles through. <a data-l10n-name="keyboard-shortcuts">Change shortcut</a>
}
# Variables:
# $shortcut (String) - The shortcut that cycles through tabs, like "Ctrl+Tab", or "none" when it has no shortcut.
zen-tab-switcher-recently-used-order =
.label =
{ $shortcut ->
[none] Cycle through tabs in recently used order
*[other] Cycle through tabs in recently used order with { $shortcut }
}
zen-tab-switcher-cross-space =
.label = Cycle through tabs in all spaces, not just the current one
# Variables:
# $shortcut (String) - The shortcut that cycles through tabs, like "Ctrl+Tab", or "none" when it has no shortcut.
zen-tab-switcher-ignore-pending-tabs =
.label =
{ $shortcut ->
[none] Ignore pending tabs when cycling through tabs
*[other] Ignore pending tabs when cycling with { $shortcut }
}
# Variables:
# $shortcut (String) - The shortcut that cycles through tabs, like "Ctrl+Tab", or "none" when it has no shortcut.
zen-tab-switcher-cycle-by-attribute =
.label =
{ $shortcut ->
[none] Stay within Essential or Workspace tabs when cycling through tabs
*[other] Stay within Essential or Workspace tabs when cycling with { $shortcut }
}
zen-tab-switcher-cycle-by-attribute-warning = This has no effect while cycling in recently used order.

zen-look-and-feel-compact-toolbar-themed =
.label = Use themed background for compact toolbar
Expand Down Expand Up @@ -198,6 +230,7 @@ zenCKSOption-group-zen-compact-mode = Compact Mode
zenCKSOption-group-zen-workspace = Workspaces
zenCKSOption-group-zen-other = Other Zen Features
zenCKSOption-group-zen-split-view = Split View
zenCKSOption-group-zen-tabs = Tabs

zen-text-action-copy-url-shortcut = Copy current URL
zen-text-action-copy-url-markdown-shortcut = Copy current URL as Markdown
Expand Down Expand Up @@ -227,3 +260,6 @@ zen-split-view-shortcut-unsplit = Close Split View
zen-new-empty-split-view-shortcut = New Empty Split View
zen-close-all-unpinned-tabs-shortcut = Close All Unpinned Tabs
zen-duplicate-tab-shortcut = Duplicate Tab
zen-tab-switcher-shortcut-cycle = Tab Switcher
zen-tab-switcher-shortcut-next = Next Tab
zen-tab-switcher-shortcut-previous = Previous Tab
3 changes: 3 additions & 0 deletions prefs/zen/sync.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
- name: services.sync.prefs.sync.zen.tabs.ctrl-tab.ignore-pending-tabs
value: true

- name: services.sync.prefs.sync.zen.tabs.ctrl-tab.cross-space
value: true

- name: services.sync.prefs.sync.zen.ctrlTab.show-pending-tabs
value: true

Expand Down
3 changes: 3 additions & 0 deletions prefs/zen/zen.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,6 @@

- name: zen.tabs.ctrl-tab.ignore-pending-tabs
value: false

- name: zen.tabs.ctrl-tab.cross-space
value: false
12 changes: 12 additions & 0 deletions src/browser/base/content/zen-keysets.inc.xhtml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,18 @@
<key id="zen-workspace-create" command="cmd_zenOpenWorkspaceCreation"/>
<key id="zen-close-all-unpinned-tabs" key="K" modifiers="accel,shift" command="cmd_zenCloseUnpinnedTabs"/>

<!-- Firefox handles tab switching itself, these keys never fire. They hold
the bindings so they can be changed in about:keyboard, see
ZenKeyboardShortcuts.getSystemActionForEvent. -->
#ifdef XP_MACOSX
#define ZEN_TAB_SWITCHER_MODIFIER control
#else
#define ZEN_TAB_SWITCHER_MODIFIER accel
#endif
#expand <key id="zen-tab-switcher-cycle" keycode="VK_TAB" modifiers="__ZEN_TAB_SWITCHER_MODIFIER__" disabled="true"/>
#expand <key id="zen-tab-switcher-next" keycode="VK_PAGE_DOWN" modifiers="__ZEN_TAB_SWITCHER_MODIFIER__" disabled="true"/>
#expand <key id="zen-tab-switcher-previous" keycode="VK_PAGE_UP" modifiers="__ZEN_TAB_SWITCHER_MODIFIER__" disabled="true"/>

<key id="zen-split-view-grid" key="G" modifiers="accel,alt" command="cmd_zenSplitViewGrid"/>
<key id="zen-split-view-vertical" key="V" modifiers="accel,alt" command="cmd_zenSplitViewVertical"/>
<key id="zen-split-view-horizontal" key="H" modifiers="accel,alt" command="cmd_zenSplitViewHorizontal"/>
Expand Down
73 changes: 73 additions & 0 deletions src/browser/components/preferences/zen-settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -713,8 +713,76 @@ var gZenLooksAndFeel = {
},
};

var gZenTabSwitcherSettings = {
init() {
// Firefox's own checkbox for this pref, which this one replaces, does the
// same so a later migration doesn't undo the user's choice.
document.getElementById("zenTabSwitcherRecentlyUsedOrder").addEventListener("command", () => {
Services.prefs.clearUserPref("browser.ctrlTab.migrated");
});

document.getElementById("zenTabSwitcherDescription").addEventListener("click", (event) => {
if (event.target.closest("a")) {
event.preventDefault();
window.browsingContext.topChromeWindow.switchToTabHavingURI("about:keyboard", true);
}
});

const updateCrossSpace = () => {
document.getElementById("zenTabSwitcherCrossSpace").disabled = !Services.prefs.getBoolPref(
"browser.ctrlTab.sortByRecentlyUsed",
false
);
};
updateCrossSpace();
Services.prefs.addObserver("browser.ctrlTab.sortByRecentlyUsed", updateCrossSpace);

// Labels mention the cycle shortcut, which can be changed in
// about:keyboard. CustomKeys updates the key element in every window, so
// follow it there to keep them current.
const cycleKey =
window.browsingContext.topChromeWindow?.document.getElementById("zen-tab-switcher-cycle");
this.updateShortcutLabels(cycleKey);
const keyObserver = new MutationObserver(() => this.updateShortcutLabels(cycleKey));
if (cycleKey) {
keyObserver.observe(cycleKey, {
attributes: true,
attributeFilter: ["key", "keycode", "modifiers"],
});
}

window.addEventListener("unload", () => {
Services.prefs.removeObserver("browser.ctrlTab.sortByRecentlyUsed", updateCrossSpace);
keyObserver.disconnect();
});
},

/**
* @param {Element|null} cycleKey The <key> element holding the cycle shortcut.
*/
updateShortcutLabels(cycleKey) {
const { ShortcutUtils } = ChromeUtils.importESModule(
"resource://gre/modules/ShortcutUtils.sys.mjs"
);
const shortcut =
cycleKey?.hasAttribute("key") || cycleKey?.hasAttribute("keycode")
? ShortcutUtils.prettifyShortcut(cycleKey)
: "none";
for (const element of document.querySelectorAll(".zen-tab-switcher-shortcut-label")) {
// The description's translation is markup, so the shortcut is escaped
// there. Labels are plain text.
const isMarkup = element.id == "zenTabSwitcherDescription";
document.l10n.setArgs(element, {
shortcut: isMarkup ? shortcut.replaceAll("&", "&amp;").replaceAll("<", "&lt;") : shortcut,
});
}
},
};

var gZenWorkspacesSettings = {
init() {
gZenTabSwitcherSettings.init();

var tabsUnloaderPrefListener = {
async observe() {
let buttonIndex = await confirmRestartPrompt(true, 1, true, true);
Expand Down Expand Up @@ -854,6 +922,11 @@ Preferences.addAll([
type: "bool",
default: false,
},
{
id: "zen.tabs.ctrl-tab.cross-space",
type: "bool",
default: false,
},
{
id: "zen.tabs.close-on-back-with-no-history",
type: "bool",
Expand Down
37 changes: 32 additions & 5 deletions src/browser/components/preferences/zenTabsManagement.inc.xhtml
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,43 @@
<checkbox id="zenTabsCloseOnBackWithNoHistory"
data-l10n-id="zen-tabs-close-on-back-with-no-history"
preference="zen.tabs.close-on-back-with-no-history"/>
<checkbox data-l10n-id="zen-tabs-cycle-ignore-pending-tabs"
<checkbox data-l10n-id="zen-tabs-select-recently-used-on-close"
preference="zen.tabs.select-recently-used-on-close"/>
</groupbox>

<hbox id="zenTabSwitcherCategory"
class="subcategory"
hidden="true"
data-category="paneZenTabManagement">
<html:h1 data-l10n-id="pane-zen-tab-switcher-title"/>
</hbox>

<groupbox id="zenTabSwitcherGroup" data-category="paneZenTabManagement" hidden="true" class="highlighting-group">
<label><html:h2 data-l10n-id="zen-tab-switcher-header"/></label>
<description id="zenTabSwitcherDescription"
class="description-deemphasized zen-tab-switcher-shortcut-label"
data-l10n-id="zen-tab-switcher-description">
<html:a class="text-link" data-l10n-name="keyboard-shortcuts" href="about:keyboard"/>
</description>

<checkbox id="zenTabSwitcherRecentlyUsedOrder"
class="zen-tab-switcher-shortcut-label"
data-l10n-id="zen-tab-switcher-recently-used-order"
preference="browser.ctrlTab.sortByRecentlyUsed"/>
<checkbox id="zenTabSwitcherCrossSpace"
class="indent"
data-l10n-id="zen-tab-switcher-cross-space"
preference="zen.tabs.ctrl-tab.cross-space"/>
<checkbox class="zen-tab-switcher-shortcut-label"
data-l10n-id="zen-tab-switcher-ignore-pending-tabs"
preference="zen.tabs.ctrl-tab.ignore-pending-tabs"/>
<checkbox data-l10n-id="zen-tabs-cycle-by-attribute"
<checkbox class="zen-tab-switcher-shortcut-label"
data-l10n-id="zen-tab-switcher-cycle-by-attribute"
preference="zen.tabs.ctrl-tab.ignore-essential-tabs"/>
<description id="zenTabsCycleByAttributeWarning"
class="description-deemphasized"
data-l10n-id="zen-tabs-cycle-by-attribute-warning"
data-l10n-id="zen-tab-switcher-cycle-by-attribute-warning"
hidden="true"/>
<checkbox data-l10n-id="zen-tabs-select-recently-used-on-close"
preference="zen.tabs.select-recently-used-on-close"/>
</groupbox>

<hbox id="zenPinnedTabsManagerCategory"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
diff --git a/browser/components/tabbrowser/content/browser-ctrlTab.js b/browser/components/tabbrowser/content/browser-ctrlTab.js
index 727e21f1754b0842080d8f3e29060baad445df66..ee9df3a311fc72954e064a2cbc56b716d116314a 100644
index 3878a29a91aef0911f0260082847ed416ddf16d4..db888dbb583caf932371b0e928b1b448ec474c39 100644
--- a/browser/components/tabbrowser/content/browser-ctrlTab.js
+++ b/browser/components/tabbrowser/content/browser-ctrlTab.js
@@ -252,7 +252,8 @@ var ctrlTab = {
@@ -264,7 +264,8 @@ var ctrlTab = {
},

get tabList() {
Expand All @@ -12,7 +12,7 @@ index 727e21f1754b0842080d8f3e29060baad445df66..ee9df3a311fc72954e064a2cbc56b716
},

init: function ctrlTab_init() {
@@ -457,7 +458,7 @@ var ctrlTab = {
@@ -485,7 +486,7 @@ var ctrlTab = {
// If the tab is hidden, don't add it to the list unless it's selected
// (Normally hidden tabs would be unhidden when selected, but that doesn't
// happen for Firefox View).
Expand All @@ -21,7 +21,7 @@ index 727e21f1754b0842080d8f3e29060baad445df66..ee9df3a311fc72954e064a2cbc56b716
return;
}

@@ -481,7 +482,7 @@ var ctrlTab = {
@@ -509,7 +510,7 @@ var ctrlTab = {
},

open: function ctrlTab_open() {
Expand All @@ -30,12 +30,86 @@ index 727e21f1754b0842080d8f3e29060baad445df66..ee9df3a311fc72954e064a2cbc56b716
return;
}

@@ -759,7 +760,7 @@ var ctrlTab = {
@@ -585,7 +586,10 @@ var ctrlTab = {
},

onKeyDown(event) {
- let action = ShortcutUtils.getSystemActionForEvent(event);
+ let action = this.ZenKeyboardShortcuts.getSystemActionForEvent(
+ event,
+ document
+ );
if (action != ShortcutUtils.CYCLE_TABS) {
return;
}
@@ -601,19 +605,26 @@ var ctrlTab = {
event.preventDefault();
event.stopPropagation();

+ let reverse = this.ZenKeyboardShortcuts.isTabSwitcherReverseEvent(
+ event,
+ document
+ );
if (this.isOpen) {
- this.advanceFocus(!event.shiftKey);
+ this.advanceFocus(!reverse);
return;
}

- if (event.shiftKey) {
+ if (reverse) {
this.showAllTabs("shift-tab");
return;
}

document.addEventListener("keyup", this, { mozSystemGroup: true });

- let tabs = gBrowser.visibleTabs;
+ // With cross-space switching, the other tabs may all be in other spaces.
+ let tabs = gZenWorkspaces.crossSpaceCtrlTab
+ ? this.tabList
+ : gBrowser.visibleTabs;
if (tabs.length > 2) {
this.open();
} else if (tabs.length == 2) {
@@ -741,7 +752,9 @@ var ctrlTab = {
event.preventDefault();
event.stopPropagation();

- if (event.keyCode === event.DOM_VK_CONTROL) {
+ if (
+ this.ZenKeyboardShortcuts.isTabSwitcherReleaseEvent(event, document)
+ ) {
document.removeEventListener("keyup", this, { mozSystemGroup: true });

if (this.isOpen) {
@@ -794,14 +807,17 @@ var ctrlTab = {
aCallback(urls);
},
_sortRecentlyUsedTabs() {
+ // Right after switching spaces, the previous and the newly selected tab
+ // can share a lastAccessed time. The selected tab always comes first.
this._recentlyUsedTabs.sort(
- (tab1, tab2) => tab2.lastAccessed - tab1.lastAccessed
+ (tab1, tab2) =>
+ tab2.selected - tab1.selected || tab2.lastAccessed - tab1.lastAccessed
);
},
_initRecentlyUsedTabs() {
this._recentlyUsedTabs = Array.prototype.filter.call(
gBrowser.tabs,
- gBrowser.tabs,
- tab => !tab.closing && !tab.hidden
+ gZenWorkspaces.ctrlTabCandidates,
+ tab => !tab.closing && !tab.hidden && !tab.hasAttribute("zen-empty-tab")
);
this._sortRecentlyUsedTabs();
},
@@ -846,6 +862,8 @@ var ctrlTab = {

ChromeUtils.defineESModuleGetters(ctrlTab, {
KeyboardLockUtils: "resource://gre/modules/KeyboardLockUtils.sys.mjs",
+ ZenKeyboardShortcuts:
+ "resource:///modules/zen/kbs/ZenKeyboardShortcuts.sys.mjs",
});

XPCOMUtils.defineLazyPreferenceGetter(
12 changes: 12 additions & 0 deletions src/browser/themes/shared/preferences/zen-preferences.css
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,17 @@ groupbox h2 {
font-size: 15px;
}

#zenTabSwitcherDescription html|kbd {
font: inherit;
font-size: 0.9em;
padding: 1px 6px;
border: 1px solid color-mix(in srgb, currentColor 25%, transparent);
border-bottom-width: 2px;
border-radius: 5px;
background-color: light-dark(#f1f1f1, #363636);
white-space: nowrap;
}

#categories > .category {
margin-left: 0 !important;
min-height: 40px !important;
Expand Down Expand Up @@ -408,6 +419,7 @@ groupbox h2 {
#helpButton,
#support-firefox,
#tabGroupSuggestions,
#ctrlTabRecentlyUsedOrder,
#setting-control-sidebarChatbotFieldset,
#setting-control-supportFirefox,
.mission-message,
Expand Down
Loading