summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--bootstrap.js100
-rw-r--r--chrome.manifest6
-rw-r--r--chrome/content/gdk.js20
-rw-r--r--chrome/content/overlay.js52
-rw-r--r--chrome/content/overlay.xul4
-rw-r--r--chrome/content/topmenu-client.js2
-rw-r--r--chrome/content/topmenuservice.js98
-rw-r--r--chrome/content/vkgdkmap.js17
-rw-r--r--install.rdf3
-rw-r--r--topmenu-mozilla.files3
11 files changed, 190 insertions, 117 deletions
diff --git a/Makefile b/Makefile
index 51d3e3f..5cededa 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
ZIP?=zip
# What goes inside the .xpi package
-CONTENT:=install.rdf chrome.manifest \
+CONTENT:=install.rdf chrome.manifest bootstrap.js \
$(wildcard chrome/content/*)
all: dist
diff --git a/bootstrap.js b/bootstrap.js
new file mode 100644
index 0000000..080d98c
--- /dev/null
+++ b/bootstrap.js
@@ -0,0 +1,100 @@
+"use strict";
+
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+var Cu = Components.utils;
+
+function loadIntoWindow(window) {
+ if (!window)
+ return;
+
+ window.topmenuProxy = TopMenuService.createWindowProxy(window);
+}
+
+function unloadFromWindow(window) {
+ if (!window)
+ return;
+ if (!window.topmenuProxy)
+ return;
+
+ window.topmenuProxy.unload();
+ window.topmenuProxy.dispose();
+ window.topmenuProxy = null;
+}
+
+var windowListener = {
+ onOpenWindow: function(window) {
+ // Wait for the window to finish loading
+ var domWindow = window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow);
+ domWindow.addEventListener("load", function onLoad() {
+ domWindow.removeEventListener("load", onLoad, false);
+ domWindow.addEventListener("unload", function onUnload() {
+ domWindow.removeEventListener("unload", onUnload, false);
+ unloadFromWindow(domWindow);
+ }, false);
+ loadIntoWindow(domWindow);
+ }, false);
+ },
+
+ onCloseWindow: function(window) {},
+ onWindowTitleChange: function(window, title) {}
+};
+
+function startup(data, reason) {
+ // Setup logging
+ Cu.import("chrome://topmenu/content/log4moz.js");
+ var formatter = new Log4Moz.BasicFormatter();
+ var root = Log4Moz.repository.rootLogger;
+ root.level = Log4Moz.Level.Debug;
+
+ var capp = new Log4Moz.ConsoleAppender(formatter);
+ capp.level = Log4Moz.Level.Debug;
+ root.addAppender(capp);
+
+ var log = Log4Moz.repository.getLogger("topmenu.Bootstrap");
+
+ // Load module
+ Cu.import("chrome://topmenu/content/topmenuservice.js");
+
+ // Load into any existing windows
+ var wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
+ var windows = wm.getEnumerator(null);
+ while (windows.hasMoreElements()) {
+ var domWindow = windows.getNext().QueryInterface(Ci.nsIDOMWindow);
+ loadIntoWindow(domWindow);
+ }
+
+ // Load into any new windows
+ wm.addListener(windowListener);
+}
+
+function shutdown(data, reason) {
+ // When the application is shutting down we normally don't have to clean
+ // up any UI changes made
+ if (reason === APP_SHUTDOWN)
+ return;
+
+ var wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
+
+ // Stop listening for new windows
+ wm.removeListener(windowListener);
+
+ // Unload from any existing windows
+ var windows = wm.getEnumerator(null);
+ while (windows.hasMoreElements()) {
+ var domWindow = windows.getNext().QueryInterface(Ci.nsIDOMWindow);
+ unloadFromWindow(domWindow);
+ }
+
+ // Stop logging and unload modules
+ Cu.unload("chrome://topmenu/content/topmenuservice.js");
+ Cu.unload("chrome://topmenu/content/log4moz.js");
+}
+
+function install(data, reason) {
+
+}
+
+function uninstall(data, reason) {
+
+}
diff --git a/chrome.manifest b/chrome.manifest
index 8c9f370..20e1d8e 100644
--- a/chrome.manifest
+++ b/chrome.manifest
@@ -1,7 +1 @@
content topmenu chrome/content/
-
-overlay chrome://browser/content/browser.xul chrome://topmenu/content/overlay.xul
-
-overlay chrome://messenger/content/messenger.xul chrome://topmenu/content/overlay.xul
-overlay chrome://messenger/content/messengercompose/messengercompose.xul chrome://topmenu/content/overlay.xul
-overlay chrome://messenger/content/addressbook/addressbook.xul chrome://topmenu/content/overlay.xul
diff --git a/chrome/content/gdk.js b/chrome/content/gdk.js
index 25458ef..d70dfc3 100644
--- a/chrome/content/gdk.js
+++ b/chrome/content/gdk.js
@@ -32,6 +32,16 @@ function defines(lib) {
this.GDK_KEY_Return = 0xff0d;
this.GDK_KEY_Escape = 0xff1b;
this.GDK_KEY_Delete = 0xffff;
+ this.GDK_KEY_Home = 0xff50;
+ this.GDK_KEY_Left = 0xff51;
+ this.GDK_KEY_Up = 0xff52;
+ this.GDK_KEY_Right = 0xff53;
+ this.GDK_KEY_Down = 0xff54;
+ this.GDK_KEY_Prior = 0xff55;
+ this.GDK_KEY_Page_Up = 0xff55;
+ this.GDK_KEY_Next = 0xff56;
+ this.GDK_KEY_Page_Down = 0xff56;
+ this.GDK_KEY_End = 0xff57;
this.GDK_KEY_F1 = 0xffbe;
this.GDK_KEY_F2 = 0xffbf;
this.GDK_KEY_F3 = 0xffc0;
@@ -45,16 +55,6 @@ function defines(lib) {
this.GDK_KEY_F11 = 0xffc8;
this.GDK_KEY_L1 = 0xffc8;
this.GDK_KEY_F12 = 0xffc9;
- this.GDK_KEY_Home = 0xff50;
- this.GDK_KEY_Left = 0xff51;
- this.GDK_KEY_Up = 0xff52;
- this.GDK_KEY_Right = 0xff53;
- this.GDK_KEY_Down = 0xff54;
- this.GDK_KEY_Prior = 0xff55;
- this.GDK_KEY_Page_Up = 0xff55;
- this.GDK_KEY_Next = 0xff56;
- this.GDK_KEY_Page_Down = 0xff56;
- this.GDK_KEY_End = 0xff57;
lib.lazy_bind("gdk_window_get_toplevel", this.GdkWindow.ptr, this.GdkWindow.ptr);
diff --git a/chrome/content/overlay.js b/chrome/content/overlay.js
deleted file mode 100644
index 29b9a07..0000000
--- a/chrome/content/overlay.js
+++ /dev/null
@@ -1,52 +0,0 @@
-"use strict";
-
-var topmenu = {
- logger : null,
- proxy : null,
-
- setupLogging: function() {
- Components.utils.import("chrome://topmenu/content/log4moz.js", topmenu);
- var Log4Moz = this.Log4Moz;
- var formatter = new Log4Moz.BasicFormatter();
- var root = Log4Moz.repository.rootLogger;
- root.level = Log4Moz.Level.Warn;
-
- var capp = new Log4Moz.ConsoleAppender(formatter);
- capp.level = Log4Moz.Level.Warn;
- root.addAppender(capp);
-
- /*
- var dapp = new Log4Moz.DumpAppender(formatter);
- dapp.level = Log4Moz.Level.Debug;
- root.addAppender(dapp);
- */
-
- this.logger = Log4Moz.repository.getLogger("topmenu");
- },
-
- setupMenuProxy: function() {
- Components.utils.import("chrome://topmenu/content/topmenuservice.js", topmenu);
- this.proxy = topmenu.TopMenuService.createWindowProxy(window);
- },
-
- dispose: function() {
- if (this.proxy) {
- this.proxy.dispose();
- this.proxy = null;
- }
- },
-
- onLoad: function() {
- window.removeEventListener('load', topmenu.onLoad);
- window.addEventListener('unload', topmenu.onUnload);
- topmenu.setupLogging();
- topmenu.setupMenuProxy();
- },
-
- onUnload: function() {
- window.removeEventListener('unload', topmenu.onUnload);
- topmenu.dispose();
- },
-}
-
-window.addEventListener('load', topmenu.onLoad);
diff --git a/chrome/content/overlay.xul b/chrome/content/overlay.xul
deleted file mode 100644
index 3e61323..0000000
--- a/chrome/content/overlay.xul
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<overlay id="topmenu-overlay" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
- <script type="application/x-javascript" src="chrome://topmenu/content/overlay.js"></script>
-</overlay>
diff --git a/chrome/content/topmenu-client.js b/chrome/content/topmenu-client.js
index a5d7ab2..af8b1d2 100644
--- a/chrome/content/topmenu-client.js
+++ b/chrome/content/topmenu-client.js
@@ -1,3 +1,5 @@
+"use strict";
+
var EXPORTED_SYMBOLS = [ "topmenu_client" ];
const Cu = Components.utils;
diff --git a/chrome/content/topmenuservice.js b/chrome/content/topmenuservice.js
index 494ea3e..96d0e6c 100644
--- a/chrome/content/topmenuservice.js
+++ b/chrome/content/topmenuservice.js
@@ -1,3 +1,5 @@
+"use strict";
+
var EXPORTED_SYMBOLS = ["TopMenuService"];
var Cu = Components.utils;
@@ -42,13 +44,23 @@ function getTopLevelGdkWindow(w) {
function createMutationObserver(window, proxy)
{
return new window.MutationObserver(function(mutations) {
- mutations.forEach(function(mutation) {
- proxy.handleMutation(mutation);
- });
+ try {
+ mutations.forEach(function(mutation) {
+ proxy.handleMutation(mutation);
+ });
+ } catch (ex) {
+ log.warn("Exception processing menubar changes: " + ex);
+ }
});
}
function WindowProxy(window) {
+ var menubars = window.document.getElementsByTagNameNS('http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul', 'menubar');
+ if (menubars.length === 0) {
+ // No menubars, give up constructing the object
+ return;
+ }
+
this.srcWindow = window;
this.srcMenuBar = null;
this.observer = null;
@@ -106,6 +118,7 @@ function WindowProxy(window) {
}
}
+ // Initialize the Gtk widgets for this window
this.accelGroup = gobject.ref_sink(gtk.gtk_accel_group_new());
this.appMenuBar = gobject.ref_sink(topmenu_client.topmenu_app_menu_bar_new());
@@ -113,48 +126,57 @@ function WindowProxy(window) {
topmenu_client.topmenu_client_connect_window_widget(this.gdkWindow, this.appMenuBar);
- var menubars = window.document.getElementsByTagNameNS('http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul', 'menubar');
- if (menubars.length > 0) {
- this.srcMenuBar = menubars[0];
- this.observer = createMutationObserver(window, this);
- this.observer.observe(this.srcMenuBar, {
- childList: true,
- attributes: true,
- subtree: true
- });
-
- // Let's find currently added menu items and proxy them
- this.srcMenuBar.topmenuData = {
- gtkMenu: this.appMenuBar
- }
+ // Connect to the first available menu bar
+ this.srcMenuBar = menubars[0];
+ this.observer = createMutationObserver(window, this);
+ this.observer.observe(this.srcMenuBar, {
+ childList: true,
+ attributes: true,
+ subtree: true
+ });
- for (var item = this.srcMenuBar.firstChild; item; item = item.nextSibling) {
- this.addItem(item, this.srcMenuBar, -1);
- }
+ // Let's find currently added menu items and proxy them
+ this.srcMenuBar.topmenuData = {
+ gtkMenu: this.appMenuBar
+ }
- this.appMenu = this.buildAppMenu();
- if (this.appMenu) {
- topmenu_client.topmenu_app_menu_bar_set_app_menu(this.appMenuBar, this.appMenu);
- }
+ for (var item = this.srcMenuBar.firstChild; item; item = item.nextSibling) {
+ this.addItem(item, this.srcMenuBar, -1);
+ }
- window.document.addEventListener("keypress", this.callbacks.keypress);
+ this.appMenu = this.buildAppMenu();
+ if (this.appMenu) {
+ topmenu_client.topmenu_app_menu_bar_set_app_menu(this.appMenuBar, this.appMenu);
}
+ window.document.addEventListener("keypress", this.callbacks.keypress);
+
+ // Connect to the appmenu monitor
this.monitor = topmenu_client.topmenu_monitor_get_instance();
this.monitorConnectionId = gobject.signal_connect(this.monitor, "notify::available",
this.callbacks.monitor_available, null);
+
+ // This will hide the source menu bar if everything's OK.
this.updateMenuBarVisibility();
}
-WindowProxy.prototype.updateMenuBarVisibility = function() {
- var topmenuAvailable = topmenu_client.topmenu_monitor_is_topmenu_available(this.monitor);
+WindowProxy.prototype.setMenuBarVisibility = function(visible) {
if (this.srcMenuBar) {
- this.srcMenuBar.parentNode.parentNode.hidden = topmenuAvailable;
+ this.srcMenuBar.hidden = !visible;
+ // A hack for windows containing the menubar in a toolbar.
+ var toolbar = this.srcMenuBar.parentNode.parentNode;
+ if (toolbar && toolbar.tagName === 'toolbar') {
+ toolbar.hidden = !visible;
+ }
}
}
-WindowProxy.prototype.buildAppMenuItem = function(itemId, stockId)
-{
+WindowProxy.prototype.updateMenuBarVisibility = function() {
+ var topmenuAvailable = topmenu_client.topmenu_monitor_is_topmenu_available(this.monitor);
+ this.setMenuBarVisibility(!topmenuAvailable);
+}
+
+WindowProxy.prototype.buildAppMenuItem = function(itemId, stockId) {
var item = this.srcWindow.document.getElementById(itemId);
if (item) {
@@ -377,7 +399,7 @@ WindowProxy.prototype.addAccelerator = function(gtkItem, item) {
if (keyItemMods) {
keyItemMods = keyItemMods.split(/[\s,]+/);
- for (i in keyItemMods) {
+ for (var i in keyItemMods) {
var mod = keyItemMods[i];
if (mod === "accel") {
/* Read platform default accelerator key from prefs */
@@ -496,9 +518,12 @@ WindowProxy.prototype.addItem = function(item, menu, position) {
try {
this.addAccelerator(gtkItem, item);
} catch (ex) {
- log.warn(ex);
+ log.warn("Exception during accelerator computation: " + ex);
}
}
+ } else if (item.tagName === "spacer") {
+ // Nothing to do
+ return;
} else {
log.warn("Unknown tagName: " + item.tagName);
return;
@@ -624,7 +649,7 @@ WindowProxy.prototype.updateItem = function(item, changedAttr) {
}
WindowProxy.prototype.updateMenu = function(menu, prevItem, removedItems, addedItems) {
- var position, i, node;
+ var position, i;
var popup = menu.firstChild;
if (removedItems.length > 0) {
@@ -637,7 +662,7 @@ WindowProxy.prototype.updateMenu = function(menu, prevItem, removedItems, addedI
if (prevItem) {
position = -1;
i = 2;
- for (node = popup.firstChild; node; node = node.nextSibling, i++) {
+ for (var node = popup.firstChild; node; node = node.nextSibling, i++) {
if (node === prevItem) {
position = i;
break;
@@ -753,6 +778,11 @@ WindowProxy.prototype.fakeCommandEvent = function(item) {
item.dispatchEvent(commandEvent);
}
+WindowProxy.prototype.unload = function() {
+ this.setMenuBarVisibility(true);
+ topmenu_client.topmenu_client_disconnect_window(this.gdkWindow);
+}
+
WindowProxy.prototype.dispose = function() {
window.document.removeEventListener("keypress", this.callbacks.keypress);
if (this.monitor) {
diff --git a/chrome/content/vkgdkmap.js b/chrome/content/vkgdkmap.js
index 35a8fc5..088a212 100644
--- a/chrome/content/vkgdkmap.js
+++ b/chrome/content/vkgdkmap.js
@@ -1,13 +1,20 @@
+"use strict";
+
var EXPORTED_SYMBOLS = [ "vkgdkmap" ];
const Cu = Components.utils;
Cu.import("chrome://topmenu/content/gdk.js");
-/* Hardcoding DOM_VK_* constants, how ugly. */
-/* But how to get a window scope from here? Need to access KeyEvent. */
+var vkgdkmap = {
+ VK_TAB : gdk.GDK_KEY_Tab,
+ VK_RETURN : gdk.GDK_KEY_Return,
+
+ VK_HOME : gdk.GDK_KEY_Home,
+ VK_END : gdk.GDK_KEY_End,
+
+ VK_DELETE : gdk.GDK_KEY_Delete,
-vkgdkmap = {
VK_F1 : gdk.GDK_KEY_F1,
VK_F2 : gdk.GDK_KEY_F2,
VK_F3 : gdk.GDK_KEY_F3,
@@ -20,8 +27,4 @@ vkgdkmap = {
VK_F10 : gdk.GDK_KEY_F10,
VK_F11 : gdk.GDK_KEY_F11,
VK_F12 : gdk.GDK_KEY_F12,
-
- VK_TAB : gdk.GDK_KEY_Tab,
- VK_DELETE : gdk.GDK_KEY_Delete
-
}
diff --git a/install.rdf b/install.rdf
index 11d48d3..3787168 100644
--- a/install.rdf
+++ b/install.rdf
@@ -3,8 +3,9 @@
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>topmenu.mozilla@javispedro.com</em:id>
- <em:version>0.1</em:version>
+ <em:version>0.2</em:version>
<em:type>2</em:type>
+ <em:bootstrap>true</em:bootstrap>
<em:targetApplication>
<Description>
diff --git a/topmenu-mozilla.files b/topmenu-mozilla.files
index 65ebee1..799baeb 100644
--- a/topmenu-mozilla.files
+++ b/topmenu-mozilla.files
@@ -1,8 +1,6 @@
chrome.manifest
install.rdf
Makefile
-chrome/content/overlay.xul
-chrome/content/overlay.js
chrome/content/log4moz.js
chrome/content/ctypes-utils.js
chrome/content/topmenuservice.js
@@ -13,3 +11,4 @@ chrome/content/gtk.js
chrome/content/gdk.js
chrome/content/gdk-pixbuf.js
chrome/content/vkgdkmap.js
+bootstrap.js