From 1f70f0ca51d1c61d3a775507b2b69dcdf60e77df Mon Sep 17 00:00:00 2001 From: "mpcomplete@google.com" Date: Thu, 18 Jun 2009 22:56:58 +0000 Subject: Send port-closed notification when a frame with ports unloads. Also add onLoad and onUnload chrome Event to our bindings, so we can add listeners to these events without needing a DOM. These don't hook into the window "unload" event, so we no longer prevent Chrome's sudden termination of tabs on shutdown. BUG=12686 TEST=no Review URL: http://codereview.chromium.org/125280 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18765 0039d316-1c4b-4281-b951-d872f2087c98 --- chrome/renderer/resources/event_bindings.js | 31 +++++++++++-- .../resources/extension_process_bindings.js | 54 +++++++++++----------- chrome/renderer/resources/greasemonkey_api.js | 4 +- .../resources/renderer_extension_bindings.js | 13 ++++++ 4 files changed, 68 insertions(+), 34 deletions(-) (limited to 'chrome/renderer/resources') diff --git a/chrome/renderer/resources/event_bindings.js b/chrome/renderer/resources/event_bindings.js index f11ec78..54dd108 100644 --- a/chrome/renderer/resources/event_bindings.js +++ b/chrome/renderer/resources/event_bindings.js @@ -1,5 +1,5 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // ----------------------------------------------------------------------------- @@ -29,6 +29,9 @@ var chrome = chrome || {}; // A map of event names to the event object that is registered to that name. chrome.Event.attached_ = {}; + // An array of all attached event objects, used for detaching on unload. + chrome.Event.allAttached_ = []; + // Dispatches a named event with the given JSON array, which is deserialized // before dispatch. The JSON array is the list of arguments that will be // sent with the event callback. @@ -105,8 +108,7 @@ var chrome = chrome || {}; // name. chrome.Event.prototype.attach_ = function() { AttachEvent(this.eventName_); - this.unloadHandler_ = this.detach_.bind(this); - window.addEventListener('unload', this.unloadHandler_, false); + chrome.Event.allAttached_[chrome.Event.allAttached_.length] = this; if (!this.eventName_) return; @@ -120,7 +122,9 @@ var chrome = chrome || {}; // Detaches this event object from its name. chrome.Event.prototype.detach_ = function() { - window.removeEventListener('unload', this.unloadHandler_, false); + var i = chrome.Event.allAttached_.indexOf(this); + if (i >= 0) + delete chrome.Event.allAttached_[i]; DetachEvent(this.eventName_); if (!this.eventName_) return; @@ -132,4 +136,21 @@ var chrome = chrome || {}; delete chrome.Event.attached_[this.eventName_]; }; + + // Load events. Note that onUnload_ might not always fire, since Chrome will + // terminate renderers on shutdown. + chrome.onLoad_ = new chrome.Event(); + chrome.onUnload_ = new chrome.Event(); + + // This is called by native code when the DOM is ready. + chrome.dispatchOnLoad_ = function() { + chrome.onLoad_.dispatch(); + delete chrome.dispatchOnLoad_; + } + + chrome.dispatchOnUnload_ = function() { + chrome.onUnload_.dispatch(); + for (var i in chrome.Event.allAttached_) + chrome.Event.allAttached_[i].detach_(); + } })(); diff --git a/chrome/renderer/resources/extension_process_bindings.js b/chrome/renderer/resources/extension_process_bindings.js index ea6481c..93d9f50 100644 --- a/chrome/renderer/resources/extension_process_bindings.js +++ b/chrome/renderer/resources/extension_process_bindings.js @@ -51,7 +51,7 @@ var chrome; validator.validate(args[i], schemas[i]); if (validator.errors.length == 0) continue; - + var message = "Invalid value for argument " + i + ". "; for (var i = 0, err; err = validator.errors[i]; i++) { if (err.path) { @@ -83,7 +83,7 @@ var chrome; console.error("Error during " + name + ": " + error); return; } - + if (callbacks[requestId]) { if (response) { callbacks[requestId](JSON.parse(response)); @@ -125,7 +125,7 @@ var chrome; chrome.types.pInt, chrome.types.fun ]; - + chrome.windows.getCurrent = function(callback) { validate(arguments, arguments.callee.params); sendRequest(GetCurrentWindow, null, callback); @@ -134,7 +134,7 @@ var chrome; chrome.windows.getCurrent.params = [ chrome.types.fun ]; - + chrome.windows.getLastFocused = function(callback) { validate(arguments, arguments.callee.params); sendRequest(GetLastFocusedWindow, null, callback); @@ -153,7 +153,7 @@ var chrome; chrome.types.optBool, chrome.types.fun ]; - + chrome.windows.create = function(createData, callback) { validate(arguments, arguments.callee.params); sendRequest(CreateWindow, createData, callback); @@ -200,7 +200,7 @@ var chrome; chrome.types.pInt, chrome.types.optFun ]; - + // sends (windowId). // *WILL* be followed by tab-attached AND then tab-selection-changed. chrome.windows.onCreated = new chrome.Event("window-created"); @@ -210,7 +210,7 @@ var chrome; // tab-selection-changed -- one for each tab that was contained in the window // that closed chrome.windows.onRemoved = new chrome.Event("window-removed"); - + // sends (windowId). chrome.windows.onFocusChanged = new chrome.Event("window-focus-changed"); @@ -229,7 +229,7 @@ var chrome; chrome.types.pInt, chrome.types.fun ]; - + chrome.tabs.getSelected = function(windowId, callback) { validate(arguments, arguments.callee.params); sendRequest(GetSelectedTab, windowId, callback); @@ -250,7 +250,7 @@ var chrome; chrome.types.fun ]; - chrome.tabs.create = function(tab, callback) { + chrome.tabs.create = function(tab, callback) { validate(arguments, arguments.callee.params); sendRequest(CreateTab, tab, callback); }; @@ -301,7 +301,7 @@ var chrome; }, chrome.types.optFun ]; - + chrome.tabs.remove = function(tabId, callback) { validate(arguments, arguments.callee.params); sendRequest(RemoveTab, tabId, callback); @@ -316,26 +316,26 @@ var chrome; // Will *NOT* be followed by tab-attached - it is implied. // *MAY* be followed by tab-selection-changed. chrome.tabs.onCreated = new chrome.Event("tab-created"); - + // Sends (tabId, {ChangedProps}). chrome.tabs.onUpdated = new chrome.Event("tab-updated"); // Sends (tabId, {windowId, fromIndex, toIndex}). // Tabs can only "move" within a window. chrome.tabs.onMoved = new chrome.Event("tab-moved"); - + // Sends (tabId, {windowId}). - chrome.tabs.onSelectionChanged = + chrome.tabs.onSelectionChanged = new chrome.Event("tab-selection-changed"); - + // Sends (tabId, {newWindowId, newPosition}). // *MAY* be followed by tab-selection-changed. chrome.tabs.onAttached = new chrome.Event("tab-attached"); - + // Sends (tabId, {oldWindowId, oldPosition}). // *WILL* be followed by tab-selection-changed. chrome.tabs.onDetached = new chrome.Event("tab-detached"); - + // Sends (tabId). // *WILL* be followed by tab-selection-changed. // Will *NOT* be followed or preceded by tab-detached. @@ -351,7 +351,7 @@ var chrome; sendRequest(EnablePageAction, [pageActionId, action]); } - chrome.pageActions.enableForTab.params = [ + chrome.pageActions.enableForTab.params = [ chrome.types.str, { type: "object", @@ -380,7 +380,7 @@ var chrome; chrome.types.singleOrListOf(chrome.types.pInt), chrome.types.fun ]; - + chrome.bookmarks.getChildren = function(id, callback) { validate(arguments, arguments.callee.params); sendRequest(GetBookmarkChildren, id, callback); @@ -390,12 +390,12 @@ var chrome; chrome.types.pInt, chrome.types.fun ]; - + chrome.bookmarks.getTree = function(callback) { validate(arguments, arguments.callee.params); sendRequest(GetBookmarkTree, null, callback); }; - + // TODO(erikkay): allow it to take an optional id as a starting point // BUG=13727 chrome.bookmarks.getTree.params = [ @@ -497,7 +497,7 @@ var chrome; // Sends (id, {parentId, index, oldParentId, oldIndex}) chrome.bookmarks.onMoved = new chrome.Event("bookmark-moved"); - + // Sends (id, [childrenIds]) chrome.bookmarks.onChildrenReordered = new chrome.Event("bookmark-children-reordered"); @@ -508,14 +508,14 @@ var chrome; // Self. chrome.self = chrome.self || {}; chrome.self.onConnect = new chrome.Event("channel-connect"); - + // Register - chrome.self.register_ = function() { + chrome.onLoad_.addListener(function() { var extensionId = RegisterExtension(); - window.addEventListener('unload', function() { - UnregisterExtension(extensionId); }, false); - delete chrome.self.register_; - } + chrome.onUnload_.addListener(function() { + UnregisterExtension(extensionId); + }); + }); chrome.self.getViews = function() { return GetViews(); diff --git a/chrome/renderer/resources/greasemonkey_api.js b/chrome/renderer/resources/greasemonkey_api.js index 3ce1d38..0ad24f0 100644 --- a/chrome/renderer/resources/greasemonkey_api.js +++ b/chrome/renderer/resources/greasemonkey_api.js @@ -1,5 +1,5 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // ----------------------------------------------------------------------------- diff --git a/chrome/renderer/resources/renderer_extension_bindings.js b/chrome/renderer/resources/renderer_extension_bindings.js index 31b97ed..f6222d7 100644 --- a/chrome/renderer/resources/renderer_extension_bindings.js +++ b/chrome/renderer/resources/renderer_extension_bindings.js @@ -10,6 +10,7 @@ var chrome = chrome || {}; (function () { native function OpenChannelToExtension(id); + native function CloseChannel(portId); native function PostMessage(portId, msg); // Port object. Represents a connection to another script context through @@ -66,6 +67,12 @@ var chrome = chrome || {}; PostMessage(this.portId_, JSON.stringify(msg)); }; + // Disconnects the port from the other end. + chrome.Port.prototype.disconnect = function() { + delete chrome.Port.ports_[this.portId_]; + CloseChannel(this.portId_); + } + // Extension object. chrome.Extension = function(id) { this.id_ = id; @@ -85,4 +92,10 @@ var chrome = chrome || {}; chrome.Extension.prototype.getURL = function(path) { return "chrome-extension://" + this.id_ + "/" + path; }; + + chrome.onUnload_.addListener(function() { + for (var i in chrome.Port.ports_) { + chrome.Port.ports_[i].disconnect(); + } + }); })(); -- cgit v1.1