Skip to content

Commit

Permalink
Completely refactor menu commanders.
Browse files Browse the repository at this point in the history
Simplify operation significantly.  Less data being passed around many
places, less need for interfaces.  Should be faster as objects are not
created until used.

Now attaches separately so that the status bar commander can be
included only when we want it.
  • Loading branch information
arantius committed Mar 13, 2011
1 parent 517f1ee commit 4e5e3ec
Show file tree
Hide file tree
Showing 11 changed files with 60 additions and 332 deletions.
Binary file removed components/gmIBrowserWindow.xpt
Binary file not shown.
Binary file removed components/gmIMenuCommand.xpt
Binary file not shown.
47 changes: 12 additions & 35 deletions components/greasemonkey.js
Expand Up @@ -87,6 +87,7 @@ GM_GreasemonkeyService.prototype = {
entry: CONTRACTID,
value: CONTRACTID,
service: true}],
menuCommands: [],

// nsISupports
QueryInterface: XPCOMUtils.generateQI([
Expand All @@ -110,7 +111,6 @@ GM_GreasemonkeyService.prototype = {
}
return this._config;
},
browserWindows: [],

// nsIObserver
observe: function(aSubject, aTopic, aData) {
Expand All @@ -124,39 +124,20 @@ GM_GreasemonkeyService.prototype = {


// gmIGreasemonkeyService
registerBrowser: function(browserWin) {
var existing;

for (var i = 0; existing = this.browserWindows[i]; i++) {
if (existing == browserWin) {
// NOTE: Unlocalised strings
throw new Error("Browser window has already been registered.");
}
}

this.browserWindows.push(browserWin);
},

unregisterBrowser: function(browserWin) {
var existing;

for (var i = 0; existing = this.browserWindows[i]; i++) {
if (existing == browserWin) {
this.browserWindows.splice(i, 1);
return;
}
}

throw new Error("Browser window is not registered.");
},

domContentLoaded: function(wrappedContentWin, chromeWin) {
var url = wrappedContentWin.document.location.href;
var scripts = this.initScripts(url, wrappedContentWin, chromeWin);

if (scripts.length > 0) {
this.injectScripts(scripts, url, wrappedContentWin, chromeWin);
}

// Clean out obsolete commands.
// TODO: This doesn't remove commands until the content window is gone.
// If the script is edited, old commands hang around.
for (var i = 0, command = null; command = this.menuCommands[i]; i++) {
if (command.window.closed) delete this.menuCommands[i--];
}
},

startup: function() {
Expand Down Expand Up @@ -298,7 +279,7 @@ GM_GreasemonkeyService.prototype = {
unsafeContentWin);

// Re-wrap the window before assigning it to the sandbox.__proto__
// This is a workaround for a bug in which the Security Manager
// This is a workaround for a bug in which the Security Manager
// vetoes the use of eval.
sandbox.__proto__ = new XPCNativeWrapper(unsafeContentWin);

Expand Down Expand Up @@ -338,17 +319,13 @@ GM_GreasemonkeyService.prototype = {
if (!GM_apiLeakCheck("GM_registerMenuCommand")) {
return;
}

var command = {name: commandName,
accelKey: accelKey,
accelModifiers: accelModifiers,
accessKey: accessKey,
doCommand: commandFunc,
window: unsafeContentWin };

for (var i = 0; i < this.browserWindows.length; i++) {
this.browserWindows[i].registerMenuCommand(command);
}
commandFunc: commandFunc,
window: unsafeContentWin};
this.menuCommands.push(command);
},

openInTab: function(safeContentWin, chromeWin, url) {
Expand Down
126 changes: 9 additions & 117 deletions content/browser.js
Expand Up @@ -11,8 +11,7 @@ var GM_BrowserUI = {};
GM_BrowserUI.QueryInterface = function(aIID) {
if (!aIID.equals(Components.interfaces.nsISupports) &&
!aIID.equals(Components.interfaces.gmIBrowserWindow) &&
!aIID.equals(Components.interfaces.nsISupportsWeakReference) &&
!aIID.equals(Components.interfaces.nsIWebProgressListener))
!aIID.equals(Components.interfaces.nsISupportsWeakReference))
throw Components.results.NS_ERROR_NO_INTERFACE;

return this;
Expand All @@ -25,9 +24,6 @@ GM_BrowserUI.QueryInterface = function(aIID) {
* changes.
*/
GM_BrowserUI.init = function() {
this.menuCommanders = [];
this.currentMenuCommander = null;

window.addEventListener("load", GM_hitch(this, "chromeLoad"), false);
window.addEventListener("unload", GM_hitch(this, "chromeUnload"), false);
};
Expand Down Expand Up @@ -63,31 +59,17 @@ GM_BrowserUI.chromeLoad = function(e) {
this.winWat = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
.getService(Components.interfaces.nsIWindowWatcher);

// this gives us onLocationChange
this.tabBrowser.addProgressListener(this,
Components.interfaces.nsIWebProgress.NOTIFY_LOCATION);

// register for notifications from greasemonkey-service about ui type things
this.gmSvc = Components.classes["@greasemonkey.mozdev.org/greasemonkey-service;1"]
.getService(Components.interfaces.gmIGreasemonkeyService);

this.gmSvc = Components
.classes["@greasemonkey.mozdev.org/greasemonkey-service;1"]
.getService(Components.interfaces.gmIGreasemonkeyService)
.wrappedJSObject;
// reference this once, so that the getter is called at least once, and the
// initialization routines will run, no matter what
this.gmSvc.wrappedJSObject.config;

this.gmSvc.registerBrowser(this);
};

GM_BrowserUI.registerMenuCommand = function(menuCommand) {
if (this.isMyWindow(menuCommand.window)) {
var commanders = this.getCommanders(menuCommand.window);
this.gmSvc.config;

for (var i = 0, commander = null; commander = commanders[i]; i++) {
commander.registerMenuCommand(
menuCommand.name, menuCommand.doCommand, menuCommand.accelKey,
menuCommand.accelModifiers, menuCommand.accessKey);
}
}
var commander = new GM_MenuCommander(
document.getElementById("userscript-commands-tbm"));
};

/**
Expand All @@ -112,16 +94,7 @@ GM_BrowserUI.contentLoad = function(e) {
var href = safeWin.location.href;

if (GM_isGreasemonkeyable(href)) {
// if this content load is in the focused tab, attach the menuCommaander
if (unsafeWin == this.tabBrowser.selectedBrowser.contentWindow) {
var commander = this.getCommander(safeWin);
this.currentMenuCommander = commander;
this.currentMenuCommander.attach();
}

this.gmSvc.domContentLoaded(safeWin, window);

safeWin.addEventListener("pagehide", GM_hitch(this, "contentUnload"), false);
}

// Show the greasemonkey install banner if we are navigating to a .user.js
Expand Down Expand Up @@ -230,65 +203,10 @@ GM_BrowserUI.installScript = function(script){
};

/**
* The browser's location has changed. Usually, we don't care. But in the case
* of tab switching we need to change the list of commands displayed in the
* User Script Commands submenu.
*/
GM_BrowserUI.onLocationChange = function(a,b,c) {
if (this.currentMenuCommander != null) {
this.currentMenuCommander.detach();
this.currentMenuCommander = null;
}

var menuCommander = this.getCommander(this.tabBrowser.selectedBrowser.
contentWindow);

if (menuCommander) {
this.currentMenuCommander = menuCommander;
this.currentMenuCommander.attach();
}
};

/**
* A content document has unloaded. We need to remove it's menuCommander to
* avoid leaking it's memory.
*/
GM_BrowserUI.contentUnload = function(e) {
if (e.persisted || !this.menuCommanders || 0 == this.menuCommanders.length) {
return;
}

var unsafeWin = e.target.defaultView;

// looping over commanders rather than using getCommander because we need
// the index into commanders.splice.
for (var i = 0, item; item = this.menuCommanders[i]; i++) {
if (item.win != unsafeWin) {
continue;
}

if (item.commander == this.currentMenuCommander) {
this.currentMenuCommander.detach();
this.currentMenuCommander = null;
}

this.menuCommanders.splice(i, 1);

break;
}
};

/**
* The browser XUL has unloaded. We need to let go of the pref watcher so
* that a non-existant window is not informed when greasemonkey enabled state
* changes. And we need to let go of the progress listener so that we don't
* leak it's memory.
* The browser XUL has unloaded. Destroy references/watchers/listeners.
*/
GM_BrowserUI.chromeUnload = function() {
GM_prefRoot.unwatch("enabled", this.enabledWatcher);
this.tabBrowser.removeProgressListener(this);
this.gmSvc.unregisterBrowser(this);
delete this.menuCommanders;
};

/**
Expand Down Expand Up @@ -330,25 +248,6 @@ GM_BrowserUI.getUserScriptLinkUnderPointer = function() {
return uri;
};

/**
* Helper method which gets the menuCommander corresponding to a given
* document
*/
GM_BrowserUI.getCommander = function(unsafeWin) {
for (var i = 0; i < this.menuCommanders.length; i++) {
if (this.menuCommanders[i].win == unsafeWin) {
return this.menuCommanders[i].commander;
}
}

// no commander found. create one and add it.
var commander = new GM_MenuCommander(
document, document.getElementById("userscript-commands-tb"));
this.menuCommanders.push({win:unsafeWin, commander:commander});

return commander;
};

/**
* Helper to determine if a given dom window is in this tabbrowser
*/
Expand All @@ -370,13 +269,6 @@ function GM_showGeneralPopup(aEvent) {
GM_BrowserUI.generalMenuEnabledItem.setAttribute("checked", GM_getEnabled());
}

// necessary for webProgressListener implementation
GM_BrowserUI.onProgressChange = function(webProgress,b,c,d,e,f){};
GM_BrowserUI.onStateChange = function(a,b,c,d){};
GM_BrowserUI.onStatusChange = function(a,b,c,d){};
GM_BrowserUI.onSecurityChange = function(a,b,c){};
GM_BrowserUI.onLinkIconAvailable = function(a){};

GM_BrowserUI.viewContextItemClicked = function() {
var uri = GM_BrowserUI.getUserScriptLinkUnderPointer();

Expand Down
3 changes: 1 addition & 2 deletions content/browser.xul
Expand Up @@ -50,10 +50,9 @@
accesskey="&menu.new.accesskey;"
label="&menu.new;"
oncommand="GM_newUserScript();" />
<menu id="userscript-commands-sb2"
<menu id="userscript-commands-tbm"
accesskey="&menu.commands.accesskey;"
label="&menu.commands;"
disabled="false"
onpopupshowing="event.stopPropagation();"
>
<menupopup />
Expand Down

0 comments on commit 4e5e3ec

Please sign in to comment.