mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-22 00:17:32 +09:00
fuck this shit bro (add tabs.onReplaced notification)
This commit is contained in:
parent
e5a431b519
commit
5ac0d5acc3
6 changed files with 108 additions and 7 deletions
|
|
@ -2920,6 +2920,18 @@
|
||||||
// Finish tearing down the tab that's going away.
|
// Finish tearing down the tab that's going away.
|
||||||
remoteBrowser._endRemoveTab(aOtherTab);
|
remoteBrowser._endRemoveTab(aOtherTab);
|
||||||
|
|
||||||
|
// Notify WebExtensions when one tab is replaced by another. Tab
|
||||||
|
// adoption uses this same swap internally, but represents a move
|
||||||
|
// and is marked below so it does not generate a replacement event.
|
||||||
|
if (!aOurTab._adoptingTab) {
|
||||||
|
let event = new CustomEvent("TabReplaced", {
|
||||||
|
bubbles: true,
|
||||||
|
detail: {addedTab: aOurTab, removedTab: aOtherTab},
|
||||||
|
});
|
||||||
|
aOurTab.dispatchEvent(event);
|
||||||
|
}
|
||||||
|
delete aOurTab._adoptingTab;
|
||||||
|
|
||||||
if (isBusy)
|
if (isBusy)
|
||||||
this.setTabTitleLoading(aOurTab);
|
this.setTabTitleLoading(aOurTab);
|
||||||
else
|
else
|
||||||
|
|
@ -3359,6 +3371,7 @@
|
||||||
params.userContextId = aTab.getAttribute("usercontextid");
|
params.userContextId = aTab.getAttribute("usercontextid");
|
||||||
}
|
}
|
||||||
let newTab = this.addTab("about:blank", params);
|
let newTab = this.addTab("about:blank", params);
|
||||||
|
newTab._adoptingTab = aTab;
|
||||||
let newBrowser = this.getBrowserForTab(newTab);
|
let newBrowser = this.getBrowserForTab(newTab);
|
||||||
let newURL = aTab.linkedBrowser.currentURI.spec;
|
let newURL = aTab.linkedBrowser.currentURI.spec;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,7 @@ let tabListener = {
|
||||||
|
|
||||||
AllWindowEvents.addListener("TabClose", this);
|
AllWindowEvents.addListener("TabClose", this);
|
||||||
AllWindowEvents.addListener("TabOpen", this);
|
AllWindowEvents.addListener("TabOpen", this);
|
||||||
|
AllWindowEvents.addListener("TabReplaced", this);
|
||||||
WindowListManager.addOpenListener(this.handleWindowOpen);
|
WindowListManager.addOpenListener(this.handleWindowOpen);
|
||||||
WindowListManager.addCloseListener(this.handleWindowClose);
|
WindowListManager.addCloseListener(this.handleWindowClose);
|
||||||
|
|
||||||
|
|
@ -138,6 +139,10 @@ let tabListener = {
|
||||||
this.emitRemoved(tab, false);
|
this.emitRemoved(tab, false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "TabReplaced":
|
||||||
|
this.emitReplaced(event.detail.addedTab, event.detail.removedTab);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -220,6 +225,13 @@ let tabListener = {
|
||||||
}, Ci.nsIThread.DISPATCH_NORMAL);
|
}, Ci.nsIThread.DISPATCH_NORMAL);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
emitReplaced(addedTab, removedTab) {
|
||||||
|
this.emit("tab-replaced", {
|
||||||
|
addedTabId: TabManager.getId(addedTab),
|
||||||
|
removedTabId: TabManager.getId(removedTab),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
tabReadyInitialized: false,
|
tabReadyInitialized: false,
|
||||||
tabReadyPromises: new WeakMap(),
|
tabReadyPromises: new WeakMap(),
|
||||||
initializingTabs: new WeakSet(),
|
initializingTabs: new WeakSet(),
|
||||||
|
|
@ -347,7 +359,15 @@ extensions.registerSchemaAPI("tabs", "addon_parent", context => {
|
||||||
};
|
};
|
||||||
}).api(),
|
}).api(),
|
||||||
|
|
||||||
onReplaced: ignoreEvent(context, "tabs.onReplaced"),
|
onReplaced: new EventManager(context, "tabs.onReplaced", fire => {
|
||||||
|
let listener = (eventName, event) => {
|
||||||
|
fire(event.addedTabId, event.removedTabId);
|
||||||
|
};
|
||||||
|
tabListener.on("tab-replaced", listener);
|
||||||
|
return () => {
|
||||||
|
tabListener.off("tab-replaced", listener);
|
||||||
|
};
|
||||||
|
}).api(),
|
||||||
|
|
||||||
onMoved: new EventManager(context, "tabs.onMoved", fire => {
|
onMoved: new EventManager(context, "tabs.onMoved", fire => {
|
||||||
// There are certain circumstances where we need to ignore a move event.
|
// There are certain circumstances where we need to ignore a move event.
|
||||||
|
|
|
||||||
|
|
@ -750,9 +750,12 @@ SingletonEventManager.prototype = {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Simple API for event listeners where events never fire.
|
// Simple API for event listeners where events never fire.
|
||||||
function ignoreEvent(context, name) {
|
function ignoreEvent(context, name, warn = true) {
|
||||||
return {
|
return {
|
||||||
addListener: function(callback) {
|
addListener: function(callback) {
|
||||||
|
if (!warn) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let id = context.extension.id;
|
let id = context.extension.id;
|
||||||
let frame = Components.stack.caller;
|
let frame = Components.stack.caller;
|
||||||
let msg = `In add-on ${id}, attempting to use listener "${name}", which is unimplemented.`;
|
let msg = `In add-on ${id}, attempting to use listener "${name}", which is unimplemented.`;
|
||||||
|
|
@ -1095,8 +1098,8 @@ class MessageManagerProxy {
|
||||||
if (this.messageManager) {
|
if (this.messageManager) {
|
||||||
return this.messageManager.sendAsyncMessage(...args);
|
return this.messageManager.sendAsyncMessage(...args);
|
||||||
}
|
}
|
||||||
/* globals uneval */
|
// Message senders can outlive their child process during normal teardown.
|
||||||
Cu.reportError(`Cannot send message: Other side disconnected: ${uneval(args)}`);
|
// Treat this as a dropped message instead of reporting a spurious error.
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -321,13 +321,60 @@ function webAPIForAddon(addon) {
|
||||||
|
|
||||||
let result = {};
|
let result = {};
|
||||||
|
|
||||||
|
function cloneable(value, seen = new Set()) {
|
||||||
|
if (value === null || value === undefined ||
|
||||||
|
typeof value == "string" || typeof value == "number" ||
|
||||||
|
typeof value == "boolean") {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof value != "object") {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Older message managers cannot structured-clone these XPCOM values.
|
||||||
|
try {
|
||||||
|
if (value instanceof Ci.nsIURI) {
|
||||||
|
return value.spec;
|
||||||
|
}
|
||||||
|
if (value instanceof Ci.nsIFile) {
|
||||||
|
return value.path;
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
|
if (seen.has(value)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
seen.add(value);
|
||||||
|
|
||||||
|
let className = Cu.getClassName(value, true);
|
||||||
|
if (className == "Array") {
|
||||||
|
return value.map(item => cloneable(item, seen));
|
||||||
|
}
|
||||||
|
if (className != "Object") {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
let copy = {};
|
||||||
|
for (let key of Object.keys(value)) {
|
||||||
|
let item = cloneable(value[key], seen);
|
||||||
|
if (item !== undefined) {
|
||||||
|
copy[key] = item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
// By default just pass through any plain property, the webidl will
|
// By default just pass through any plain property, the webidl will
|
||||||
// control access. Also filter out private properties, regular Addon
|
// control access. Also filter out private properties, regular Addon
|
||||||
// objects are okay but MockAddon used in tests has non-serializable
|
// objects are okay but MockAddon used in tests has non-serializable
|
||||||
// private properties.
|
// private properties.
|
||||||
for (let prop in addon) {
|
for (let prop in addon) {
|
||||||
if (prop[0] != "_" && typeof(addon[prop]) != "function") {
|
if (prop[0] != "_" && typeof(addon[prop]) != "function") {
|
||||||
result[prop] = addon[prop];
|
let value = cloneable(addon[prop]);
|
||||||
|
if (value !== undefined) {
|
||||||
|
result[prop] = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,20 @@ const CHILD_SCRIPT = "resource://gre/modules/addons/Content.js";
|
||||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
Cu.import("resource://gre/modules/Services.jsm");
|
Cu.import("resource://gre/modules/Services.jsm");
|
||||||
|
|
||||||
|
function deserializeTriggeringPrincipal(principal) {
|
||||||
|
if (typeof principal != "string") {
|
||||||
|
return principal;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return Cc["@mozilla.org/network/serialization-helper;1"]
|
||||||
|
.getService(Ci.nsISerializationHelper)
|
||||||
|
.deserializeObject(principal)
|
||||||
|
.QueryInterface(Ci.nsIPrincipal);
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var gSingleton = null;
|
var gSingleton = null;
|
||||||
|
|
||||||
function amManager() {
|
function amManager() {
|
||||||
|
|
@ -219,7 +233,7 @@ amManager.prototype = {
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.installAddonsFromWebpage(payload.mimetype,
|
return this.installAddonsFromWebpage(payload.mimetype,
|
||||||
aMessage.target, payload.triggeringPrincipal, payload.uris,
|
aMessage.target, deserializeTriggeringPrincipal(payload.triggeringPrincipal), payload.uris,
|
||||||
payload.hashes, payload.names, payload.icons, callback);
|
payload.hashes, payload.names, payload.icons, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,11 @@ RemoteMediator.prototype = {
|
||||||
let callbackID = this._addCallback(callback, installs.uris);
|
let callbackID = this._addCallback(callback, installs.uris);
|
||||||
|
|
||||||
installs.mimetype = XPINSTALL_MIMETYPE;
|
installs.mimetype = XPINSTALL_MIMETYPE;
|
||||||
installs.triggeringPrincipal = principal;
|
// nsIPrincipal is an XPCOM object and cannot cross the legacy message
|
||||||
|
// manager boundary used by content processes. Serialize it explicitly.
|
||||||
|
installs.triggeringPrincipal = Cc["@mozilla.org/network/serialization-helper;1"]
|
||||||
|
.getService(Ci.nsISerializationHelper)
|
||||||
|
.serializeToString(principal);
|
||||||
installs.callbackID = callbackID;
|
installs.callbackID = callbackID;
|
||||||
|
|
||||||
if (Services.appinfo.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) {
|
if (Services.appinfo.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue