userChrome.js hacks

Discussion about official Mozilla Firefox builds
Post Reply
morat
Posts: 6404
Joined: February 3rd, 2009, 6:29 pm

userChrome.js hacks

Post by morat »

Are userChrome.js hacks using the -moz-binding property still possible in Fx 71 and Fx 72?

My hacks still work in Fx 70.

What is userChrome.js?
http://www.userchrome.org/what-is-userchrome-js.html

userChrome.js hack example
http://github.com/Sporif/firefox-quantu ... Chrome.css
http://github.com/Sporif/firefox-quantu ... Chrome.xml
http://gist.github.com/Sporif/ad6e917d8 ... 80d3c8918c

Remove XBL implementation
http://bugzilla.mozilla.org/show_bug.cgi?id=1566221
User avatar
therube
Posts: 21703
Joined: March 10th, 2004, 9:59 pm
Location: Maryland USA

Re: userChrome.js hacks

Post by therube »

What is http://github.com/Sporif/firefox-quantu ... Chrome.css supposed to do?

copy code, put into /chrome/userChrome.css
enable "chrome" in FF ("stylesheets", about:config, toolkit.legacyUserProfileCustomizations.stylesheets)
restart FF

I'm not seeing any difference, assuming I've done things correctly (72 Nightly).


(The word legacy in there is telling, but then we all knew that.)
Fire 750, bring back 250.
Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.19) Gecko/20110420 SeaMonkey/2.0.14 Pinball CopyURL+ FetchTextURL FlashGot NoScript
morat
Posts: 6404
Joined: February 3rd, 2009, 6:29 pm

Re: userChrome.js hacks

Post by morat »

Is there an error involving the -moz-binding property in the browser console?

Instructions:

* start firefox
* set toolkit.legacyUserProfileCustomizations.stylesheets pref to true
* exit firefox
* create userChrome.css file in chrome folder
* create userChrome.xml file in chrome folder
* create RestartFirefoxButton_Movable.uc.js file in chrome folder
* start firefox
* test restart button on nav bar next to hamburger button

Firefox Quantum compatible userChrome.js
http://github.com/Sporif/firefox-quantum-userchromejs
Gusar
Posts: 205
Joined: March 17th, 2006, 1:52 pm

Re: userChrome.js hacks

Post by Gusar »

With XBL gone, any code that relies on it, so everything involving -moz-binding, indeed does not work anymore. So say goodbye to userChrome.js. There doesn't seem to be any replacement, there's no other way to load custom code like this anymore.
morat
Posts: 6404
Joined: February 3rd, 2009, 6:29 pm

Re: userChrome.js hacks

Post by morat »

I tested...

The userChrome.js hack succeeds in the Firefox Portable 71.0b8 beta build.
The userChrome.js hack fails in the Firefox Portable 72.0a1 nightly build.

There are no errors in the browser console.

@Gusar

You can do similar hacks with the AutoConfig file.

Customizing Firefox using AutoConfig
http://support.mozilla.org/kb/customizi ... autoconfig

Example
http://github.com/alice0775/userChrome. ... /master/72

AutoConfig is sandboxed by default on the release build. (i.e. can't use the Components object)

You can disable the sandbox by setting the general.config.sandbox_enabled pref to false in the autoconfig.js file.
Our long term plan is to remove the ability to turn off the sandboxing.
Firefox 62 Release Notes
http://www.mozilla.org/firefox/62.0/releasenotes/
Last edited by morat on November 17th, 2019, 8:40 am, edited 1 time in total.
User avatar
therube
Posts: 21703
Joined: March 10th, 2004, 9:59 pm
Location: Maryland USA

Re: userChrome.js hacks

Post by therube »

(When I initially looked, didn't realize that all three files were need.
When looking later, yes I found the same as you.
Nothing noted in Error Console & the code no longer worked.)
Fire 750, bring back 250.
Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.19) Gecko/20110420 SeaMonkey/2.0.14 Pinball CopyURL+ FetchTextURL FlashGot NoScript
morat
Posts: 6404
Joined: February 3rd, 2009, 6:29 pm

Re: userChrome.js hacks

Post by morat »

Here are my config files in Firefox 117.

* <install directory>\defaults\pref\autoconfig.js

Code: Select all

pref("general.config.sandbox_enabled", false);
pref("general.config.filename", "mozilla.cfg");
pref("general.config.obscure_value", 0);
* <install directory>\mozilla.cfg

Code: Select all

// mozilla.cfg file needs to start with a comment line

// mozilla.cfg file is sandboxed by default i.e. can't use Components object
// disable sandbox by setting general.config.sandbox_enabled pref to false in autoconfig.js file

// run userChrome.js example.uc.js example.as.css example.css files in chrome folder
// do not run userChrome.css userContent.css example.js files in chrome folder

// browser-delayed-startup-finished topic supports browser window only

// Firefox 68 uses browser.xul   page
// Firefox 69 uses browser.xhtml page

// Firefox 116 uses Components.utils.import("resource://gre/modules/Services.jsm");
// Firefox 117 uses var Services = globalThis.Services;

var Services = globalThis.Services;
Services.console.logStringMessage("mozilla.cfg script loaded");
Services.obs.addObserver(function (aSubject, aTopic, aData) {
  var chromeWindow = aSubject;
  chromeWindow.setTimeout(function () {
    try {
      if (chromeWindow.userChromeJsMod) return;
      chromeWindow.userChromeJsMod = true;
      var chromeFiles = chromeWindow.FileUtils.getDir("UChrm", []).directoryEntries;
      var sss = Components.classes["@mozilla.org/content/style-sheet-service;1"].
        getService(Components.interfaces.nsIStyleSheetService);
      while (chromeFiles.hasMoreElements()) {
        var file = chromeFiles.getNext().QueryInterface(Components.interfaces.nsIFile);
        var fileURI = Services.io.newFileURI(file);
        if (file.isFile()) {
          if (/(^userChrome|\.uc)\.js$/i.test(file.leafName)) {
            Services.scriptloader.loadSubScriptWithOptions(fileURI.spec, {
              target: chromeWindow,
              charset: "UTF-8",
              ignoreCache: true,
            });
          } else if (/\.as\.css$/i.test(file.leafName)) {
            if (!sss.sheetRegistered(fileURI, sss.AGENT_SHEET)) {
              sss.loadAndRegisterSheet(fileURI, sss.AGENT_SHEET);
            }
          } else if (/^(?!(userChrome|userContent)\.css$).+\.css$/i.test(file.leafName)) {
            if (!sss.sheetRegistered(fileURI, sss.USER_SHEET)) {
              sss.loadAndRegisterSheet(fileURI, sss.USER_SHEET);
            }
          }
        }
      }
    } catch (aError) {
      Components.utils.reportError(aError);
    }
  }, 10);
}, "browser-delayed-startup-finished", false);
* <profile directory>\chrome\RestartFirefoxButton_Movable.uc.js

Code: Select all

(function () {
  if (location != "chrome://browser/content/browser.xul" &&
      location != "chrome://browser/content/browser.xhtml") return;
  try {
    CustomizableUI.createWidget({
      id: "__unique_identifier_restart_button", // should match id below
      type: "custom",
      defaultArea: CustomizableUI.AREA_MENUBAR,
   // defaultArea: CustomizableUI.AREA_NAVBAR,
      onBuild: function (aDocument) {
        var XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
        var toolbarbutton = aDocument.createElementNS(XUL_NS, "toolbarbutton");
        toolbarbutton.onclick = function (aEvent) {
          var win = aEvent.target.ownerDocument.defaultView;
          if (aEvent.button == 0) {
            if (aEvent.shiftKey) {
              Services.appinfo.invalidateCachesOnRestart();
              Services.prompt.alert(win, "Restart", "Invalidate caches on restart.");
            }
            var os = Components.classes["@mozilla.org/observer-service;1"].
              getService(Components.interfaces.nsIObserverService);
            var cancelQuit = Components.classes["@mozilla.org/supports-PRBool;1"].
              createInstance(Components.interfaces.nsISupportsPRBool);
            os.notifyObservers(cancelQuit, "quit-application-requested", "restart");
            if (cancelQuit.data) {
              Services.prompt.alert(win, "Restart", "Abort restart process.");
            } else {
              var appStartup = Components.classes["@mozilla.org/toolkit/app-startup;1"].
                getService(Components.interfaces.nsIAppStartup);
              appStartup.quit(appStartup.eAttemptQuit | appStartup.eRestart);
            }
          } else if (aEvent.button == 1) {
            if (aEvent.shiftKey) {
              Services.appinfo.invalidateCachesOnRestart();
              Services.prompt.alert(win, "Restart", "Invalidate caches on startup.");
            }
            var os = Components.classes["@mozilla.org/observer-service;1"].
              getService(Components.interfaces.nsIObserverService);
            var cancelQuit = Components.classes["@mozilla.org/supports-PRBool;1"].
              createInstance(Components.interfaces.nsISupportsPRBool);
            os.notifyObservers(cancelQuit, "quit-application-requested", null);
            if (cancelQuit.data) {
              Services.prompt.alert(win, "Restart", "Abort quit process.");
            } else {
              var prefBranch = Components.classes["@mozilla.org/preferences-service;1"].
                getService(Components.interfaces.nsIPrefBranch);
              var pref = "browser.sessionstore.resume_session_once";
              prefBranch.setBoolPref(pref, true);
              var appStartup = Components.classes["@mozilla.org/toolkit/app-startup;1"].
                getService(Components.interfaces.nsIAppStartup);
              appStartup.quit(appStartup.eAttemptQuit);
            }
          }
        };
        var dataUrl = "data:image/png;base64," +
          "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAANbY1E9YMgAAAB" +
          "h0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjM2qefiJQAAA2hJREFUOE9tkm1MU1ccxg9F" +
          "YKIIxbdgw4e9GEQYoomArRVYwsIoEakUsRQ3KQpiF8SXMDdtajL8gho+TKeJyYxaFGyltg" +
          "ZK1bkurg4uQ0QMgjSbOrbwUoIglPbe9tm5NdGgO8mT3PM/9/md/8sJIv+3JOYwGk6miolY" +
          "HB4y5ZqeIcDfxD87SH4vmg5YJOZk4veOvm+XmOOE+XfOZp7qfya/+Ny7/dq/KNAPTafoHv" +
          "VH5LZdJWmNnxKxKSE8xzYQuvHCl3MBEnNSwv7OkVKrC0rrBDabXiLX7EbhbQ6VncCBLi9S" +
          "dT2TCdXM5PbGIURlndv7FiAxR0fm3W4qu+VC0c1RyJpGkWucQLZxGjKLF1tsfqjuAYcesj" +
          "ja60F568hcQFhWqyL95JNXiisvkHGyF+LaHmSfcXKlLS5UOGZRbGex7RcOOxwc1AyLCus7" +
          "gCWKuz/FVTH+5UrjhFDeMB68qamPrD2tjSk0n19/5IHr4B9uVHR6UeLwYGeHB5Vtw3MzEE" +
          "hNTuGWyz+LSs7r53924Rz5sCyF1hcVKtWvj69qZ3R9s9AOsPj2iRdHn7LQ2N4BhGU21IiK" +
          "6nct2/pDSfCaY2JqXkAVLJBa7CuK7b41BxgkH2Sw9hCDdVQrd//GhaTUVxBaez7dsHyQP+" +
          "R/4iVS2X1BEuN9CllEtVQQ93XaUlmtIkZ+XBkiPn2YxlbwcbJkm12hsY1AO+jDdwMcjjk5" +
          "fN/vQbzmXve8xJovApmk6mM/yDJoY3deqovKbzQESU2DfHl8hgHA3rYRqLt8+IrhoOnmUN" +
          "PtBm3cmEjZdoaIm8sFm0y/CuVXB5crm5+vqmJ80Xk3DNQcTRUUAFRSQHk3oO6ks3ZQkIM2" +
          "qd2NMusYZD862Y3HH/kyTz32FdIRp5/omwlNqddQc/gbAD9TXZ8Hh3tZlHb46bxZyK0z2G" +
          "yZhNwyjvzmYRS3DENtG8OiHFMLiZGtpmZB4BXyGRQ3DSGxumMqTfdw6pseD/bRMlR33Sho" +
          "nULBzXHsuDUONc1m9b52F1lZzfeFb+zrRaewNTy75U/yieZzEn9EGpFjuZ6q7XIW6l/MqA" +
          "z/oODiX96MusdDUTnGBvJxZSa1RL65PUDYYBCRxNoM+iWkmkc+Ko8mSSckJLletSD97B6S" +
          "VLebgvNIZGIsPV8410zIfzl/yL/mmVpFAAAAAElFTkSuQmCC";
        var tooltip = [];
        tooltip.push("", "", "L: restart application with previous windows and tabs");
        tooltip.push("M: quit application, open previous windows and tabs on startup");
        tooltip.push("R: open button context popup", "");
        tooltip.push("S+L: left click option and invalidate caches on restart");
        tooltip.push("S+M: middle click option and invalidate caches on startup", "");
        tooltip.push("The middle click option is for users that do not normally restore sessions.");
        var props = {
          id: "__unique_identifier_restart_button",
          class: "toolbarbutton-1 chromeclass-toolbar-additional",
          label: "Restart",
          tooltiptext: "Restart" + tooltip.join("\n"),
          style: 'list-style-image: url("' + dataUrl + '"); -moz-image-region: auto;',
        };
        for (var p in props) toolbarbutton.setAttribute(p, props[p]);
        return toolbarbutton;
      },
    });
  } catch (aError) {
    // [check] Show Content Messages in Firefox 109
    // [select] Browser Console Mode Multiprocess in Firefox 110
    Components.utils.reportError(aError);
  };
})();
* <profile directory>\chrome\StylesFirefox.as.css

Code: Select all

/* AGENT_SHEET */

@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
@namespace html url("http://www.w3.org/1999/xhtml");

/* Firefox fails to set correct order on startup, see browser.uiCustomization.state pref */

/* use -moz-box-ordinal-group property in Firefox 112 */
/* use order                  property in Firefox 113 */

@-moz-document url-prefix("chrome://browser/content/browser.xhtml") {
  toolbaritem#menubar-items                        { order: 1 !important; }
  toolbarbutton#__unique_identifier_restart_button { order: 2 !important; }
}
Troubleshooting info: http://forums.mozillazine.org/viewtopic ... #p14886674

Deploying Firefox in an enterprise environment
http://web.archive.org/web/201910060610 ... _before_60

Observer Notifications
http://web.archive.org/web/201910060345 ... ifications

CustomizableUI
http://web.archive.org/web/201910021231 ... ableUI.jsm
http://web.archive.org/web/201910021231 ... ed_widgets

Agent Sheet
http://www.userchrome.org/adding-style- ... agentsheet
http://web.archive.org/web/201909301025 ... et_Service

Services.jsm is going to be removed in Firefox 117
http://groups.google.com/a/mozilla.org/ ... RgKcXmGd5M

Another example: http://forums.mozillazine.org/viewtopic ... &t=3084974
Last edited by morat on September 14th, 2023, 4:32 pm, edited 13 times in total.
Kenosis
Posts: 77
Joined: November 11th, 2011, 5:43 am

Re: userChrome.js hacks

Post by Kenosis »

Thank you very much. Works perfect for me.
Cye3s
Posts: 20
Joined: December 28th, 2007, 9:53 pm

Re: userChrome.js hacks

Post by Cye3s »

Dont work on 78.3 esr, sad
pintassilgo
Posts: 200
Joined: August 30th, 2013, 3:50 pm

Re: userChrome.js hacks

Post by pintassilgo »

It works using autoconfig as it always has. userChromeJS by XBL binding was an ugly hack and was removed.
User avatar
JAB Creations
Posts: 394
Joined: December 28th, 2003, 10:21 pm
Location: Sarasota Florida
Contact:

Re: userChrome.js hacks

Post by JAB Creations »

Morat, this worked fantastic in Firefox 115 ESR however I'm having trouble with Firefox 102 ESR.

With the exact same setup I get this in the Browser Toolbox / console:
TypeError: Services is undefined
Well, so I start to try to debug. If I manually run the script in the Toolbox / console it doesn't throw any errors in Firefox 102 ESR.

So I did a bit more research and came across the following at https://wiki.mozilla.org/UserChrome.js:
userChrome.js might be run either as soon as possible or onLoad. Most customization I've seen so far requires for the chrome to be fully loaded. Applying it ASAP will require further boilerplate code to delay some code until the chrome is ready.
So now I'm thinking about setTimeout however I know it's not going to be available in a website developer content. Well, looked at the script you referenced earlier and I see chromeWindow.setTimeout. However it is already defined once globalThis.Services is already called so yeah... I'm at a dead-end here. How do we modify this to delay until globalThis.Services becomes available please?
Here to mostly fix the browser's broken GUI. I maintain the Fixed Firefox website to share the things I've confirmed work.
morat
Posts: 6404
Joined: February 3rd, 2009, 6:29 pm

Re: userChrome.js hacks

Post by morat »

See files like aboutPage.js in Firefox 115 ESR for possible backward compatibility with ESR versions.

Reference
http://searchfox.org/mozilla-esr115/sou ... outPage.js

i.e.

Code: Select all

var Services = globalThis.Services || ChromeUtils.import("resource://gre/modules/Services.jsm").Services;
Services.console.logStringMessage("mozilla.cfg script loaded");
I use the following code in Firefox 102 ESR and Firefox 115 ESR.

Code: Select all

Components.utils.import("resource://gre/modules/Services.jsm");
Services.console.logStringMessage("mozilla.cfg script loaded");
I use the following code in Firefox 117.

Code: Select all

var Services = globalThis.Services;
Services.console.logStringMessage("mozilla.cfg script loaded");
Please don't post in old threads.
User avatar
JAB Creations
Posts: 394
Joined: December 28th, 2003, 10:21 pm
Location: Sarasota Florida
Contact:

Re: userChrome.js hacks

Post by JAB Creations »

Morat, thank you! So Firefox 102 ESR and 115 ESR both work using different code combined (for anyone looking to clean/fix 102 ESR and 115 ESR as well):

Code: Select all

var Services = globalThis.Services || ChromeUtils.import("resource://gre/modules/Services.jsm").Services;
So globalThis.Services works in 115 ESR+ while ChromeUtils.import("resource://gre/modules/Services.jsm").Services works in 102 ESR and I confirmed 91 ESR as well.
Here to mostly fix the browser's broken GUI. I maintain the Fixed Firefox website to share the things I've confirmed work.
Farby
Posts: 20
Joined: June 28th, 2011, 1:47 am
Location: Minsk, Belarus

Re: userChrome.js hacks

Post by Farby »

So globalThis.Services works in 115 ESR+
Services are always available in FF 115+, but can be rewritten by another script, for a access to original Services, you need to query globalThis.Services
Life sometimes throws this what you want to find ...
Post Reply