mirror of
https://github.com/zen-browser/desktop.git
synced 2026-05-24 22:00:13 +00:00
no-bug: Start working on little zen
This commit is contained in:
@@ -7,3 +7,6 @@
|
||||
|
||||
- name: zen.keyboard.shortcuts.disable-mainkeyset-clear
|
||||
value: false # for debugging
|
||||
|
||||
- name: zen.keyboard.shortcuts.global.enabled
|
||||
value: true
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
<link rel="stylesheet" type="text/css" href="chrome://browser/content/zen-styles/zen-welcome.css" />
|
||||
<link rel="stylesheet" type="text/css" href="chrome://browser/content/zen-styles/zen-media-controls.css" />
|
||||
<link rel="stylesheet" type="text/css" href="chrome://browser/content/zen-styles/zen-download-box-animation.css" />
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="chrome://browser/content/zen-styles/zen-little-window.css" />
|
||||
</linkset>
|
||||
|
||||
# Startup "preloaded" scripts that requre globals such as gBrowser and gURLBar
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include ../../../zen/mods/jar.inc.mn
|
||||
#include ../../../zen/spaces/jar.inc.mn
|
||||
#include ../../../zen/tabs/jar.inc.mn
|
||||
#include ../../../zen/kbs/jar.inc.mn
|
||||
#include ../../../zen/glance/jar.inc.mn
|
||||
#include ../../../zen/folders/jar.inc.mn
|
||||
#include ../../../zen/welcome/jar.inc.mn
|
||||
@@ -19,3 +18,4 @@
|
||||
#include ../../../zen/vendor/jar.inc.mn
|
||||
#include ../../../zen/fonts/jar.inc.mn
|
||||
#include ../../../zen/live-folders/jar.inc.mn
|
||||
#include ../../../zen/little-window/jar.inc.mn
|
||||
|
||||
@@ -68,4 +68,6 @@
|
||||
<command id="cmd_zenNewLiveFolder" />
|
||||
|
||||
<command id="cmd_zenDuplicateTab" />
|
||||
|
||||
<command id="cmd_zenNewLittleWindow" />
|
||||
</commandset>
|
||||
|
||||
@@ -8,13 +8,16 @@ const { nsZenMultiWindowFeature } = ChromeUtils.importESModule(
|
||||
{ global: "current" }
|
||||
);
|
||||
|
||||
const { nsKeyShortcutModifiers } = ChromeUtils.importESModule(
|
||||
"chrome://browser/content/zen-components/ZenKeyboardShortcuts.mjs",
|
||||
{
|
||||
global: "current",
|
||||
}
|
||||
const {
|
||||
nsKeyShortcutModifiers,
|
||||
ZenKeyboardShortcuts,
|
||||
VALID_SHORTCUT_GROUPS,
|
||||
} = ChromeUtils.importESModule(
|
||||
"resource:///modules/zen/ZenKeyboardShortcuts.sys.mjs"
|
||||
);
|
||||
|
||||
const gZenKeyboardShortcutsManager = ZenKeyboardShortcuts.manager;
|
||||
|
||||
var gZenMarketplaceManager = {
|
||||
async init() {
|
||||
const checkForUpdates = document.getElementById("zenThemeMarketplaceCheckForUpdates");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
diff --git a/browser/components/urlbar/content/UrlbarInput.mjs b/browser/components/urlbar/content/UrlbarInput.mjs
|
||||
index b23244f9d3278918b016bb3fcab19687bc2e292a..ade1f031bbb68202a37e6c9d3071a73f5c811a82 100644
|
||||
index b23244f9d3278918b016bb3fcab19687bc2e292a..0bcb63f7abaf406077b52469eb913fcb75ba13f8 100644
|
||||
--- a/browser/components/urlbar/content/UrlbarInput.mjs
|
||||
+++ b/browser/components/urlbar/content/UrlbarInput.mjs
|
||||
@@ -90,6 +90,13 @@ const lazy = XPCOMUtils.declareLazy({
|
||||
@@ -75,7 +75,7 @@ index b23244f9d3278918b016bb3fcab19687bc2e292a..ade1f031bbb68202a37e6c9d3071a73f
|
||||
}
|
||||
|
||||
if (isCanonized) {
|
||||
@@ -2696,6 +2728,42 @@ export class UrlbarInput extends HTMLElement {
|
||||
@@ -2696,6 +2728,45 @@ export class UrlbarInput extends HTMLElement {
|
||||
await this.#updateLayoutBreakoutDimensions();
|
||||
}
|
||||
|
||||
@@ -84,7 +84,10 @@ index b23244f9d3278918b016bb3fcab19687bc2e292a..ade1f031bbb68202a37e6c9d3071a73f
|
||||
+ }
|
||||
+
|
||||
+ get zenUrlbarBehavior() {
|
||||
+ if (this.document.documentElement.hasAttribute("inDOMFullscreen")) {
|
||||
+ if (
|
||||
+ this.document.documentElement.hasAttribute("inDOMFullscreen") ||
|
||||
+ this.document.documentElement.hasAttribute("zen-little-window")
|
||||
+ ) {
|
||||
+ return "float";
|
||||
+ }
|
||||
+ return lazy.ZEN_URLBAR_BEHAVIOR;
|
||||
@@ -118,7 +121,7 @@ index b23244f9d3278918b016bb3fcab19687bc2e292a..ade1f031bbb68202a37e6c9d3071a73f
|
||||
startLayoutExtend() {
|
||||
if (!this.#allowBreakout || this.hasAttribute("breakout-extend")) {
|
||||
// Do not expand if the Urlbar does not support being expanded or it is
|
||||
@@ -2710,6 +2778,13 @@ export class UrlbarInput extends HTMLElement {
|
||||
@@ -2710,6 +2781,13 @@ export class UrlbarInput extends HTMLElement {
|
||||
|
||||
this.setAttribute("breakout-extend", "true");
|
||||
|
||||
@@ -132,7 +135,7 @@ index b23244f9d3278918b016bb3fcab19687bc2e292a..ade1f031bbb68202a37e6c9d3071a73f
|
||||
// Enable the animation only after the first extend call to ensure it
|
||||
// doesn't run when opening a new window.
|
||||
if (!this.hasAttribute("breakout-extend-animate")) {
|
||||
@@ -2729,6 +2804,27 @@ export class UrlbarInput extends HTMLElement {
|
||||
@@ -2729,6 +2807,27 @@ export class UrlbarInput extends HTMLElement {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -160,7 +163,7 @@ index b23244f9d3278918b016bb3fcab19687bc2e292a..ade1f031bbb68202a37e6c9d3071a73f
|
||||
this.removeAttribute("breakout-extend");
|
||||
this.#updateTextboxPosition();
|
||||
}
|
||||
@@ -2759,7 +2855,7 @@ export class UrlbarInput extends HTMLElement {
|
||||
@@ -2759,7 +2858,7 @@ export class UrlbarInput extends HTMLElement {
|
||||
forceUnifiedSearchButtonAvailable = false
|
||||
) {
|
||||
let prevState = this.getAttribute("pageproxystate");
|
||||
@@ -169,7 +172,7 @@ index b23244f9d3278918b016bb3fcab19687bc2e292a..ade1f031bbb68202a37e6c9d3071a73f
|
||||
this.setAttribute("pageproxystate", state);
|
||||
this._inputContainer.setAttribute("pageproxystate", state);
|
||||
this._identityBox?.setAttribute("pageproxystate", state);
|
||||
@@ -3031,10 +3127,12 @@ export class UrlbarInput extends HTMLElement {
|
||||
@@ -3031,10 +3130,12 @@ export class UrlbarInput extends HTMLElement {
|
||||
return;
|
||||
}
|
||||
this.style.top = px(
|
||||
@@ -182,7 +185,7 @@ index b23244f9d3278918b016bb3fcab19687bc2e292a..ade1f031bbb68202a37e6c9d3071a73f
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3093,9 +3191,10 @@ export class UrlbarInput extends HTMLElement {
|
||||
@@ -3093,9 +3194,10 @@ export class UrlbarInput extends HTMLElement {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -194,7 +197,7 @@ index b23244f9d3278918b016bb3fcab19687bc2e292a..ade1f031bbb68202a37e6c9d3071a73f
|
||||
);
|
||||
this.style.setProperty(
|
||||
"--urlbar-height",
|
||||
@@ -3597,6 +3696,7 @@ export class UrlbarInput extends HTMLElement {
|
||||
@@ -3597,6 +3699,7 @@ export class UrlbarInput extends HTMLElement {
|
||||
}
|
||||
|
||||
_toggleActionOverride(event) {
|
||||
@@ -202,7 +205,7 @@ index b23244f9d3278918b016bb3fcab19687bc2e292a..ade1f031bbb68202a37e6c9d3071a73f
|
||||
if (
|
||||
event.keyCode == KeyEvent.DOM_VK_SHIFT ||
|
||||
event.keyCode == KeyEvent.DOM_VK_ALT ||
|
||||
@@ -3709,8 +3809,8 @@ export class UrlbarInput extends HTMLElement {
|
||||
@@ -3709,8 +3812,8 @@ export class UrlbarInput extends HTMLElement {
|
||||
if (!this.#isAddressbar) {
|
||||
return val;
|
||||
}
|
||||
@@ -213,7 +216,7 @@ index b23244f9d3278918b016bb3fcab19687bc2e292a..ade1f031bbb68202a37e6c9d3071a73f
|
||||
: val;
|
||||
// Only trim value if the directionality doesn't change to RTL and we're not
|
||||
// showing a strikeout https protocol.
|
||||
@@ -4006,6 +4106,7 @@ export class UrlbarInput extends HTMLElement {
|
||||
@@ -4006,6 +4109,7 @@ export class UrlbarInput extends HTMLElement {
|
||||
resultDetails = null,
|
||||
browser = this.window.gBrowser.selectedBrowser
|
||||
) {
|
||||
@@ -221,7 +224,19 @@ index b23244f9d3278918b016bb3fcab19687bc2e292a..ade1f031bbb68202a37e6c9d3071a73f
|
||||
if (this.#isAddressbar) {
|
||||
this.#prepareAddressbarLoad(
|
||||
url,
|
||||
@@ -4117,6 +4218,10 @@ export class UrlbarInput extends HTMLElement {
|
||||
@@ -4088,6 +4192,11 @@ export class UrlbarInput extends HTMLElement {
|
||||
* @returns {"current" | "tabshifted" | "tab" | "save" | "window"}
|
||||
*/
|
||||
_whereToOpen(event) {
|
||||
+ if (this.document.documentElement.hasAttribute("zen-little-window")) {
|
||||
+ // Little windows are single-tab popups -- never spawn extra tabs
|
||||
+ // or new windows from the urlbar.
|
||||
+ return "current";
|
||||
+ }
|
||||
let isKeyboardEvent = KeyboardEvent.isInstance(event);
|
||||
let reuseEmpty = isKeyboardEvent;
|
||||
let where = undefined;
|
||||
@@ -4117,6 +4226,10 @@ export class UrlbarInput extends HTMLElement {
|
||||
}
|
||||
reuseEmpty = true;
|
||||
}
|
||||
@@ -232,7 +247,7 @@ index b23244f9d3278918b016bb3fcab19687bc2e292a..ade1f031bbb68202a37e6c9d3071a73f
|
||||
if (
|
||||
where == "tab" &&
|
||||
reuseEmpty &&
|
||||
@@ -4124,6 +4229,9 @@ export class UrlbarInput extends HTMLElement {
|
||||
@@ -4124,6 +4237,9 @@ export class UrlbarInput extends HTMLElement {
|
||||
) {
|
||||
where = "current";
|
||||
}
|
||||
@@ -242,7 +257,7 @@ index b23244f9d3278918b016bb3fcab19687bc2e292a..ade1f031bbb68202a37e6c9d3071a73f
|
||||
return where;
|
||||
}
|
||||
|
||||
@@ -4378,6 +4486,7 @@ export class UrlbarInput extends HTMLElement {
|
||||
@@ -4378,6 +4494,7 @@ export class UrlbarInput extends HTMLElement {
|
||||
this.setResultForCurrentValue(null);
|
||||
this.handleCommand();
|
||||
this.controller.clearLastQueryContextCache();
|
||||
@@ -250,7 +265,7 @@ index b23244f9d3278918b016bb3fcab19687bc2e292a..ade1f031bbb68202a37e6c9d3071a73f
|
||||
|
||||
this._suppressStartQuery = false;
|
||||
});
|
||||
@@ -4385,7 +4494,6 @@ export class UrlbarInput extends HTMLElement {
|
||||
@@ -4385,7 +4502,6 @@ export class UrlbarInput extends HTMLElement {
|
||||
contextMenu.addEventListener("popupshowing", () => {
|
||||
// Close the results pane when the input field contextual menu is open,
|
||||
// because paste and go doesn't want a result selection.
|
||||
@@ -258,7 +273,7 @@ index b23244f9d3278918b016bb3fcab19687bc2e292a..ade1f031bbb68202a37e6c9d3071a73f
|
||||
|
||||
let controller =
|
||||
this.document.commandDispatcher.getControllerForCommand("cmd_paste");
|
||||
@@ -4541,7 +4649,11 @@ export class UrlbarInput extends HTMLElement {
|
||||
@@ -4541,7 +4657,11 @@ export class UrlbarInput extends HTMLElement {
|
||||
if (!engineName && !source && !this.hasAttribute("searchmode")) {
|
||||
return;
|
||||
}
|
||||
@@ -271,7 +286,7 @@ index b23244f9d3278918b016bb3fcab19687bc2e292a..ade1f031bbb68202a37e6c9d3071a73f
|
||||
if (this._searchModeIndicatorTitle) {
|
||||
this._searchModeIndicatorTitle.textContent = "";
|
||||
this._searchModeIndicatorTitle.removeAttribute("data-l10n-id");
|
||||
@@ -4851,6 +4963,7 @@ export class UrlbarInput extends HTMLElement {
|
||||
@@ -4851,6 +4971,7 @@ export class UrlbarInput extends HTMLElement {
|
||||
|
||||
this.document.l10n.setAttributes(
|
||||
this.inputField,
|
||||
@@ -279,7 +294,20 @@ index b23244f9d3278918b016bb3fcab19687bc2e292a..ade1f031bbb68202a37e6c9d3071a73f
|
||||
l10nId,
|
||||
l10nId == "urlbar-placeholder-with-name"
|
||||
? { name: engineName }
|
||||
@@ -4964,6 +5077,11 @@ export class UrlbarInput extends HTMLElement {
|
||||
@@ -4891,6 +5012,12 @@ export class UrlbarInput extends HTMLElement {
|
||||
|
||||
_on_blur(event) {
|
||||
lazy.logger.debug("Blur Event");
|
||||
+ if (
|
||||
+ this.document.commandDispatcher.focusedElement == this.inputField &&
|
||||
+ !lazy.UrlbarPrefs.get("closeOnWindowBlur")
|
||||
+ ) {
|
||||
+ return;
|
||||
+ }
|
||||
// We cannot count every blur events after a missed engagement as abandoment
|
||||
// because the user may have clicked on some view element that executes
|
||||
// a command causing a focus change. For example opening preferences from
|
||||
@@ -4964,6 +5091,11 @@ export class UrlbarInput extends HTMLElement {
|
||||
}
|
||||
|
||||
_on_click(event) {
|
||||
@@ -291,7 +319,7 @@ index b23244f9d3278918b016bb3fcab19687bc2e292a..ade1f031bbb68202a37e6c9d3071a73f
|
||||
switch (event.target) {
|
||||
case this.inputField:
|
||||
case this._inputContainer:
|
||||
@@ -5042,7 +5160,7 @@ export class UrlbarInput extends HTMLElement {
|
||||
@@ -5042,7 +5174,7 @@ export class UrlbarInput extends HTMLElement {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,7 +328,7 @@ index b23244f9d3278918b016bb3fcab19687bc2e292a..ade1f031bbb68202a37e6c9d3071a73f
|
||||
this.view.autoOpen({ event });
|
||||
} else {
|
||||
if (this._untrimOnFocusAfterKeydown) {
|
||||
@@ -5082,9 +5200,16 @@ export class UrlbarInput extends HTMLElement {
|
||||
@@ -5082,9 +5214,16 @@ export class UrlbarInput extends HTMLElement {
|
||||
}
|
||||
|
||||
_on_mousedown(event) {
|
||||
@@ -318,7 +346,7 @@ index b23244f9d3278918b016bb3fcab19687bc2e292a..ade1f031bbb68202a37e6c9d3071a73f
|
||||
if (
|
||||
event.composedTarget != this.inputField &&
|
||||
event.composedTarget != this._inputContainer
|
||||
@@ -5094,6 +5219,10 @@ export class UrlbarInput extends HTMLElement {
|
||||
@@ -5094,6 +5233,10 @@ export class UrlbarInput extends HTMLElement {
|
||||
|
||||
this.focusedViaMousedown = !this.focused;
|
||||
this._preventClickSelectsAll = this.focused;
|
||||
@@ -329,7 +357,7 @@ index b23244f9d3278918b016bb3fcab19687bc2e292a..ade1f031bbb68202a37e6c9d3071a73f
|
||||
|
||||
// Keep the focus status, since the attribute may be changed
|
||||
// upon calling this.focus().
|
||||
@@ -5129,7 +5258,7 @@ export class UrlbarInput extends HTMLElement {
|
||||
@@ -5129,7 +5272,7 @@ export class UrlbarInput extends HTMLElement {
|
||||
}
|
||||
// Don't close the view when clicking on a tab; we may want to keep the
|
||||
// view open on tab switch, and the TabSelect event arrived earlier.
|
||||
@@ -338,7 +366,7 @@ index b23244f9d3278918b016bb3fcab19687bc2e292a..ade1f031bbb68202a37e6c9d3071a73f
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -5411,7 +5540,7 @@ export class UrlbarInput extends HTMLElement {
|
||||
@@ -5411,7 +5554,7 @@ export class UrlbarInput extends HTMLElement {
|
||||
// When we are in actions search mode we can show more results so
|
||||
// increase the limit.
|
||||
let maxResults =
|
||||
|
||||
@@ -1,22 +1,37 @@
|
||||
diff --git a/browser/modules/BrowserWindowTracker.sys.mjs b/browser/modules/BrowserWindowTracker.sys.mjs
|
||||
index 9aecab66d8f23fac9f16cea2120a5fe903ae1122..692f2bfe3899a58925789503a6bb2a547cdbf7f3 100644
|
||||
index 9aecab66d8f23fac9f16cea2120a5fe903ae1122..e023c27bcb027d29ba9b3469eca5957d42040c46 100644
|
||||
--- a/browser/modules/BrowserWindowTracker.sys.mjs
|
||||
+++ b/browser/modules/BrowserWindowTracker.sys.mjs
|
||||
@@ -330,6 +330,7 @@ export const BrowserWindowTracker = {
|
||||
@@ -210,7 +210,8 @@ export const BrowserWindowTracker = {
|
||||
!win.closed &&
|
||||
(options.allowPopups || win.toolbar.visible) &&
|
||||
(options.allowTaskbarTabs ||
|
||||
- !win.document.documentElement.hasAttribute("taskbartab")) &&
|
||||
+ (!win.document.documentElement.hasAttribute("taskbartab") &&
|
||||
+ !win.document.documentElement.hasAttribute("zen-little-window"))) &&
|
||||
(!("private" in options) ||
|
||||
lazy.PrivateBrowsingUtils.permanentPrivateBrowsing ||
|
||||
lazy.PrivateBrowsingUtils.isWindowPrivate(win) == options.private)
|
||||
@@ -330,6 +331,8 @@ export const BrowserWindowTracker = {
|
||||
args = null,
|
||||
remote = undefined,
|
||||
fission = undefined,
|
||||
+ zenSyncedWindow = true,
|
||||
+ zenLittleWindow = false,
|
||||
} = options;
|
||||
|
||||
args = lazy.AIWindow.handleAIWindowOptions(options);
|
||||
@@ -386,6 +387,12 @@ export const BrowserWindowTracker = {
|
||||
@@ -386,6 +389,16 @@ export const BrowserWindowTracker = {
|
||||
windowFeatures,
|
||||
args
|
||||
);
|
||||
+ win._zenStartupSyncFlag = Services.prefs.getBoolPref("zen.window-sync.prefer-unsynced-windows")
|
||||
+ ? (zenSyncedWindow ? 'unsynced' : 'synced')
|
||||
+ : (zenSyncedWindow ? 'synced' : 'unsynced');
|
||||
+ if (zenLittleWindow) {
|
||||
+ win._zenStartupLittleWindow = true;
|
||||
+ win._zenStartupSyncFlag = 'unsynced';
|
||||
+ }
|
||||
+ if (win._zenStartupSyncFlag === 'unsynced' && openerWindow) {
|
||||
+ win._zenStartupUnsyncedUserContextId = openerWindow.gZenWorkspaces.getCurrentSpaceContainerId();
|
||||
+ }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
diff --git a/browser/modules/URILoadingHelper.sys.mjs b/browser/modules/URILoadingHelper.sys.mjs
|
||||
index a005dbdf84609622ef8054f73f78c0c290e76125..d5bf6fb51c9af5e60f69a73612ee91598080730a 100644
|
||||
index a005dbdf84609622ef8054f73f78c0c290e76125..2d347ac12d53ae97b61750d421a489ce10af3376 100644
|
||||
--- a/browser/modules/URILoadingHelper.sys.mjs
|
||||
+++ b/browser/modules/URILoadingHelper.sys.mjs
|
||||
@@ -224,6 +224,7 @@ function openInWindow(url, params, sourceWindow) {
|
||||
@@ -19,7 +19,17 @@ index a005dbdf84609622ef8054f73f78c0c290e76125..d5bf6fb51c9af5e60f69a73612ee9159
|
||||
where = "tab";
|
||||
targetBrowser = null;
|
||||
} else if (
|
||||
@@ -974,7 +975,7 @@ export const URILoadingHelper = {
|
||||
@@ -724,7 +725,8 @@ export const URILoadingHelper = {
|
||||
"navigator:browser" &&
|
||||
(!skipPopups || top.toolbar.visible) &&
|
||||
(!skipTaskbarTabs ||
|
||||
- !top.document.documentElement.hasAttribute("taskbartab")) &&
|
||||
+ (!top.document.documentElement.hasAttribute("taskbartab") &&
|
||||
+ !top.document.documentElement.hasAttribute("zen-little-window"))) &&
|
||||
(!forceNonPrivate || !PrivateBrowsingUtils.isWindowPrivate(top))
|
||||
) {
|
||||
return top;
|
||||
@@ -974,7 +976,7 @@ export const URILoadingHelper = {
|
||||
ignoreQueryString || replaceQueryString,
|
||||
ignoreFragmentWhenComparing
|
||||
);
|
||||
@@ -28,7 +38,7 @@ index a005dbdf84609622ef8054f73f78c0c290e76125..d5bf6fb51c9af5e60f69a73612ee9159
|
||||
for (let i = 0; i < browsers.length; i++) {
|
||||
let browser = browsers[i];
|
||||
let browserCompare = cleanURL(
|
||||
@@ -1030,7 +1031,7 @@ export const URILoadingHelper = {
|
||||
@@ -1030,7 +1032,7 @@ export const URILoadingHelper = {
|
||||
);
|
||||
aSplitView.ownerGlobal.focus();
|
||||
} else {
|
||||
|
||||
@@ -16,3 +16,5 @@ category app-startup nsBrowserGlue @mozilla.org/browser/browserglue;1 applicatio
|
||||
#include common/Components.manifest
|
||||
#include sessionstore/SessionComponents.manifest
|
||||
#include live-folders/LiveFoldersComponents.manifest
|
||||
#include kbs/KbsComponents.manifest
|
||||
#include little-window/LittleWindowComponents.manifest
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
"chrome://browser/content/zen-components/ZenCompactMode.mjs",
|
||||
"chrome://browser/content/ZenUIManager.mjs",
|
||||
"chrome://browser/content/zen-components/ZenMods.mjs",
|
||||
"chrome://browser/content/zen-components/ZenKeyboardShortcuts.mjs",
|
||||
"chrome://browser/content/zen-components/ZenSessionStore.mjs",
|
||||
"chrome://browser/content/zen-components/ZenMediaController.mjs",
|
||||
"chrome://browser/content/zen-components/ZenGlanceManager.mjs",
|
||||
|
||||
@@ -32,7 +32,6 @@ class ZenStartup {
|
||||
return;
|
||||
}
|
||||
this.#hasInitializedLayout = true;
|
||||
gZenKeyboardShortcutsManager.beforeInit();
|
||||
try {
|
||||
const kNavbarItems = ["nav-bar", "PersonalToolbar"];
|
||||
const kNewContainerId = "zen-appcontent-navbar-container";
|
||||
|
||||
@@ -942,7 +942,9 @@ window.gZenVerticalTabsManager = {
|
||||
?.includes("toolbar") ||
|
||||
document.documentElement
|
||||
.getAttribute("chromehidden")
|
||||
?.includes("menubar")
|
||||
?.includes("menubar") ||
|
||||
document.documentElement.hasAttribute("zen-little-window") ||
|
||||
window._zenStartupLittleWindow
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1261,7 +1263,8 @@ window.gZenVerticalTabsManager = {
|
||||
|
||||
const topButtons = document.getElementById("zen-sidebar-top-buttons");
|
||||
const isCompactMode =
|
||||
gZenCompactModeManager.preference && !forCustomizableMode;
|
||||
(gZenCompactModeManager.preference && !forCustomizableMode) ||
|
||||
this.hidesTabsToolbar;
|
||||
const isVerticalTabs = this._prefsVerticalTabs || forCustomizableMode;
|
||||
const isSidebarExpanded = this._prefsSidebarExpanded || !isVerticalTabs;
|
||||
const isRightSide = this._prefsRightSide && isVerticalTabs;
|
||||
|
||||
@@ -293,7 +293,7 @@
|
||||
}
|
||||
|
||||
#main-window[windowtype="navigator:browser"]:not([chromehidden~='toolbar']) {
|
||||
min-height: 495px !important;
|
||||
min-height: var(--zen-minimum-window-height, 495px) !important;
|
||||
|
||||
@media (-moz-windows-mica) or (-moz-platform: macos) or ((-moz-platform: linux) and
|
||||
-moz-pref('zen.widget.linux.transparency')) {
|
||||
|
||||
@@ -136,6 +136,13 @@ document.addEventListener(
|
||||
case "cmd_zenNewNavigatorUnsynced":
|
||||
OpenBrowserWindow({ zenSyncedWindow: false });
|
||||
break;
|
||||
case "cmd_zenNewLittleWindow": {
|
||||
const { ZenLittleWindow } = ChromeUtils.importESModule(
|
||||
"resource:///modules/zen/ZenLittleWindow.sys.mjs"
|
||||
);
|
||||
ZenLittleWindow.openLittleWindow(window);
|
||||
break;
|
||||
}
|
||||
case "cmd_zenNewLiveFolder": {
|
||||
const { ZenLiveFoldersManager } = ChromeUtils.importESModule(
|
||||
"resource:///modules/zen/ZenLiveFoldersManager.sys.mjs"
|
||||
|
||||
@@ -158,6 +158,14 @@
|
||||
) {
|
||||
separation = 0;
|
||||
}
|
||||
// Little windows are visually a single floating bar; we never want
|
||||
// chrome padding around them.
|
||||
if (
|
||||
document.documentElement.hasAttribute("zen-little-window") ||
|
||||
window._zenStartupLittleWindow
|
||||
) {
|
||||
separation = 0;
|
||||
}
|
||||
// In order to still use it on fullscreen, even if it's 0px, add .1px (almost invisible)
|
||||
separation = Math.max(kMinElementSeparation, separation);
|
||||
document.documentElement.style.setProperty(
|
||||
|
||||
@@ -126,6 +126,9 @@ window.gZenCompactModeManager = {
|
||||
},
|
||||
|
||||
get shouldBeCompact() {
|
||||
if (document.documentElement.hasAttribute("zen-little-window")) {
|
||||
return false;
|
||||
}
|
||||
return !document.documentElement
|
||||
.getAttribute("chromehidden")
|
||||
?.includes("toolbar");
|
||||
|
||||
6
src/zen/kbs/KbsComponents.manifest
Normal file
6
src/zen/kbs/KbsComponents.manifest
Normal file
@@ -0,0 +1,6 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
category browser-before-ui-startup resource:///modules/zen/ZenKeyboardShortcuts.sys.mjs ZenKeyboardShortcuts.init
|
||||
category browser-quit-application-granted resource:///modules/zen/ZenKeyboardShortcuts.sys.mjs ZenKeyboardShortcuts.uninit
|
||||
File diff suppressed because it is too large
Load Diff
134
src/zen/kbs/global-shortcuts/ZenGlobalShortcuts.cpp
Normal file
134
src/zen/kbs/global-shortcuts/ZenGlobalShortcuts.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ZenGlobalShortcuts.h"
|
||||
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsGlobalWindowOuter.h"
|
||||
#include "nsIWindowMediator.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
namespace zen {
|
||||
|
||||
ZenGlobalShortcuts* ZenGlobalShortcuts::sInstance = nullptr;
|
||||
|
||||
NS_IMPL_ISUPPORTS(ZenGlobalShortcuts, nsIZenGlobalShortcuts)
|
||||
|
||||
ZenGlobalShortcuts::ZenGlobalShortcuts() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!sInstance);
|
||||
sInstance = this;
|
||||
}
|
||||
|
||||
ZenGlobalShortcuts::~ZenGlobalShortcuts() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
for (auto& reg : mRegistrations) {
|
||||
NativeUnregister(reg);
|
||||
}
|
||||
mRegistrations.Clear();
|
||||
NativeShutdown();
|
||||
sInstance = nullptr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ZenGlobalShortcuts::RegisterShortcut(const nsACString& aId,
|
||||
const nsACString& aKey,
|
||||
uint32_t aModifiers, bool* aRetVal) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
*aRetVal = false;
|
||||
|
||||
for (const auto& reg : mRegistrations) {
|
||||
if (reg.id.Equals(aId)) return NS_ERROR_ALREADY_INITIALIZED;
|
||||
}
|
||||
|
||||
Registration reg;
|
||||
reg.id = aId;
|
||||
reg.internalId = mNextInternalId++;
|
||||
|
||||
if (NS_FAILED(NativeRegister(reg, aKey, aModifiers))) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mRegistrations.AppendElement(std::move(reg));
|
||||
*aRetVal = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ZenGlobalShortcuts::UnregisterShortcut(const nsACString& aId) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
for (size_t i = 0; i < mRegistrations.Length(); ++i) {
|
||||
if (mRegistrations[i].id.Equals(aId)) {
|
||||
NativeUnregister(mRegistrations[i]);
|
||||
mRegistrations.RemoveElementAt(i);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ZenGlobalShortcuts::UnregisterAll() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
for (auto& reg : mRegistrations) {
|
||||
NativeUnregister(reg);
|
||||
}
|
||||
mRegistrations.Clear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
const ZenGlobalShortcuts::Registration* ZenGlobalShortcuts::FindByInternalId(
|
||||
uint32_t aInternalId) const {
|
||||
for (const auto& reg : mRegistrations) {
|
||||
if (reg.internalId == aInternalId) return ®
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// static
|
||||
void ZenGlobalShortcuts::OnNativeShortcut(uint32_t aInternalId) {
|
||||
if (!NS_IsMainThread()) {
|
||||
NS_DispatchToMainThread(NS_NewRunnableFunction(
|
||||
"ZenGlobalShortcuts::OnNativeShortcut",
|
||||
[aInternalId]() { OnNativeShortcut(aInternalId); }));
|
||||
return;
|
||||
}
|
||||
if (!sInstance) return;
|
||||
|
||||
const Registration* reg = sInstance->FindByInternalId(aInternalId);
|
||||
if (!reg) return;
|
||||
DispatchEventForId(reg->id);
|
||||
}
|
||||
|
||||
// static
|
||||
void ZenGlobalShortcuts::DispatchEventForId(const nsACString& aId) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsCOMPtr<nsIWindowMediator> med = do_GetService(NS_WINDOWMEDIATOR_CONTRACTID);
|
||||
if (!med) return;
|
||||
|
||||
nsCOMPtr<mozIDOMWindowProxy> mostRecent;
|
||||
med->GetMostRecentBrowserWindow(getter_AddRefs(mostRecent));
|
||||
if (!mostRecent) return;
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowOuter> outer = nsPIDOMWindowOuter::From(mostRecent);
|
||||
if (!outer) return;
|
||||
|
||||
RefPtr<mozilla::dom::Document> doc = outer->GetExtantDoc();
|
||||
if (!doc) return;
|
||||
|
||||
nsAutoString eventName;
|
||||
eventName.AssignLiteral(u"zen-global-shortcut-");
|
||||
AppendUTF8toUTF16(aId, eventName);
|
||||
|
||||
nsContentUtils::DispatchTrustedEvent(doc, nsGlobalWindowOuter::Cast(outer),
|
||||
eventName, mozilla::CanBubble::eYes,
|
||||
mozilla::Cancelable::eNo);
|
||||
}
|
||||
|
||||
} // namespace zen
|
||||
61
src/zen/kbs/global-shortcuts/ZenGlobalShortcuts.h
Normal file
61
src/zen/kbs/global-shortcuts/ZenGlobalShortcuts.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_ZenGlobalShortcuts_h_
|
||||
#define mozilla_ZenGlobalShortcuts_h_
|
||||
|
||||
#include "nsIZenGlobalShortcuts.h"
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
namespace zen {
|
||||
|
||||
/**
|
||||
* @brief Singleton XPCOM service that registers OS-level global hotkeys
|
||||
* and dispatches a trusted DOM event on the most recently focused
|
||||
* browser window when one fires.
|
||||
*/
|
||||
class ZenGlobalShortcuts final : public nsIZenGlobalShortcuts {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIZENGLOBALSHORTCUTS
|
||||
|
||||
ZenGlobalShortcuts();
|
||||
|
||||
// Per-shortcut record. Public so the per-OS backend can read/write its
|
||||
// fields directly without going through accessors.
|
||||
struct Registration {
|
||||
nsCString id;
|
||||
uint32_t internalId = 0;
|
||||
void* nativeHandle = nullptr;
|
||||
};
|
||||
|
||||
// Called by the per-OS layer when a registered shortcut is triggered
|
||||
// by the system. Safe to call from any thread; bounces to the main
|
||||
// thread before touching DOM state.
|
||||
static void OnNativeShortcut(uint32_t aInternalId);
|
||||
|
||||
private:
|
||||
~ZenGlobalShortcuts();
|
||||
|
||||
static ZenGlobalShortcuts* sInstance;
|
||||
|
||||
const Registration* FindByInternalId(uint32_t aInternalId) const;
|
||||
static void DispatchEventForId(const nsACString& aId);
|
||||
|
||||
// Per-OS implementations live in cocoa/, windows/, or the stub.
|
||||
static nsresult NativeRegister(Registration& aReg, const nsACString& aKey,
|
||||
uint32_t aModifiers);
|
||||
static void NativeUnregister(Registration& aReg);
|
||||
static void NativeShutdown();
|
||||
|
||||
nsTArray<Registration> mRegistrations;
|
||||
uint32_t mNextInternalId = 1;
|
||||
};
|
||||
|
||||
} // namespace zen
|
||||
|
||||
#endif
|
||||
27
src/zen/kbs/global-shortcuts/ZenGlobalShortcutsStub.cpp
Normal file
27
src/zen/kbs/global-shortcuts/ZenGlobalShortcutsStub.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ZenGlobalShortcuts.h"
|
||||
|
||||
// Linux/other-toolkit fallback. A real implementation needs X11
|
||||
// XGrabKey on the root window or, on Wayland, the
|
||||
// org.freedesktop.portal.GlobalShortcuts portal over D-Bus. Until one
|
||||
// is added, registrations always fail and JS-side code can fall back
|
||||
// to in-window shortcuts.
|
||||
|
||||
namespace zen {
|
||||
|
||||
// static
|
||||
nsresult ZenGlobalShortcuts::NativeRegister(Registration&, const nsACString&,
|
||||
uint32_t) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
// static
|
||||
void ZenGlobalShortcuts::NativeUnregister(Registration&) {}
|
||||
|
||||
// static
|
||||
void ZenGlobalShortcuts::NativeShutdown() {}
|
||||
|
||||
} // namespace zen
|
||||
210
src/zen/kbs/global-shortcuts/cocoa/ZenGlobalShortcutsCocoa.mm
Normal file
210
src/zen/kbs/global-shortcuts/cocoa/ZenGlobalShortcutsCocoa.mm
Normal file
@@ -0,0 +1,210 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ZenGlobalShortcuts.h"
|
||||
|
||||
#include "mozilla/TextEvents.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsString.h"
|
||||
|
||||
#import <Carbon/Carbon.h>
|
||||
|
||||
namespace zen {
|
||||
namespace {
|
||||
|
||||
using mozilla::CodeNameIndex;
|
||||
using mozilla::WidgetKeyboardEvent;
|
||||
|
||||
constexpr FourCharCode kZenHotKeySignature = 'zen ';
|
||||
|
||||
// Mozilla-internal aliases referenced by NativeKeyToDOMCodeName.inc but
|
||||
// not part of Carbon. Mirrors widget/cocoa/TextInputHandler.h so we
|
||||
// don't need to drag the whole header in.
|
||||
enum {
|
||||
kVK_PC_ContextMenu = 0x6E,
|
||||
kVK_Powerbook_KeypadEnter = 0x34,
|
||||
};
|
||||
|
||||
class MacGlobalShortcuts final {
|
||||
public:
|
||||
MacGlobalShortcuts() = delete;
|
||||
|
||||
static nsresult Register(ZenGlobalShortcuts::Registration& aReg,
|
||||
const nsACString& aKey, uint32_t aModifiers);
|
||||
static void Unregister(ZenGlobalShortcuts::Registration& aReg);
|
||||
static void Shutdown();
|
||||
|
||||
private:
|
||||
static bool EnsureHandler();
|
||||
static OSStatus HandleHotKey(EventHandlerCallRef, EventRef, void*);
|
||||
static bool ResolveKey(const nsACString& aKey, UInt32& aOut);
|
||||
static UInt32 ToCarbonModifiers(uint32_t aMods);
|
||||
|
||||
static EventHandlerUPP sUPP;
|
||||
static EventHandlerRef sHandler;
|
||||
};
|
||||
|
||||
EventHandlerUPP MacGlobalShortcuts::sUPP = nullptr;
|
||||
EventHandlerRef MacGlobalShortcuts::sHandler = nullptr;
|
||||
|
||||
// static
|
||||
OSStatus MacGlobalShortcuts::HandleHotKey(EventHandlerCallRef, EventRef inEvent,
|
||||
void*) {
|
||||
EventHotKeyID hkID;
|
||||
if (GetEventParameter(inEvent, kEventParamDirectObject, typeEventHotKeyID,
|
||||
nullptr, sizeof(hkID), nullptr, &hkID) == noErr) {
|
||||
ZenGlobalShortcuts::OnNativeShortcut(hkID.id);
|
||||
}
|
||||
return noErr;
|
||||
}
|
||||
|
||||
// static
|
||||
bool MacGlobalShortcuts::EnsureHandler() {
|
||||
if (sHandler) return true;
|
||||
|
||||
sUPP = NewEventHandlerUPP(HandleHotKey);
|
||||
if (!sUPP) return false;
|
||||
|
||||
EventTypeSpec spec = {kEventClassKeyboard, kEventHotKeyPressed};
|
||||
OSStatus status =
|
||||
InstallApplicationEventHandler(sUPP, 1, &spec, nullptr, &sHandler);
|
||||
if (status != noErr) {
|
||||
DisposeEventHandlerUPP(sUPP);
|
||||
sUPP = nullptr;
|
||||
sHandler = nullptr;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Convert the JS-friendly key string into a DOM code-name (e.g. "A" ->
|
||||
// "KeyA", "5" -> "Digit5", "F1"/"f1" -> "F1", "Space"/"space" -> "Space").
|
||||
// Returns false for inputs we don't accept.
|
||||
static bool ToDOMCodeName(const nsACString& aKey, nsAString& aOut) {
|
||||
aOut.Truncate();
|
||||
if (aKey.Length() == 1) {
|
||||
char c = aKey[0];
|
||||
if (c >= 'a' && c <= 'z') c = char(c - 32);
|
||||
if (c >= 'A' && c <= 'Z') {
|
||||
aOut.AssignLiteral(u"Key");
|
||||
} else if (c >= '0' && c <= '9') {
|
||||
aOut.AssignLiteral(u"Digit");
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
aOut.Append(char16_t(c));
|
||||
return true;
|
||||
}
|
||||
// Multi-character: assume it's a DOM code name, normalized to leading
|
||||
// upper-case ("space" -> "Space", "f1" -> "F1").
|
||||
AppendUTF8toUTF16(aKey, aOut);
|
||||
if (!aOut.IsEmpty() && aOut[0] >= 'a' && aOut[0] <= 'z') {
|
||||
aOut.BeginWriting()[0] = char16_t(aOut[0] - 32);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
struct CodeIndexToMacKey {
|
||||
CodeNameIndex idx;
|
||||
UInt32 keyCode;
|
||||
};
|
||||
|
||||
// Generated from widget's mapping table. Order matches the .inc, so when
|
||||
// multiple native keys map to the same DOM code (e.g. NumpadEnter ->
|
||||
// kVK_ANSI_KeypadEnter and kVK_Powerbook_KeypadEnter), the first entry
|
||||
// wins -- which is the one we'd want to pass to RegisterEventHotKey.
|
||||
static constexpr CodeIndexToMacKey kCodeIndexToMacKeyTable[] = {
|
||||
#define NS_NATIVE_KEY_TO_DOM_CODE_NAME_INDEX(aNativeKey, aCodeNameIndex) \
|
||||
{mozilla::aCodeNameIndex, static_cast<UInt32>(aNativeKey)},
|
||||
#include "NativeKeyToDOMCodeName.inc"
|
||||
#undef NS_NATIVE_KEY_TO_DOM_CODE_NAME_INDEX
|
||||
};
|
||||
|
||||
// static
|
||||
bool MacGlobalShortcuts::ResolveKey(const nsACString& aKey, UInt32& aOut) {
|
||||
nsAutoString domCode;
|
||||
if (!ToDOMCodeName(aKey, domCode)) return false;
|
||||
|
||||
CodeNameIndex idx = WidgetKeyboardEvent::GetCodeNameIndex(domCode);
|
||||
if (idx == mozilla::CODE_NAME_INDEX_USE_STRING) return false;
|
||||
|
||||
for (const auto& entry : kCodeIndexToMacKeyTable) {
|
||||
if (entry.idx == idx) {
|
||||
aOut = entry.keyCode;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// static
|
||||
UInt32 MacGlobalShortcuts::ToCarbonModifiers(uint32_t aMods) {
|
||||
UInt32 m = 0;
|
||||
if (aMods & nsIZenGlobalShortcuts::MODIFIER_SHIFT) m |= shiftKey;
|
||||
if (aMods & nsIZenGlobalShortcuts::MODIFIER_CTRL) m |= controlKey;
|
||||
if (aMods & nsIZenGlobalShortcuts::MODIFIER_ALT) m |= optionKey;
|
||||
if (aMods & nsIZenGlobalShortcuts::MODIFIER_META) m |= cmdKey;
|
||||
return m;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult MacGlobalShortcuts::Register(ZenGlobalShortcuts::Registration& aReg,
|
||||
const nsACString& aKey,
|
||||
uint32_t aModifiers) {
|
||||
if (!EnsureHandler()) return NS_ERROR_FAILURE;
|
||||
|
||||
UInt32 keyCode;
|
||||
if (!ResolveKey(aKey, keyCode)) return NS_ERROR_INVALID_ARG;
|
||||
|
||||
EventHotKeyID hkID;
|
||||
hkID.signature = kZenHotKeySignature;
|
||||
hkID.id = aReg.internalId;
|
||||
|
||||
EventHotKeyRef ref = nullptr;
|
||||
OSStatus status =
|
||||
RegisterEventHotKey(keyCode, ToCarbonModifiers(aModifiers), hkID,
|
||||
GetApplicationEventTarget(), 0, &ref);
|
||||
if (status != noErr || !ref) return NS_ERROR_FAILURE;
|
||||
|
||||
aReg.nativeHandle = static_cast<void*>(ref);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
void MacGlobalShortcuts::Unregister(ZenGlobalShortcuts::Registration& aReg) {
|
||||
if (!aReg.nativeHandle) return;
|
||||
UnregisterEventHotKey(static_cast<EventHotKeyRef>(aReg.nativeHandle));
|
||||
aReg.nativeHandle = nullptr;
|
||||
}
|
||||
|
||||
// static
|
||||
void MacGlobalShortcuts::Shutdown() {
|
||||
if (sHandler) {
|
||||
RemoveEventHandler(sHandler);
|
||||
sHandler = nullptr;
|
||||
}
|
||||
if (sUPP) {
|
||||
DisposeEventHandlerUPP(sUPP);
|
||||
sUPP = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
nsresult ZenGlobalShortcuts::NativeRegister(Registration& aReg,
|
||||
const nsACString& aKey,
|
||||
uint32_t aModifiers) {
|
||||
return MacGlobalShortcuts::Register(aReg, aKey, aModifiers);
|
||||
}
|
||||
|
||||
// static
|
||||
void ZenGlobalShortcuts::NativeUnregister(Registration& aReg) {
|
||||
MacGlobalShortcuts::Unregister(aReg);
|
||||
}
|
||||
|
||||
// static
|
||||
void ZenGlobalShortcuts::NativeShutdown() { MacGlobalShortcuts::Shutdown(); }
|
||||
|
||||
} // namespace zen
|
||||
18
src/zen/kbs/global-shortcuts/cocoa/moz.build
Normal file
18
src/zen/kbs/global-shortcuts/cocoa/moz.build
Normal file
@@ -0,0 +1,18 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
FINAL_LIBRARY = "xul"
|
||||
|
||||
SOURCES += [
|
||||
"ZenGlobalShortcutsCocoa.mm",
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
"../",
|
||||
"/widget",
|
||||
]
|
||||
|
||||
OS_LIBS += [
|
||||
"-framework Carbon",
|
||||
]
|
||||
14
src/zen/kbs/global-shortcuts/components.conf
Normal file
14
src/zen/kbs/global-shortcuts/components.conf
Normal file
@@ -0,0 +1,14 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
Classes = [
|
||||
{
|
||||
'cid': '{b8e9f3a2-7c1d-4a5b-9e6f-3d8c2a1b5e74}',
|
||||
'interfaces': ['nsIZenGlobalShortcuts'],
|
||||
'contract_ids': ['@mozilla.org/zen/global-shortcuts;1'],
|
||||
'type': 'zen::ZenGlobalShortcuts',
|
||||
'headers': ['mozilla/ZenGlobalShortcuts.h'],
|
||||
'processes': ProcessSelector.MAIN_PROCESS_ONLY,
|
||||
},
|
||||
]
|
||||
29
src/zen/kbs/global-shortcuts/moz.build
Normal file
29
src/zen/kbs/global-shortcuts/moz.build
Normal file
@@ -0,0 +1,29 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
"nsIZenGlobalShortcuts.idl",
|
||||
]
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
"ZenGlobalShortcuts.h",
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
"ZenGlobalShortcuts.cpp",
|
||||
]
|
||||
|
||||
XPCOM_MANIFESTS += [
|
||||
"components.conf",
|
||||
]
|
||||
|
||||
if CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa":
|
||||
DIRS += ["cocoa"]
|
||||
elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "windows":
|
||||
DIRS += ["windows"]
|
||||
else:
|
||||
SOURCES += ["ZenGlobalShortcutsStub.cpp"]
|
||||
|
||||
FINAL_LIBRARY = "xul"
|
||||
XPIDL_MODULE = "zen_global_shortcuts"
|
||||
49
src/zen/kbs/global-shortcuts/nsIZenGlobalShortcuts.idl
Normal file
49
src/zen/kbs/global-shortcuts/nsIZenGlobalShortcuts.idl
Normal file
@@ -0,0 +1,49 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
/**
|
||||
* @brief OS-level global keyboard shortcut registration for Zen.
|
||||
*
|
||||
* Registers shortcuts with the operating system so that pressing the
|
||||
* key combination triggers a callback even when no Zen window is
|
||||
* focused (or the application is in the background). When a shortcut
|
||||
* fires, a trusted DOM event is dispatched on the most recently
|
||||
* focused browser window. The event type is
|
||||
* "zen-global-shortcut-<id>", where <id> is the identifier passed at
|
||||
* registration time.
|
||||
*/
|
||||
[scriptable, uuid(b8e9f3a2-7c1d-4a5b-9e6f-3d8c2a1b5e74)]
|
||||
interface nsIZenGlobalShortcuts : nsISupports {
|
||||
const unsigned long MODIFIER_NONE = 0;
|
||||
const unsigned long MODIFIER_SHIFT = 1;
|
||||
const unsigned long MODIFIER_CTRL = 2;
|
||||
const unsigned long MODIFIER_ALT = 4;
|
||||
const unsigned long MODIFIER_META = 8;
|
||||
|
||||
/**
|
||||
* @brief Register a global keyboard shortcut.
|
||||
* @param aId Caller-chosen identifier; the dispatched event name will be
|
||||
* "zen-global-shortcut-" + aId. Must be unique across active
|
||||
* registrations.
|
||||
* @param aKey Key name. Supported: "A".."Z", "0".."9", "F1".."F12",
|
||||
* "Space".
|
||||
* @param aModifiers Bitmask of MODIFIER_* constants. On macOS, META
|
||||
* is Command; on Windows, META is the Windows key.
|
||||
* @return true if the OS accepted the registration.
|
||||
*/
|
||||
boolean registerShortcut(in ACString aId, in ACString aKey,
|
||||
in unsigned long aModifiers);
|
||||
|
||||
/**
|
||||
* @brief Unregister a previously registered shortcut by id.
|
||||
*/
|
||||
void unregisterShortcut(in ACString aId);
|
||||
|
||||
/**
|
||||
* @brief Unregister all shortcuts registered through this service.
|
||||
*/
|
||||
void unregisterAll();
|
||||
};
|
||||
@@ -0,0 +1,166 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ZenGlobalShortcuts.h"
|
||||
|
||||
#include "nsString.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
namespace zen {
|
||||
namespace {
|
||||
|
||||
constexpr wchar_t kWindowClassName[] = L"ZenGlobalShortcutsWindow";
|
||||
|
||||
class WinGlobalShortcuts final {
|
||||
public:
|
||||
WinGlobalShortcuts() = delete;
|
||||
|
||||
static nsresult Register(ZenGlobalShortcuts::Registration& aReg,
|
||||
const nsACString& aKey, uint32_t aModifiers);
|
||||
static void Unregister(ZenGlobalShortcuts::Registration& aReg);
|
||||
static void Shutdown();
|
||||
|
||||
private:
|
||||
static bool EnsureWindow();
|
||||
static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
|
||||
static bool ResolveKey(const nsACString& aKey, UINT& aOut);
|
||||
static UINT ToWinModifiers(uint32_t aMods);
|
||||
|
||||
static HWND sWindow;
|
||||
static ATOM sClass;
|
||||
};
|
||||
|
||||
HWND WinGlobalShortcuts::sWindow = nullptr;
|
||||
ATOM WinGlobalShortcuts::sClass = 0;
|
||||
|
||||
// static
|
||||
LRESULT CALLBACK WinGlobalShortcuts::WndProc(HWND hwnd, UINT msg, WPARAM wParam,
|
||||
LPARAM lParam) {
|
||||
if (msg == WM_HOTKEY) {
|
||||
ZenGlobalShortcuts::OnNativeShortcut(static_cast<uint32_t>(wParam));
|
||||
return 0;
|
||||
}
|
||||
return DefWindowProcW(hwnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
// static
|
||||
bool WinGlobalShortcuts::EnsureWindow() {
|
||||
if (sWindow) return true;
|
||||
|
||||
HINSTANCE module = GetModuleHandleW(nullptr);
|
||||
if (!sClass) {
|
||||
WNDCLASSEXW wc = {};
|
||||
wc.cbSize = sizeof(wc);
|
||||
wc.lpfnWndProc = WndProc;
|
||||
wc.hInstance = module;
|
||||
wc.lpszClassName = kWindowClassName;
|
||||
sClass = RegisterClassExW(&wc);
|
||||
if (!sClass) return false;
|
||||
}
|
||||
|
||||
sWindow = CreateWindowExW(0, kWindowClassName, L"", 0, 0, 0, 0, 0,
|
||||
HWND_MESSAGE, nullptr, module, nullptr);
|
||||
return sWindow != nullptr;
|
||||
}
|
||||
|
||||
// static
|
||||
bool WinGlobalShortcuts::ResolveKey(const nsACString& aKey, UINT& aOut) {
|
||||
if (aKey.Length() == 1) {
|
||||
char c = aKey[0];
|
||||
if (c >= 'a' && c <= 'z') c = char(c - 32);
|
||||
if ((c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) {
|
||||
aOut = static_cast<UINT>(c);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (aKey.LowerCaseEqualsLiteral("space")) {
|
||||
aOut = VK_SPACE;
|
||||
return true;
|
||||
}
|
||||
if ((aKey.Length() == 2 || aKey.Length() == 3) &&
|
||||
(aKey[0] == 'F' || aKey[0] == 'f')) {
|
||||
int n = aKey[1] - '0';
|
||||
if (n < 0 || n > 9) return false;
|
||||
if (aKey.Length() == 3) {
|
||||
int d = aKey[2] - '0';
|
||||
if (d < 0 || d > 9) return false;
|
||||
n = n * 10 + d;
|
||||
}
|
||||
if (n >= 1 && n <= 12) {
|
||||
aOut = VK_F1 + (n - 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// static
|
||||
UINT WinGlobalShortcuts::ToWinModifiers(uint32_t aMods) {
|
||||
UINT m = MOD_NOREPEAT;
|
||||
if (aMods & nsIZenGlobalShortcuts::MODIFIER_SHIFT) m |= MOD_SHIFT;
|
||||
if (aMods & nsIZenGlobalShortcuts::MODIFIER_CTRL) m |= MOD_CONTROL;
|
||||
if (aMods & nsIZenGlobalShortcuts::MODIFIER_ALT) m |= MOD_ALT;
|
||||
if (aMods & nsIZenGlobalShortcuts::MODIFIER_META) m |= MOD_WIN;
|
||||
return m;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult WinGlobalShortcuts::Register(ZenGlobalShortcuts::Registration& aReg,
|
||||
const nsACString& aKey,
|
||||
uint32_t aModifiers) {
|
||||
if (!EnsureWindow()) return NS_ERROR_FAILURE;
|
||||
|
||||
UINT vk;
|
||||
if (!ResolveKey(aKey, vk)) return NS_ERROR_INVALID_ARG;
|
||||
|
||||
if (!RegisterHotKey(sWindow, static_cast<int>(aReg.internalId),
|
||||
ToWinModifiers(aModifiers), vk)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
aReg.nativeHandle =
|
||||
reinterpret_cast<void*>(static_cast<uintptr_t>(aReg.internalId));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
void WinGlobalShortcuts::Unregister(ZenGlobalShortcuts::Registration& aReg) {
|
||||
if (!sWindow || !aReg.nativeHandle) return;
|
||||
UnregisterHotKey(
|
||||
sWindow,
|
||||
static_cast<int>(reinterpret_cast<uintptr_t>(aReg.nativeHandle)));
|
||||
aReg.nativeHandle = nullptr;
|
||||
}
|
||||
|
||||
// static
|
||||
void WinGlobalShortcuts::Shutdown() {
|
||||
if (sWindow) {
|
||||
DestroyWindow(sWindow);
|
||||
sWindow = nullptr;
|
||||
}
|
||||
if (sClass) {
|
||||
UnregisterClassW(kWindowClassName, GetModuleHandleW(nullptr));
|
||||
sClass = 0;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
nsresult ZenGlobalShortcuts::NativeRegister(Registration& aReg,
|
||||
const nsACString& aKey,
|
||||
uint32_t aModifiers) {
|
||||
return WinGlobalShortcuts::Register(aReg, aKey, aModifiers);
|
||||
}
|
||||
|
||||
// static
|
||||
void ZenGlobalShortcuts::NativeUnregister(Registration& aReg) {
|
||||
WinGlobalShortcuts::Unregister(aReg);
|
||||
}
|
||||
|
||||
// static
|
||||
void ZenGlobalShortcuts::NativeShutdown() { WinGlobalShortcuts::Shutdown(); }
|
||||
|
||||
} // namespace zen
|
||||
@@ -2,4 +2,12 @@
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
content/browser/zen-components/ZenKeyboardShortcuts.mjs (../../zen/kbs/ZenKeyboardShortcuts.mjs)
|
||||
FINAL_LIBRARY = "xul"
|
||||
|
||||
SOURCES += [
|
||||
"ZenGlobalShortcutsWindows.cpp",
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
"../",
|
||||
]
|
||||
11
src/zen/kbs/moz.build
Normal file
11
src/zen/kbs/moz.build
Normal file
@@ -0,0 +1,11 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXTRA_JS_MODULES.zen += [
|
||||
"ZenKeyboardShortcuts.sys.mjs",
|
||||
]
|
||||
|
||||
DIRS += [
|
||||
"global-shortcuts",
|
||||
]
|
||||
6
src/zen/little-window/LittleWindowComponents.manifest
Normal file
6
src/zen/little-window/LittleWindowComponents.manifest
Normal file
@@ -0,0 +1,6 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
category browser-before-ui-startup resource:///modules/zen/ZenLittleWindow.sys.mjs ZenLittleWindow.init
|
||||
category browser-quit-application-granted resource:///modules/zen/ZenLittleWindow.sys.mjs ZenLittleWindow.uninit
|
||||
110
src/zen/little-window/ZenLittleWindow.sys.mjs
Normal file
110
src/zen/little-window/ZenLittleWindow.sys.mjs
Normal file
@@ -0,0 +1,110 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const URLBAR_HEIGHT = 340;
|
||||
const URLBAR_WIDTH = 640;
|
||||
|
||||
const FEATURES =
|
||||
"titlebar,close,toolbar,location,personalbar=no,status,menubar=no," +
|
||||
`resizable,minimizable,scrollbars,width=${URLBAR_WIDTH},height=${URLBAR_HEIGHT},centerscreen`;
|
||||
|
||||
class nsZenLittleWindow {
|
||||
#initialized = false;
|
||||
|
||||
init() {
|
||||
if (this.#initialized) {
|
||||
return;
|
||||
}
|
||||
this.#initialized = true;
|
||||
Services.obs.addObserver(this, "browser-window-before-show");
|
||||
}
|
||||
|
||||
uninit() {
|
||||
if (!this.#initialized) {
|
||||
return;
|
||||
}
|
||||
this.#initialized = false;
|
||||
try {
|
||||
Services.obs.removeObserver(this, "browser-window-before-show");
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
observe(subject, topic) {
|
||||
if (
|
||||
topic === "browser-window-before-show" &&
|
||||
this.#isLittleWindow(subject)
|
||||
) {
|
||||
this.#attachAutoclose(subject);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a fresh little window, or focus an existing empty one if there
|
||||
* already is a little window sitting on its empty tab.
|
||||
*
|
||||
* @param {Window} opener The browser window asking for the little window.
|
||||
* @returns {Window|null} The window that received focus.
|
||||
*/
|
||||
openLittleWindow(opener) {
|
||||
for (const win of this.#iterLittleWindows()) {
|
||||
if (this.#isOnEmptyTab(win)) {
|
||||
win.focus();
|
||||
return win;
|
||||
}
|
||||
}
|
||||
if (typeof opener?.OpenBrowserWindow !== "function") {
|
||||
return null;
|
||||
}
|
||||
let win = opener.OpenBrowserWindow({
|
||||
zenLittleWindow: true,
|
||||
all: false,
|
||||
features: FEATURES,
|
||||
});
|
||||
win.focus();
|
||||
return win;
|
||||
}
|
||||
|
||||
#isLittleWindow(win) {
|
||||
return (
|
||||
!!win._zenStartupLittleWindow ||
|
||||
win.document?.documentElement?.hasAttribute("zen-little-window")
|
||||
);
|
||||
}
|
||||
|
||||
#isOnEmptyTab(win) {
|
||||
const tab = win.gBrowser?.selectedTab;
|
||||
return !!tab?.hasAttribute("zen-empty-tab");
|
||||
}
|
||||
|
||||
*#iterLittleWindows() {
|
||||
const en = Services.wm.getEnumerator("navigator:browser");
|
||||
while (en.hasMoreElements()) {
|
||||
const win = en.getNext();
|
||||
if (!win.closed && this.#isLittleWindow(win)) {
|
||||
yield win;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#attachAutoclose(win) {
|
||||
const onClosed = event => {
|
||||
if (event.detail?.onElementPicked && event.type === "ZenURLBarClosed") {
|
||||
return;
|
||||
}
|
||||
if (!win.closed && this.#isOnEmptyTab(win)) {
|
||||
win.close();
|
||||
} else {
|
||||
// Resize window back to normal size
|
||||
win.resizeTo(1240, 840);
|
||||
}
|
||||
};
|
||||
win.document.documentElement.setAttribute("zen-little-window", "true");
|
||||
win.resizeTo(URLBAR_WIDTH, URLBAR_HEIGHT);
|
||||
win.focus();
|
||||
win.addEventListener("ZenURLBarClosed", onClosed, { once: true });
|
||||
win.addEventListener("blur", onClosed, { once: true });
|
||||
}
|
||||
}
|
||||
|
||||
export const ZenLittleWindow = new nsZenLittleWindow();
|
||||
5
src/zen/little-window/jar.inc.mn
Normal file
5
src/zen/little-window/jar.inc.mn
Normal file
@@ -0,0 +1,5 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
content/browser/zen-styles/zen-little-window.css (../../zen/little-window/zen-little-window.css)
|
||||
7
src/zen/little-window/moz.build
Normal file
7
src/zen/little-window/moz.build
Normal file
@@ -0,0 +1,7 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXTRA_JS_MODULES.zen += [
|
||||
"ZenLittleWindow.sys.mjs",
|
||||
]
|
||||
52
src/zen/little-window/zen-little-window.css
Normal file
52
src/zen/little-window/zen-little-window.css
Normal file
@@ -0,0 +1,52 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/*
|
||||
* Little-window chrome: the URL bar fills the entire window. The vertical
|
||||
* tab strip, sidebar buttons, bookmarks toolbar, and any other chrome are
|
||||
* suppressed so the window acts as a quick search/launch box.
|
||||
*/
|
||||
|
||||
:root[zen-little-window="true"] {
|
||||
/*
|
||||
* The navigator toolbox (sidebar + tab strip) and its splitter are
|
||||
* never visible in a little window. We use visibility: hidden rather
|
||||
* than display: none so layout stays stable and the urlbar floats
|
||||
* cleanly over its slot.
|
||||
*/
|
||||
#navigator-toolbox,
|
||||
#zen-sidebar-splitter {
|
||||
visibility: collapse !important;
|
||||
}
|
||||
|
||||
&[zen-has-empty-tab="true"] {
|
||||
/* Keep in sync with URLBAR_HEIGHT in ZenLittleWindow.sys.mjs */
|
||||
--zen-minimum-window-height: 340px;
|
||||
min-width: unset !important;
|
||||
|
||||
#zen-appcontent-wrapper {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#urlbar[breakout-extend] {
|
||||
min-width: 100% !important;
|
||||
left: 50% !important;
|
||||
top: 0 !important;
|
||||
transform: translate(10px, 0) !important;
|
||||
visibility: visible;
|
||||
|
||||
& .urlbar-background {
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
& .urlbar-input-container {
|
||||
-moz-window-dragging: drag;
|
||||
}
|
||||
|
||||
& .urlbar-input-box {
|
||||
-moz-window-dragging: no-drag;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,8 @@ DIRS += [
|
||||
"common",
|
||||
"drag-and-drop",
|
||||
"glance",
|
||||
"kbs",
|
||||
"little-window",
|
||||
"live-folders",
|
||||
"mods",
|
||||
"tests",
|
||||
|
||||
@@ -212,6 +212,13 @@ class nsZenWindowSync {
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (aWindow._zenStartupLittleWindow) {
|
||||
aWindow.document.documentElement.setAttribute(
|
||||
"zen-little-window",
|
||||
"true"
|
||||
);
|
||||
delete aWindow._zenStartupLittleWindow;
|
||||
}
|
||||
this.log("Setting up window sync for window", aWindow);
|
||||
// There are 2 possibilities to know if we are trying to open
|
||||
// a new *unsynced* window:
|
||||
|
||||
Reference in New Issue
Block a user