Skip to content

Commit

Permalink
Workaround for #5: allow forcing Flash into windowed mode.
Browse files Browse the repository at this point in the history
  • Loading branch information
patwonder committed Jan 4, 2015
1 parent ccd75ab commit 3d7381d
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 34 deletions.
7 changes: 4 additions & 3 deletions extension/bootstrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ function loadModule(url) {
try {
Cu.import(url, module);
} catch (ex) {
Utils.ERROR("Failed to load module " + url + ": " + ex);
Cu.reportError("[FlashGestures] Failed to load module " + url + ": " + ex + "\n" + ex.stack);
return;
}

Expand All @@ -59,7 +59,8 @@ function loadModule(url) {
try {
obj.init(initData, uninitFuncs);
} catch (ex) {
Utils.ERROR("Calling method init() for module " + url + " failed: " + ex);
Cu.reportError("[FlashGestures] Calling method init() for module " + url + " failed: " +
ex + "\n" + ex.stack);
}
return;
}
Expand Down Expand Up @@ -99,7 +100,7 @@ function install(data, reason) { }

function uninstall(data,reason) {
if (reason == ADDON_UNINSTALL) {
console.log("LOG [FlashGestures] Uninstall detected, resetting critical prefs.");
// Reset critical prefs on uninstall
Services.prefs.clearUserPref("extensions.flashgestures.enabled");
Services.prefs.clearUserPref("extensions.flashgestures.toggleButtonAdded");
}
Expand Down
7 changes: 7 additions & 0 deletions extension/chrome/content/ForceWindowedFlash.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@namespace url(http://www.w3.org/1999/xhtml);

object[type="application/x-shockwave-flash"]:not(.flashgestures-forced-window),
embed[type="application/x-shockwave-flash"]:not(.flashgestures-forced-window)
{
-moz-binding: url("chrome://flashgestures/content/bindings.xml#forceWindowedFlashPlayer") !important;
}
48 changes: 48 additions & 0 deletions extension/chrome/content/bindings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<bindings xmlns="http://www.mozilla.org/xbl"
xmlns:xbl="http://www.mozilla.org/xbl"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<binding id="forceWindowedFlashPlayer" bindToUntrustedContent="true">
<implementation>
<constructor>
<![CDATA[
let plugin = this;
let wmode = plugin.getAttribute("wmode") || (function() {
let params = plugin.querySelectorAll("param[name]");
for (let i = 0, l = params.length; i < l; i++) {
let param = params[i];
if (param.getAttribute("name").toLowerCase() === "wmode")
return param.getAttribute("value");
}
return "";
})();
//console.log("[FlashGestures] Flash player detected, wmode = " + (wmode || "(default)"));
wmode = wmode.toLowerCase();
let preferredWmode = "direct";
if (wmode === "opaque" || wmode === "transparent") {
if (plugin.hasAttribute("wmode")) {
plugin.setAttribute("wmode", preferredWmode);
} else {
let params = plugin.querySelectorAll("param[name]");
for (let i = 0, l = params.length; i < l; i++) {
let param = params[i];
if (param.getAttribute("name").toLowerCase() === "wmode") {
param.setAttribute("value", preferredWmode);
break;
}
}
}
//console.log("[FlashGestures] Forced into wmode = " + preferredWmode);
}
// Self-"unbind"ing
// This does not actually remove the binding, however. But it does allow other bindings
// to be attached to plugin elements. See
// https://ask.mozilla.org/question/297/apply-and-remove-xbl-binding-on-runtime/
// for details.
plugin.classList.add("flashgestures-forced-window");
]]>
</constructor>
</implementation>
</binding>
</bindings>
63 changes: 42 additions & 21 deletions extension/chrome/content/modules/AppIntegration.jsm
Original file line number Diff line number Diff line change
Expand Up @@ -41,27 +41,37 @@ Cu.import(moduleURIPrefix + "Localization.jsm");
*/
let wrappers = [];

/**
* Timers from Utils.runAsyncTimeout
* @type Array of nsITimer
*/
let timers = [];

/**
* Globally referable name in the application window's context
*/
const globalName = "gFlashGestures";

const stylesheetURL = "chrome://flashgestures/skin/main.css";
const forceWindowedFlashPlayerStylesheetURL = "chrome://flashgestures/content/ForceWindowedFlash.css";

/**
* Exported app integration functions.
* @class
*/
let AppIntegration = {
init: function(data, unlist) {
loadStylesheet();
loadStylesheet(stylesheetURL);
if (Prefs.forceWindowedFlashPlayer)
loadStylesheet(forceWindowedFlashPlayerStylesheetURL);

if (Hook.initialized) {
// Listen for pref changes
Prefs.addListener(function(name) {
if (name == "enabled")
AppIntegration.reloadPrefs();
});
registerPrefChangeHandlers();
}

forEachOpenWindow(this.addWindow, this);
Expand All @@ -74,7 +84,9 @@ let AppIntegration = {
Services.wm.removeListener(WindowListener);
forEachOpenWindow(this.removeWindow, this);

unloadStylesheet();
if (Prefs.forceWindowedFlashPlayer)
unloadStylesheet(forceWindowedFlashPlayerStylesheetURL);
unloadStylesheet(stylesheetURL);
},

/**
Expand Down Expand Up @@ -126,8 +138,6 @@ let AppIntegration = {
wrappers.forEach(function (wrapper) {
wrapper.updateState();
});

updateHookState();
},
};

Expand Down Expand Up @@ -324,38 +334,31 @@ let WindowListener = {
onWindowTitleChange: function(xulWindow, newTitle) { }
};

function loadStylesheet() {
function loadStylesheet(url) {
let styleSheetService= Components.classes["@mozilla.org/content/style-sheet-service;1"]
.getService(Components.interfaces.nsIStyleSheetService);
let styleSheetURI = Services.io.newURI(stylesheetURL, null, null);
styleSheetService.loadAndRegisterSheet(styleSheetURI, styleSheetService.AUTHOR_SHEET);
let uri = Services.io.newURI(url, null, null);
styleSheetService.loadAndRegisterSheet(uri, styleSheetService.AUTHOR_SHEET);
}

function unloadStylesheet() {
function unloadStylesheet(url) {
let styleSheetService = Components.classes["@mozilla.org/content/style-sheet-service;1"]
.getService(Components.interfaces.nsIStyleSheetService);
let styleSheetURI = Services.io.newURI(stylesheetURL, null, null);
if (styleSheetService.sheetRegistered(styleSheetURI, styleSheetService.AUTHOR_SHEET)) {
styleSheetService.unregisterSheet(styleSheetURI, styleSheetService.AUTHOR_SHEET);
let uri = Services.io.newURI(url, null, null);
if (styleSheetService.sheetRegistered(uri, styleSheetService.AUTHOR_SHEET)) {
styleSheetService.unregisterSheet(uri, styleSheetService.AUTHOR_SHEET);
}
}

let timers = [];

function clearPendingTimers() {
timers.forEach(function(timer) {
Utils.cancelAsyncTimeout(timer);
});
timers = [];
}

let previousHookState = Prefs.enabled;

function updateHookState() {
if (Prefs.enabled == previousHookState)
return;
previousHookState = Prefs.enabled;
if (Prefs.enabled) {
function updateHookState(newState) {
if (newState) {
Utils.LOG("Installing hooks... (prefs enable)");
Hook.install();
wrappers.forEach(function (wrapper) {
Expand All @@ -367,6 +370,21 @@ function updateHookState() {
}
}

function updateForceWindowedFlashPlayerState(newState) {
if (newState) {
Utils.LOG("Registering ForceWindowedFlash.css...");
loadStylesheet(forceWindowedFlashPlayerStylesheetURL);
} else {
Utils.LOG("Unregistering ForceWindowedFlash.css...");
unloadStylesheet(forceWindowedFlashPlayerStylesheetURL);
}
}

function registerPrefChangeHandlers() {
Prefs.registerPrefChangeHandler("enabled", updateHookState);
Prefs.registerPrefChangeHandler("forceWindowedFlashPlayer", updateForceWindowedFlashPlayerState);
}

function onPluginEvent(event) {
// Only handle plugin instantiation events
if (event.type != "PluginInstantiated")
Expand All @@ -377,7 +395,10 @@ function onPluginEvent(event) {
// We're expecting the target to be a plugin.
if (!(plugin instanceof Ci.nsIObjectLoadingContent))
return;


Utils.LOG(event.type + " triggered on <" + plugin.localName + "> with mime-type \"" +
plugin.getAttribute("type") + "\"");

// Do async hook installing. The relavant plugin processes should be ready
// in no more than 10 seconds
let MaxLoadingTimeMillis = 10000;
Expand Down
52 changes: 42 additions & 10 deletions extension/chrome/content/modules/Prefs.jsm
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ let branch = Services.prefs.getBranch(prefRoot);
* List of listeners to be notified whenever preferences are updated
* @type Array of Function
*/
let listeners = [];
let globalListeners = [];
let prefChangeListenersMap = Object.create(null);

/**
* This object allows easy access to Flash Gestures' preferences, all defined
Expand Down Expand Up @@ -110,18 +111,18 @@ let Prefs = {
* reloaded
*/
addListener: function(/**Function*/ listener) {
let index = listeners.indexOf(listener);
let index = globalListeners.indexOf(listener);
if (index < 0)
listeners.push(listener);
globalListeners.push(listener);
},

/**
* Removes a preferences listener
*/
removeListener: function(/**Function*/ listener) {
let index = listeners.indexOf(listener);
let index = globalListeners.indexOf(listener);
if (index >= 0)
listeners.splice(index, 1);
globalListeners.splice(index, 1);
},

/**
Expand All @@ -135,6 +136,7 @@ let Prefs = {
* Reset a pref to its default value.
*/
reset: function(name) {
let defaultBranch = this.defaultBranch;
let type = defaultBranch.getPrefType(name);
switch (type) {
case Ci.nsIPrefBranch.PREF_INT:
Expand All @@ -148,6 +150,26 @@ let Prefs = {
break;
}
},

/**
* Register a handler that handles pref changing events
*/
registerPrefChangeHandler: function(name, handler) {
if (this.defaultBranch.getPrefType(name) === Ci.nsIPrefBranch.PREF_INVALID)
throw new Exception("Cannot register pref change handler for non-existing prefs.");

let listeners = prefChangeListenersMap[name] || (prefChangeListenersMap[name] = []);
listeners.push(handler);
},

/**
* Unregister a previously-registered pref change handler
*/
unregisterPrefChangeHandler: function(name, handler) {
let listeners = prefChangeListenersMap[name];
if (listeners)
Utils.removeOneItem(listeners, handler);
},
};

/**
Expand Down Expand Up @@ -199,13 +221,23 @@ function unregisterObservers() {
* Triggers preference listeners whenever a preference is changed.
*/
function triggerListeners(/**String*/ name) {
listeners.slice().forEach(function(listener) {
globalListeners.slice().forEach(function(listener) {
try {
listener(name);
} catch (ex) {
Utils.ERROR("Failed to call listeners for Prefs." + name + ": " + ex);
}
});
let prefChangeListeners = prefChangeListenersMap[name];
if (prefChangeListeners) {
prefChangeListeners.slice().forEach(function(listener) {
try {
listener(Prefs[name]);
} catch (ex) {
Utils.ERROR("Failed to call pref change listeners for Prefs." + name + ": " + ex);
}
});
}
}

/**
Expand All @@ -217,8 +249,8 @@ function defineProperty(/**String*/ name, defaultValue, /**Function*/ readFunc,
try {
value = readFunc();
triggerListeners(name);
} catch(e) {
Cu.reportError(e);
} catch(ex) {
Utils.ERROR("Prefs." + name + " _update_ exception: " + ex);
}
}
Object.defineProperty(Prefs, name, {
Expand All @@ -232,8 +264,8 @@ function defineProperty(/**String*/ name, defaultValue, /**Function*/ readFunc,
writeFunc(newValue);
value = newValue;
triggerListeners(name);
} catch(e) {
Cu.reportError(e);
} catch(ex) {
Utils.ERROR("Prefs." + name + " setter exception: " + ex);
} finally {
PrefsPrivate.ignorePrefChanges = false;
}
Expand Down
1 change: 1 addition & 0 deletions extension/chrome/content/preferences/FlashGestures.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pref("extensions.flashgestures.enabled", true);
pref("extensions.flashgestures.toggleButtonAdded", false);
pref("extensions.flashgestures.forceWindowedFlashPlayer", false);

0 comments on commit 3d7381d

Please sign in to comment.