diff --git a/app/SysTray-X/SysTray-X-app/preferencesdialog.cpp b/app/SysTray-X/SysTray-X-app/preferencesdialog.cpp index 04bae40..2bb8c34 100644 --- a/app/SysTray-X/SysTray-X-app/preferencesdialog.cpp +++ b/app/SysTray-X/SysTray-X-app/preferencesdialog.cpp @@ -41,10 +41,10 @@ PreferencesDialog::PreferencesDialog( SysTrayXLink *link, Preferences *pref, QWi * Set close type button Ids */ m_ui->closeTypeGroup->setId( m_ui->defaultCloseWindowsRadioButton, Preferences::PREF_DEFAULT_CLOSE_WINDOWS); - m_ui->closeTypeGroup->setId( m_ui->minimizeMainCloseChildrenWindowsRadioButton, Preferences::PREF_MINIMIZE_MAIN_CLOSE_CHILDREN_WINDOWS ); - m_ui->closeTypeGroup->setId( m_ui->minimizeAllWindowsRadioButton, Preferences::PREF_MINIMIZE_ALL_WINDOWS ); m_ui->closeTypeGroup->setId( m_ui->minimizeMainTrayCloseChildrenWindowsRadioButton, Preferences::PREF_MINIMIZE_MAIN_TRAY_CLOSE_CHILDREN_WINDOWS ); m_ui->closeTypeGroup->setId( m_ui->minimizeAllTrayWindowsRadioButton, Preferences::PREF_MINIMIZE_ALL_WINDOWS_TRAY ); + m_ui->closeTypeGroup->setId( m_ui->minimizeMainCloseChildrenWindowsRadioButton, Preferences::PREF_MINIMIZE_MAIN_CLOSE_CHILDREN_WINDOWS ); + m_ui->closeTypeGroup->setId( m_ui->minimizeAllWindowsRadioButton, Preferences::PREF_MINIMIZE_ALL_WINDOWS ); /* * Set minimize type button Ids diff --git a/app/SysTray-X/SysTray-X-app/windowctrl.cpp b/app/SysTray-X/SysTray-X-app/windowctrl.cpp index b9bd7ac..6e5cc45 100644 --- a/app/SysTray-X/SysTray-X-app/windowctrl.cpp +++ b/app/SysTray-X/SysTray-X-app/windowctrl.cpp @@ -231,7 +231,7 @@ void WindowCtrl::slotWindowState( Preferences::WindowState state ) } else { - if( state == Preferences::STATE_MINIMIZED ) + if( state == Preferences::STATE_MINIMIZED || state == Preferences::STATE_DOCKED ) { Preferences::MinimizeType minimizeType = getMinimizeType(); if( minimizeType != Preferences::PREF_DEFAULT_MINIMIZE ) diff --git a/webext/background.js b/webext/background.js index f760c74..a6a4684 100644 --- a/webext/background.js +++ b/webext/background.js @@ -364,6 +364,34 @@ SysTrayX.Messaging = { console.debug("onCloseButton Window: " + JSON.stringify( window ) ); +// SysTrayX.Link.postSysTrayXMessage({ window: "minimized_all" }); + + let state = undefined; + if (SysTrayX.Messaging.closeType === "1" || SysTrayX.Messaging.closeType === "2") { + // Minimize to tray + state = "docked"; + + console.debug("onCloseButton: " + state); + + } else if (SysTrayX.Messaging.closeType === "3" || SysTrayX.Messaging.closeType === "4") { + // Minimize + state = "minimized"; + + console.debug("onCloseButton: " + state); + + } + + if (state !== undefined) { + browser.windows.update( window.id, { + state: state, + }); + + SysTrayX.Link.postSysTrayXMessage({ window: state }); + + console.debug("onCloseButton Send state: " + state); + } + +/* if( window.id === SysTrayX.mainWindowId ) { SysTrayX.Link.postSysTrayXMessage({ window: "minimized_all" }); } else { @@ -374,7 +402,7 @@ SysTrayX.Messaging = { // state: "minimized", }); } - +*/ /* browser.windows.update(browser.windows.WINDOW_ID_CURRENT, { state: "minimized", @@ -953,7 +981,14 @@ SysTrayX.Link = { SysTrayX.Window = { focusChanged: function (windowId) { + // no focus change when docked + + // windowId sometimes not defined + console.debug("focusChanged Id: " + windowId); + browser.windows.getCurrent().then((win) => { + console.debug("focusChanged Id: " + win.id); + console.debug("focusChanged state: " + win.state); SysTrayX.Link.postSysTrayXMessage({ window: win.state }); }); }, @@ -1088,17 +1123,17 @@ async function start() { // Set the close type - browser.windowEvent2.setCloseType( Number( SysTrayX.Messaging.closeType ) ); + browser.windowEvent.setCloseType( Number( SysTrayX.Messaging.closeType ) ); // Set the main window id - browser.windowEvent2.setMainWindowId( Number( SysTrayX.mainWindowId ) ); + browser.windowEvent.setMainWindowId( Number( SysTrayX.mainWindowId ) ); // Intercept close button? if (SysTrayX.Messaging.closeType !== "0") { // Intercept new window - browser.windowEvent2.onNewWindow.addListener( SysTrayX.Messaging.onNewWindow ); + browser.windowEvent.onNewWindow.addListener( SysTrayX.Messaging.onNewWindow ); - browser.windowEvent2.onCloseButtonClick.addListener( + browser.windowEvent.onCloseButtonClick.addListener( SysTrayX.Messaging.onCloseButton ); } diff --git a/webext/js/experimental.js b/webext/js/experimental.js deleted file mode 100644 index 757458f..0000000 --- a/webext/js/experimental.js +++ /dev/null @@ -1,159 +0,0 @@ -/* eslint-disable object-shorthand */ - -"use strict"; - -// Using a closure to not leak anything but the API to the outside world. -(function (exports) { - - // Get various parts of the WebExtension framework that we need. - var { ExtensionCommon } = ChromeUtils.import("resource://gre/modules/ExtensionCommon.jsm"); - - // You probably already know what this does. - var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); - - // A helpful class for listening to windows opening and closing. - var { ExtensionSupport } = ChromeUtils.import("resource:///modules/ExtensionSupport.jsm"); - - /** - * This object is just what we're using to listen for toolbar clicks. The implementation - * isn't what this example is about, but you might be interested as it's a common pattern. - * We count the number of callbacks waiting for events so that we're only listening if we - * need to be. - * - * An EventEmitter has the following basic functions: - * - * EventEmitter.on(emitterName, callback) - * Registers a callback for a custom emitter. - * - * EventEmitter.off(emitterName, callback) - * Unregisters a callback for a custom emitter. - * - * EventEmitter.emit(emitterName) - * Emit a custom emitter, all provided parameters will be forwarded to the registered callbacks. - */ - - let windowListener; - - class WindowListener extends ExtensionCommon.EventEmitter { - constructor(extension) { - super(); - this.extension = extension; - this.callbackCount = 0; - } - - get listenerId() { - return `experiment_listener_${this.extension.uuid}_${this.extension.instanceId}`; - } - - handleEvent(event) { - // Only react to the secondary mouse button. - if (event.button == 0) { - let toolbar = event.target.closest("toolbar"); - // Emit "toolbar-clicked" and send toolbar.id, event.clientX, event.clientY to - // the registered callbacks. - windowListener.emit("toolbar-clicked", toolbar.id, event.clientX, event.clientY); - } - } - - add(callback) { - // Registering the callback for "toolbar-clicked". - this.on("toolbar-clicked", callback); - this.callbackCount++; - - if (this.callbackCount == 1) { - ExtensionSupport.registerWindowListener(this.listenerId, { - chromeURLs: [ - "chrome://messenger/content/messenger.xhtml", - "chrome://messenger/content/messenger.xul", - ], - onLoadWindow: function (window) { - let toolbox = window.document.getElementById("mail-toolbox"); - toolbox.addEventListener("click", windowListener.handleEvent); - }, - }); - } - } - - remove(callback) { - // Un-Registering the callback for "toolbar-clicked". - this.off("toolbar-clicked", callback); - this.callbackCount--; - - if (this.callbackCount == 0) { - for (let window of ExtensionSupport.openWindows) { - if ([ - "chrome://messenger/content/messenger.xhtml", - "chrome://messenger/content/messenger.xul", - ].includes(window.location.href)) { - let toolbox = window.document.getElementById("mail-toolbox"); - toolbox.removeEventListener("click", this.handleEvent); - } - } - ExtensionSupport.unregisterWindowListener(this.listenerId); - } - } - }; - - - // This is the important part. It implements the functions and events defined - // in the schema.json. The name must match what you've been using so far, - // "ExampleAPI" in this case. - class ExampleAPI extends ExtensionCommon.ExtensionAPI { - // An alternative to defining a constructor here, is to use the onStartup - // event. However, this causes the API to be instantiated directly after the - // add-on has been loaded, not when the API is first used. Depends on what is - // desired. - constructor(extension) { - super(extension); - windowListener = new WindowListener(extension); - } - - getAPI(context) { - return { - // This key must match the class name. - ExampleAPI: { - - // A function. - sayHello: async function (name) { - Services.wm.getMostRecentWindow("mail:3pane").alert(name); - }, - - // An event. Most of this is boilerplate you don't need to worry about, just copy it. - onToolbarClick: new ExtensionCommon.EventManager({ - context, - name: "ExampleAPI.onToolbarClick", - // In this function we add listeners for any events we want to listen to, and return a - // function that removes those listeners. To have the event fire in your extension, - // call fire.async. - register(fire) { - function callback(event, id, x, y) { - return fire.async(id, x, y); - } - - windowListener.add(callback); - return function () { - windowListener.remove(callback); - }; - }, - }).api(), - - }, - }; - } - - onShutdown(isAppShutdown) { - // This function is called if the extension is disabled or removed, or Thunderbird closes. - // We usually do not have to do any cleanup, if Thunderbird is shutting down entirely - if (isAppShutdown) { - return; - } - - console.log("Goodbye world!"); - } - }; - - // Export the api by assigning in to the exports parameter of the anonymous closure - // function, which is the global this. - exports.ExampleAPI = ExampleAPI; - -})(this) diff --git a/webext/js/windowEvent.js b/webext/js/windowEvent.js index f58d6b3..afa6c99 100644 --- a/webext/js/windowEvent.js +++ b/webext/js/windowEvent.js @@ -1,206 +1,312 @@ -// This is the important part. It implements the functions and events defined in schema.json. -// The variable must have the same name you've been using so far, "myapi" in this case. -var windowEvent = class extends ExtensionCommon.ExtensionAPI { - getAPI(context) { - console.log("windowEvent API started"); +/* eslint-disable object-shorthand */ - // To be notified of the extension going away, call callOnClose with any object that has a - // close function, such as this one. - context.callOnClose(this); +"use strict"; - return { - // Again, this key must have the same name. - windowEvent: { - setCloseType: async function (type) { - windowListener.setCloseType(type); - }, +// Using a closure to not leak anything but the API to the outside world. +(function (exports) { - // An event. Most of this is boilerplate you don't need to worry about, just copy it. - onCloseButtonClick: new ExtensionCommon.EventManager({ - context, - name: "windowEvent.onCloseButtonClick", - // In this function we add listeners for any events we want to listen to, and return a - // function that removes those listeners. To have the event fire in your extension, - // call fire.async. - register(fire) { - function callback(event) { - return fire.async(); - } + // Get various parts of the WebExtension framework that we need. + var { ExtensionCommon } = ChromeUtils.import("resource://gre/modules/ExtensionCommon.jsm"); - windowListener.addOnCloseButton(callback); - return function () { - windowListener.removeOnCloseButton(callback); - }; - }, - }).api(), - }, - }; - } + // You probably already know what this does. + var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); - close() { - // This function is called if the extension is disabled or removed, or Thunderbird closes. - // We registered it with callOnClose, above. - console.log("windowEvent API closed"); - } -}; + // A helpful class for listening to windows opening and closing. + var { ExtensionSupport } = ChromeUtils.import("resource:///modules/ExtensionSupport.jsm"); -// A helpful class for listening to windows opening and closing. -// (This file had a lowercase E in Thunderbird 65 and earlier.) -var { ExtensionSupport } = ChromeUtils.import( - "resource:///modules/ExtensionSupport.jsm" -); + /** + * This object is just what we're using to listen for toolbar clicks. The implementation + * isn't what this example is about, but you might be interested as it's a common pattern. + * We count the number of callbacks waiting for events so that we're only listening if we + * need to be. + * + * An EventEmitter has the following basic functions: + * + * EventEmitter.on(emitterName, callback) + * Registers a callback for a custom emitter. + * + * EventEmitter.off(emitterName, callback) + * Unregisters a callback for a custom emitter. + * + * EventEmitter.emit(emitterName) + * Emit a custom emitter, all provided parameters will be forwarded to the registered callbacks. + */ -// This object is just what we're using to listen for toolbar clicks. The implementation isn't -// what this example is about, but you might be interested as it's a common pattern. We count the -// number of callbacks waiting for events so that we're only listening if we need to be. -var windowListener = new (class extends ExtensionCommon.EventEmitter { - constructor() { - super(); - this.callbackOnCloseButtonCount = 0; - this.callbackOnLoadWindowCount = 0; + let windowListener; - this.MESSAGE_CLOSE_TYPE_DEFAULT = 0; - this.MESSAGE_CLOSE_TYPE_MIN_MAIN_TRAY_CLOSE_CHILDREN = 1; - this.MESSAGE_CLOSE_TYPE_MIN_ALL_TRAY = 2; - this.MESSAGE_CLOSE_TYPE_MIN_MAIN_CLOSE_CHILDREN = 3; - this.MESSAGE_CLOSE_TYPE_MIN_ALL = 4; + class WindowListener extends ExtensionCommon.EventEmitter { + constructor(extension) { + super(); + this.extension = extension; + this.onNewWindowCallbackCount = 0; + this.onCloseButtonClickCallbackCount = 0; - this.closeType = this.MESSAGE_CLOSE_TYPE_MIN_MAIN_CLOSE_CHILDREN; - } - - setCloseType(closeType) { - if (closeType === 0) { + this.MESSAGE_CLOSE_TYPE_DEFAULT = 0; + this.MESSAGE_CLOSE_TYPE_MIN_MAIN_TRAY_CLOSE_CHILDREN = 1; + this.MESSAGE_CLOSE_TYPE_MIN_ALL_TRAY = 2; + this.MESSAGE_CLOSE_TYPE_MIN_MAIN_CLOSE_CHILDREN = 3; + this.MESSAGE_CLOSE_TYPE_MIN_ALL = 4; + this.closeType = this.MESSAGE_CLOSE_TYPE_DEFAULT; - } else if (closeType === 1) { - this.closeType = this.MESSAGE_CLOSE_TYPE_MIN_MAIN_TRAY_CLOSE_CHILDREN; - } else if (closeType === 2) { - this.closeType = this.MESSAGE_CLOSE_TYPE_MIN_ALL_TRAY; - } else if (closeType === 3) { - this.closeType = this.MESSAGE_CLOSE_TYPE_MIN_MAIN_CLOSE_CHILDREN; - } else if (closeType === 4) { - this.closeType = this.MESSAGE_CLOSE_TYPE_MIN_ALL; - } else console.log("Unknown close type: " + closeType); - } - - addOnCloseButton(callback) { - if (this.callbackOnCloseButtonCount == 0) { - this.on("close-clicked", callback); - this.callbackOnCloseButtonCount++; - - ExtensionSupport.registerWindowListener("closeButtonListener", { - chromeURLs: [ - "chrome://messenger/content/messenger.xhtml", - "chrome://messenger/content/messenger.xul", - ], - onLoadWindow: function (window) { - windowListener.callbackOnLoadWindowCount++; - if ( - windowListener.callbackOnLoadWindowCount === 1 || - windowListener.closeType === - windowListener.MESSAGE_CLOSE_TYPE_MIN_ALL || - windowListener.closeType === - windowListener.MESSAGE_CLOSE_TYPE_MIN_ALL_TRAY - ) { - window.addEventListener( - "close", - windowListener.onCloseButton, - true - ); - windowListener.hijackTitlebarCloseButton(window); - - windowListener.oldClose = window.close; - window.close = () => windowListener.onCloseButton(null); - - console.log("Close listener added"); - } - }, - }); + this.oldClose = undefined; + this.mainWindowId = 0; } - } - removeOnCloseButton(callback) { - if (this.callbackOnCloseButtonCount == 1) { - this.off("close-clicked", callback); - this.callbackOnCloseButtonCount--; + get listenerIdNewWindow() { + return `window_event_listener_new_window_${this.extension.uuid}_${this.extension.instanceId}`; + } - for (let window of ExtensionSupport.openWindows) { - if ( - [ + get listenerIdCloseButton() { + return `window_event_listener_close_button_${this.extension.uuid}_${this.extension.instanceId}`; + } + + setCloseType(closeType) { + if (closeType === 0) { + this.closeType = this.MESSAGE_CLOSE_TYPE_DEFAULT; + } else if (closeType === 1) { + this.closeType = this.MESSAGE_CLOSE_TYPE_MIN_MAIN_TRAY_CLOSE_CHILDREN; + } else if (closeType === 2) { + this.closeType = this.MESSAGE_CLOSE_TYPE_MIN_ALL_TRAY; + } else if (closeType === 3) { + this.closeType = this.MESSAGE_CLOSE_TYPE_MIN_MAIN_CLOSE_CHILDREN; + } else if (closeType === 4) { + this.closeType = this.MESSAGE_CLOSE_TYPE_MIN_ALL; + } else console.log("Unknown close type: " + closeType); + } + + setMainWindowId(id) { + this.mainWindowId = id; + } + + addOnNewWindow( callback ) { + // Registering the callback for "new-window". + this.on("new-window", callback); + this.onNewWindowCallbackCount++; + + if (this.onNewWindowCallbackCount === 1) { + ExtensionSupport.registerWindowListener( this.listenerIdNewWindow, { + chromeURLs: [ "chrome://messenger/content/messenger.xhtml", "chrome://messenger/content/messenger.xul", - ].includes(window.location.href) - ) { - window.removeEventListener( - "close", - windowListener.onCloseButton, - true - ); - window.close = windowListener.oldClose; + ], + onLoadWindow: function ( window ) { - console.log("Close listener removed"); + windowListener.emit( "new-window" ); + + console.log("New window added"); + }, + }); + } + } + + removeOnNewWindow( callback ) { + // Un-Registering the callback for "new-window". + this.off("new-window", callback); + this.onNewWindowCallbackCount--; + + if (this.onNewWindowCallbackCount === 0) { + for (let window of ExtensionSupport.openWindows) { + if ( [ + "chrome://messenger/content/messenger.xhtml", + "chrome://messenger/content/messenger.xul", + ].includes( window.location.href ) ) { + console.log( "New window listener removed" ); + } } + ExtensionSupport.unregisterWindowListener( this.listenerIdNewWindow ); } - ExtensionSupport.unregisterWindowListener("closeButtonListener"); - } - } - - onCloseButton(event) { - if (event) event.preventDefault(); - windowListener.emit("close-clicked"); - return true; - } - - hijackTitlebarCloseButton(window) { - if ( - windowListener.replaceCommand(window, "titlebar-close", function () { - return windowListener.onCloseButton(null); - }) - ) { - console.log("replaced command= " + "titlebar-close"); - } - } - - replaceCommand(window, eltId, gotHidden) { - let elt = window.document.getElementById(eltId); - if (!elt) { - console.log("Element '" + eltId + "' not found. Command not replaced."); - return false; } - let prevent = null; - if (elt.command) { - prevent = { - event: "click", - func: function (e) { - e.preventDefault(); + + onCloseButton( event ) { + if ( event ) event.preventDefault(); + windowListener.emit( "close-clicked" ); + + console.log("Close clicked"); + + return true; + } + + onCloseMenu( event ) { + if ( event ) event.preventDefault(); + windowListener.emit( "close-clicked" ); + + console.log("Close menu"); + + return true; + } + + addOnCloseButtonClick( callback, context ) { + // Registering the callback for "close-clicked". + this.on( "close-clicked", callback ); + this.onCloseButtonClickCallbackCount++; + + if (this.onCloseButtonClickCallbackCount === 1) { + ExtensionSupport.registerWindowListener( this.listenerIdCloseButton, { + context, + chromeURLs: [ + "chrome://messenger/content/messenger.xhtml", + "chrome://messenger/content/messenger.xul", + ], + onLoadWindow: function ( window ) { + if (windowListener.closeType !== windowListener.MESSAGE_CLOSE_TYPE_DEFAULT) { + if ((windowListener.closeType === windowListener.MESSAGE_CLOSE_TYPE_MIN_MAIN_TRAY_CLOSE_CHILDREN || + windowListener.closeType === windowListener.MESSAGE_CLOSE_TYPE_MIN_MAIN_CLOSE_CHILDREN) && + (context.extension.windowManager.getWrapper(window).id === windowListener.mainWindowId) || + windowListener.closeType === windowListener.MESSAGE_CLOSE_TYPE_MIN_ALL_TRAY || + windowListener.closeType === windowListener.MESSAGE_CLOSE_TYPE_MIN_ALL) { + + // Intercept the close event (triggered when clicking the close button) + window.addEventListener( + "close", + windowListener.onCloseButton, + true + ); + } + } + + // Get a window ID from a real window: + let id = context.extension.windowManager.getWrapper(window).id; + + if (windowListener.closeType !== windowListener.MESSAGE_CLOSE_TYPE_DEFAULT) { + console.log( "Close listener trigger"); + } + + // Intercept the close by menu +// windowListener.oldClose = window.close; +// window.close = () => windowListener.onCloseMenu(); + + console.log( "Close listener mid:" + windowListener.mainWindowId); + console.log( "Close listener id:" + id); + console.log( "Close listener typeof mid:" + typeof windowListener.mainWindowId); + console.log( "Close listener typeof id:" + typeof id); + + console.log( "Close listener added" ); + }, + }); + } + } + + removeOnCloseButtonClick( callback, context ) { + // Un-Registering the callback for "close-clicked". + this.off( "close-clicked", callback ); + this.onCloseButtonClickCallbackCount--; + + if ( this.onCloseButtonClickCallbackCount === 0 ) { + for ( let window of ExtensionSupport.openWindows ) { + if ( [ + "chrome://messenger/content/messenger.xhtml", + "chrome://messenger/content/messenger.xul", + ].includes( window.location.href ) ) { + if (windowListener.closeType !== windowListener.MESSAGE_CLOSE_TYPE_DEFAULT) { + if ((windowListener.closeType === windowListener.MESSAGE_CLOSE_TYPE_MIN_MAIN_TRAY_CLOSE_CHILDREN || + windowListener.closeType === windowListener.MESSAGE_CLOSE_TYPE_MIN_MAIN_CLOSE_CHILDREN) && + (context.extension.windowManager.getWrapper(window).id === windowListener.mainWindowId) || + windowListener.closeType === windowListener.MESSAGE_CLOSE_TYPE_MIN_ALL_TRAY || + windowListener.closeType === windowListener.MESSAGE_CLOSE_TYPE_MIN_ALL) { + // Release the close event (triggered when clicking the close button) + window.removeEventListener( + "close", + windowListener.onCloseButton, + true + ); + } + } + + if ( windowListener.oldClose != undefined ) { + window.close = windowListener.oldClose; + } + + console.log( "Close listener removed" ); + } + } + ExtensionSupport.unregisterWindowListener( this.listenerIdCloseButton ); + } + } + }; + + // This is the important part. It implements the functions and events defined + // in the schema.json. The name must match what you've been using so far, + // "windowEvent" in this case. + class windowEvent extends ExtensionCommon.ExtensionAPI { + // An alternative to defining a constructor here, is to use the onStartup + // event. However, this causes the API to be instantiated directly after the + // add-on has been loaded, not when the API is first used. Depends on what is + // desired. + constructor(extension) { + super(extension); + windowListener = new WindowListener(extension); + } + + getAPI(context) { + console.log("windowEvent API started"); + + return { + // This key must match the class name. + windowEvent: { + setCloseType: async function (type) { + windowListener.setCloseType(type); + }, + + setMainWindowId: async function (id) { + windowListener.setMainWindowId(id); + }, + + // An event. Most of this is boilerplate you don't need to worry about, just copy it. + onNewWindow: new ExtensionCommon.EventManager({ + context, + name: "windowEvent.onNewWindow", + // In this function we add listeners for any events we want to listen to, and return a + // function that removes those listeners. To have the event fire in your extension, + // call fire.async. + register(fire) { + function callback(event) { + return fire.async(); + } + + windowListener.addOnNewWindow(callback); + return function () { + windowListener.removeOnNewWindow(callback); + }; + }, + }).api(), + + // An event. Most of this is boilerplate you don't need to worry about, just copy it. + onCloseButtonClick: new ExtensionCommon.EventManager({ + context, + name: "windowEvent.onCloseButtonClick", + // In this function we add listeners for any events we want to listen to, and return a + // function that removes those listeners. To have the event fire in your extension, + // call fire.async. + register(fire) { + function callback(event) { + return fire.async(); + } + + windowListener.addOnCloseButtonClick(callback,context); + return function () { + windowListener.removeOnCloseButtonClick(callback,context); + }; + }, + }).api(), + }, }; - } else if (elt.getAttribute("oncommand")) { - prevent = { - event: "command", - func: function (e) { - e.stopPropagation(); - }, - }; - } else { - console.warn("Could not replace oncommand on " + eltId); - return false; } - let callback = function (event) { - if (event.target.id === eltId) { - console.debug(prevent.event + " on " + eltId); - if (gotHidden()) prevent.func(event); + onShutdown(isAppShutdown) { + // This function is called if the extension is disabled or removed, or Thunderbird closes. + // We usually do not have to do any cleanup, if Thunderbird is shutting down entirely + if (isAppShutdown) { + return; } - }; - /* We put listeners on the "titlebar" parent node, because: - - we can hardly short-circuit command/oncommand (probably because they are - registered first) - - we'd have otherwise to alter "oncommand"/"command" attribute and use - Function(), which do not pass review nowadays. */ - elt.parentNode.addEventListener(prevent.event, callback, true); + console.log("windowEvent API closed"); + } + }; - return true; - } -})(); + // Export the api by assigning in to the exports parameter of the anonymous closure + // function, which is the global this. + exports.windowEvent = windowEvent; + +})(this) diff --git a/webext/js/windowEvent2.js b/webext/js/windowEvent2.js deleted file mode 100644 index 66cd101..0000000 --- a/webext/js/windowEvent2.js +++ /dev/null @@ -1,283 +0,0 @@ -/* eslint-disable object-shorthand */ - -"use strict"; - -// Using a closure to not leak anything but the API to the outside world. -(function (exports) { - - // Get various parts of the WebExtension framework that we need. - var { ExtensionCommon } = ChromeUtils.import("resource://gre/modules/ExtensionCommon.jsm"); - - // You probably already know what this does. - var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); - - // A helpful class for listening to windows opening and closing. - var { ExtensionSupport } = ChromeUtils.import("resource:///modules/ExtensionSupport.jsm"); - - /** - * This object is just what we're using to listen for toolbar clicks. The implementation - * isn't what this example is about, but you might be interested as it's a common pattern. - * We count the number of callbacks waiting for events so that we're only listening if we - * need to be. - * - * An EventEmitter has the following basic functions: - * - * EventEmitter.on(emitterName, callback) - * Registers a callback for a custom emitter. - * - * EventEmitter.off(emitterName, callback) - * Unregisters a callback for a custom emitter. - * - * EventEmitter.emit(emitterName) - * Emit a custom emitter, all provided parameters will be forwarded to the registered callbacks. - */ - - let windowListener; - - class WindowListener extends ExtensionCommon.EventEmitter { - constructor(extension) { - super(); - this.extension = extension; - this.onNewWindowCallbackCount = 0; - this.onCloseButtonClickCallbackCount = 0; - - this.closeType = this.MESSAGE_CLOSE_TYPE_DEFAULT; - this.oldClose = undefined; - this.mainWindowId = 0; - } - - get listenerIdNewWindow() { - return `window_event_listener_new_window_${this.extension.uuid}_${this.extension.instanceId}`; - } - - get listenerIdCloseButton() { - return `window_event_listener_close_button_${this.extension.uuid}_${this.extension.instanceId}`; - } - - setCloseType(closeType) { - if (closeType === 0) { - this.closeType = this.MESSAGE_CLOSE_TYPE_DEFAULT; - } else if (closeType === 1) { - this.closeType = this.MESSAGE_CLOSE_TYPE_MIN_MAIN_TRAY_CLOSE_CHILDREN; - } else if (closeType === 2) { - this.closeType = this.MESSAGE_CLOSE_TYPE_MIN_ALL_TRAY; - } else if (closeType === 3) { - this.closeType = this.MESSAGE_CLOSE_TYPE_MIN_MAIN_CLOSE_CHILDREN; - } else if (closeType === 4) { - this.closeType = this.MESSAGE_CLOSE_TYPE_MIN_ALL; - } else console.log("Unknown close type: " + closeType); - } - - setMainWindowId(id) { - this.mainWindowId = id; - } - - addOnNewWindow( callback ) { - // Registering the callback for "new-window". - this.on("new-window", callback); - this.onNewWindowCallbackCount++; - - if (this.onNewWindowCallbackCount == 1) { - ExtensionSupport.registerWindowListener( this.listenerIdNewWindow, { - chromeURLs: [ - "chrome://messenger/content/messenger.xhtml", - "chrome://messenger/content/messenger.xul", - ], - onLoadWindow: function ( window ) { - - windowListener.emit( "new-window" ); - - console.log("New window added"); - }, - }); - } - } - - removeOnNewWindow( callback ) { - // Un-Registering the callback for "new-window". - this.off("new-window", callback); - this.onNewWindowCallbackCount--; - - if (this.onNewWindowCallbackCount == 0) { - for (let window of ExtensionSupport.openWindows) { - if ( [ - "chrome://messenger/content/messenger.xhtml", - "chrome://messenger/content/messenger.xul", - ].includes( window.location.href ) ) { - console.log( "New window listener removed" ); - } - } - ExtensionSupport.unregisterWindowListener( this.listenerIdNewWindow ); - } - } - - - onCloseButton( event ) { - if ( event ) event.preventDefault(); - windowListener.emit( "close-clicked" ); - - console.log("Close clicked"); - - return true; - } - - onCloseMenu( event ) { - if ( event ) event.preventDefault(); - windowListener.emit( "close-clicked" ); - - console.log("Close menu"); - - return true; - } - - addOnCloseButtonClick( callback, context, window ) { - // Registering the callback for "close-clicked". - this.on( "close-clicked", callback ); - this.onCloseButtonClickCallbackCount++; - - if (this.onCloseButtonClickCallbackCount == 1) { - ExtensionSupport.registerWindowListener( this.listenerIdCloseButton, { - chromeURLs: [ - "chrome://messenger/content/messenger.xhtml", - "chrome://messenger/content/messenger.xul", - ], - onLoadWindow: function ( window ) { - if( this.closeType !== ) - - - window.addEventListener( - "close", - windowListener.onCloseButton, - true - ); - -// windowListener.oldClose = window.close; -// window.close = () => windowListener.onCloseMenu(); - - // Get a window ID from a real window: - let id = context.extension.windowManager.getWrapper(window).id; - - console.log( "Close listener mid:" + windowListener.mainWindowId); - console.log( "Close listener id:" + id); - - - console.log( "Close listener added" ); - }, - }); - } - } - - removeOnCloseButtonClick( callback ) { - // Un-Registering the callback for "close-clicked". - this.off( "close-clicked", callback ); - this.onCloseButtonClickCallbackCount--; - - if ( this.onCloseButtonClickCallbackCount == 0 ) { - for ( let window of ExtensionSupport.openWindows ) { - if ( [ - "chrome://messenger/content/messenger.xhtml", - "chrome://messenger/content/messenger.xul", - ].includes( window.location.href ) ) { - window.removeEventListener( - "close", - windowListener.onCloseButton, - true - ); - - if ( windowListener.oldClose != undefined ) { - window.close = windowListener.oldClose; - } - - console.log( "Close listener removed" ); - } - } - ExtensionSupport.unregisterWindowListener( this.listenerIdCloseButton ); - } - } - }; - - // This is the important part. It implements the functions and events defined - // in the schema.json. The name must match what you've been using so far, - // "windowEvent2" in this case. - class windowEvent2 extends ExtensionCommon.ExtensionAPI { - // An alternative to defining a constructor here, is to use the onStartup - // event. However, this causes the API to be instantiated directly after the - // add-on has been loaded, not when the API is first used. Depends on what is - // desired. - constructor(extension) { - super(extension); - windowListener = new WindowListener(extension); - } - - getAPI(context) { - console.log("windowEvent API started"); - - return { - // This key must match the class name. - windowEvent2: { - setCloseType: async function (type) { - windowListener.setCloseType(type); - }, - - setMainWindowId: async function (id) { - windowListener.setMainWindowId(id); - }, - - // An event. Most of this is boilerplate you don't need to worry about, just copy it. - onNewWindow: new ExtensionCommon.EventManager({ - context, - name: "windowEvent2.onNewWindow", - // In this function we add listeners for any events we want to listen to, and return a - // function that removes those listeners. To have the event fire in your extension, - // call fire.async. - register(fire) { - function callback(event) { - return fire.async(); - } - - windowListener.addOnNewWindow(callback); - return function () { - windowListener.removeOnNewWindow(callback); - }; - }, - }).api(), - - // An event. Most of this is boilerplate you don't need to worry about, just copy it. - onCloseButtonClick: new ExtensionCommon.EventManager({ - context, - name: "windowEvent2.onCloseButtonClick", - // In this function we add listeners for any events we want to listen to, and return a - // function that removes those listeners. To have the event fire in your extension, - // call fire.async. - register(fire) { - function callback(event) { - return fire.async(); - } - - windowListener.addOnCloseButtonClick(callback,context); - return function () { - windowListener.removeOnCloseButtonClick(callback); - }; - }, - }).api(), - - }, - }; - } - - onShutdown(isAppShutdown) { - // This function is called if the extension is disabled or removed, or Thunderbird closes. - // We usually do not have to do any cleanup, if Thunderbird is shutting down entirely - if (isAppShutdown) { - return; - } - - console.log("windowEvent API closed"); - } - }; - - // Export the api by assigning in to the exports parameter of the anonymous closure - // function, which is the global this. - exports.windowEvent2 = windowEvent2; - -})(this) diff --git a/webext/js/windowHandler.js b/webext/js/windowHandler.js index af8ccb0..9af1dc7 100644 --- a/webext/js/windowHandler.js +++ b/webext/js/windowHandler.js @@ -44,7 +44,7 @@ // This is the important part. It implements the functions and events defined // in the schema.json. The name must match what you've been using so far, - // "windowEvent2" in this case. + // "windowHandler" in this case. class windowHandler extends ExtensionCommon.ExtensionAPI { // An alternative to defining a constructor here, is to use the onStartup // event. However, this causes the API to be instantiated directly after the diff --git a/webext/manifest.json b/webext/manifest.json index d5b3718..cd86fa2 100644 --- a/webext/manifest.json +++ b/webext/manifest.json @@ -40,14 +40,6 @@ "script": "js/windowEvent.js" } }, - "windowEvent2": { - "schema": "schema_windowEvent2.json", - "parent": { - "scopes": ["addon_parent"], - "paths": [["windowEvent2"]], - "script": "js/windowEvent2.js" - } - }, "windowHandler": { "schema": "schema_windowHandler.json", "parent": { diff --git a/webext/schema_experimental.json b/webext/schema_experimental.json deleted file mode 100644 index 33a1f94..0000000 --- a/webext/schema_experimental.json +++ /dev/null @@ -1,46 +0,0 @@ -[ - { - "namespace": "ExampleAPI", - "functions": [ - { - "name": "sayHello", - "type": "function", - "description": "Says hello to the user.", - "async": true, - "parameters": [ - { - "name": "name", - "type": "string", - "description": "Who to say hello to." - } - ] - } - ], - "events": [ - { - "name": "onToolbarClick", - "type": "function", - "description": "Fires when the user clicks the secondary mouse button anywhere on the toolbar in the main window.", - "parameters": [ - { - "name": "toolbarId", - "type": "string", - "description": "The ID of the toolbar the user clicked." - }, - { - "type": "integer", - "name": "x", - "minimum": 0, - "description": "The X position of the mouse when the user clicked." - }, - { - "type": "integer", - "name": "y", - "minimum": 0, - "description": "The Y position of the mouse when the user clicked." - } - ] - } - ] - } -] diff --git a/webext/schema_windowEvent.json b/webext/schema_windowEvent.json index 6a5495f..9502ec8 100644 --- a/webext/schema_windowEvent.json +++ b/webext/schema_windowEvent.json @@ -15,13 +15,31 @@ "maximum": 4 } ] + }, + { + "name": "setMainWindowId", + "type": "function", + "description": "Set the main window id.", + "async": true, + "parameters": [ + { + "type": "integer", + "name": "type" + } + ] } ], "events": [ + { + "name": "onNewWindow", + "type": "function", + "description": "Fires when the user opens a new window.", + "parameters": [] + }, { "name": "onCloseButtonClick", "type": "function", - "description": "Fires when the user clicks on the close button of the main window.", + "description": "Fires when the user clicks on the close button of a window.", "parameters": [] } ] diff --git a/webext/schema_windowEvent2.json b/webext/schema_windowEvent2.json deleted file mode 100644 index 5f1994d..0000000 --- a/webext/schema_windowEvent2.json +++ /dev/null @@ -1,47 +0,0 @@ -[ - { - "namespace": "windowEvent2", - "functions": [ - { - "name": "setCloseType", - "type": "function", - "description": "Set the close type.", - "async": true, - "parameters": [ - { - "type": "integer", - "name": "type", - "minimum": 0, - "maximum": 4 - } - ] - }, - { - "name": "setMainWindowId", - "type": "function", - "description": "Set the main window id.", - "async": true, - "parameters": [ - { - "type": "integer", - "name": "type" - } - ] - } - ], - "events": [ - { - "name": "onNewWindow", - "type": "function", - "description": "Fires when the user opens a new window.", - "parameters": [] - }, - { - "name": "onCloseButtonClick", - "type": "function", - "description": "Fires when the user clicks on the close button of a window.", - "parameters": [] - } - ] - } -]