Firefox, March 2020 and later
Around March 2020, the browser.urlbar.clickSelectsAll
preference has been removed.
Since then, this bug has been under discussion, where a patch has been suggested — this would involve recompiling Firefox from scratch.
As the “clickSelectsAll
doesn’t work” duplicates accumulate on Bugzilla, one of these has received a comment by Stephen McCarthy which describes a workaround that involves editing internal Firefox files, specifically the omni.ja
which basically is a zip
file that contains lots of internal files, e.g. JavaScript modules for the browser chrome, including the relevant modules/UrlbarInput.jsm
.
This workaround looks like the simplest approach, but the approach doesn’t work as-is.
There is an official documentation on MDN (archived version) that describes how omni.ja
should be repackaged.
I also found a blog article on Shallow Thoughts about modifying omni.ja
that describes this process in more detail.
Then, there is another thing to worry about: you need to force Firefox to use the modified omni.ja
by clearing its startup cache, which is explained in an In Pursuit Of Laziness blog article that I found.
Modifying internal files
Puttng all these resources together, these are the shell commands that currently work on Arch Linux (core/linux
5.8.1.arch1-1
through 5.12.13.arch1-2
).1
If at any point you run into “permission denied” errors, simply continue executing the commands as root.
These need to be executed after every Firefox update.
The commands are explained afterwards.
Instead of typing the individual commands, you can use this shell script instead, available on this GitHub repo of mine.
That script offers a user-friendly terminal interface; it automatically finds Firefox, changes the omni.ja
, and handles the cache.
It also automatically switches to root as needed and creates backups.
And there’s a web interface where you can pick other options and download a customized shell script.
The commands
urlbarinput_path=omni/modules/UrlbarInput.sys.mjs
cd /tmp
mkdir omni
unzip -d omni -q /usr/lib/firefox/browser/omni.ja
if [[ ! -f /tmp/$urlbarinput_path ]]; then
urlbarinput_path=omni/modules/UrlbarInput.jsm
fi
sed -i 's/this\._preventClickSelectsAll = this\.focused;/this._preventClickSelectsAll = true;/' $urlbarinput_path
sed -i 's/this\._preventClickSelectsAll = this\._textbox\.focused;/this._preventClickSelectsAll = true;/' omni/chrome/browser/content/browser/search/searchbar.js
cd omni
zip -0DXqr omni.ja *
cd ..
mv omni/omni.ja /usr/lib/firefox/browser/omni.ja
chown ⟨user⟩:⟨group⟩ /usr/lib/firefox/browser/omni.ja
rm -r omni
Important notes:
Update Firefox and then close it before doing this.
Firefox needs to have the updates installed (i.e. you may have to start Firefox after upgrading, then close it again).
/usr/lib/firefox
is a possible install path for Firefox; your path may differ, e.g. it may be /usr/share/firefox
.
You should be able to find the possible paths with one of these commands:
whereis -b firefox firefox-esr
which firefox firefox-esr
The correct omni.ja
is in the …/browser/omni.ja
path.
Before any of this is executed make sure you create a copy of the working omni.ja
somewhere, so you have a backup available in case something goes wrong.
Make sure you replace ⟨user⟩
by the user name and ⟨group⟩
by the user group of the original ownership of the file.
As far as I know, in most cases, this should be root:root
, if it isn’t already.
After unzipping omni.ja
you may want to double check that
- the line
this._preventClickSelectsAll = this.focused;
exists in modules/UrlbarInput.jsm
, and
- the line
this._preventClickSelectsAll = this._textbox.focused;
exists in chrome/browser/content/browser/search/searchbar.js
.
Clearing the cache
Finally, Firefox needs to properly load the new omni.ja
by purging the cache.
These are the two different options I found easiest.
Only one of the options is necessary.
One way to do that is to simply create an empty file named .purgecaches
in the browser
directory.
For example, you can execute this:
touch /usr/lib/firefox/browser/.purgecaches
You’ll only need to create that file after running the above commands.
On startup, Firefox will clear its startup cache if it finds this file, and it will also attempt to remove the file.
Depending on how you originally installed Firefox, removing the file automatically may fail.
Even if that doesn’t affect successfully clearing the cache, just be aware of that.
An alternative way is to find the desktop configuration file for Firefox.
Look into /usr/share/applications/
or ~/.local/share/applications/
and find some *.desktop
file with firefox
(or nightly
or maybe mozilla
or something similar) in the file name.
Open the files you found.
On my system there are two of them:
- A small one that starts
firefox-bin
(via Exec=
)
- A large one that has three references to
/usr/lib/firefox/firefox
You want to modify the larger one: after each /usr/lib/firefox/firefox
(or whichever path it is for you) put the -purgecaches
option (--purgecaches
works, too); so one of the configuration entries may looke like this:
Exec=/usr/lib/firefox/firefox -purgecaches %u
Using this approach, you may need to edit your *.desktop
file after every Firefox update and it slows down every start-up of Firefox.
Now you can start Firefox by clicking on the desktop icon.
There are two other alternatives, if you don’t start Firefox from clicking on the desktop icon, but instead use the terminal:
- You can type
firefox -purgecaches
into the terminal,
- or you can type
export MOZ_PURGE_CACHES=1
into the terminal, then type firefox
into the same terminal.
And finally, you can clear the cache directly, as well.
The script caches, including the startup cache, are hidden in the .cache
directory of your /home
.
The path will look something like /home/⟨user⟩/.cache/mozilla/firefox/⟨profileID⟩.⟨profileType⟩/startupCache
.
Deleting these directories will clear the startup cache of Firefox.
Use this approach if you use more than one profile on the same Firefox installation.
The other built-in purgecaches
approaches only clear the cache of the first profile that gets used by Firefox.
Explanation
This is a variable storing the path of one of the relevant files.
Later, you need to check if this path exists, because Mozilla has renamed this file around release version 103.
urlbarinput_path=omni/modules/UrlbarInput.sys.mjs
# …
if [[ ! -f /tmp/$urlbarinput_path ]]; then
urlbarinput_path=omni/modules/UrlbarInput.jsm
fi
These lines unpack the omni.ja
file (a quasi PKZIP file) into the newly created /tmp/omni
directory using the unzip
utility (extra/unzip
6.0-14
)1.
cd /tmp
mkdir omni
unzip -d omni -q /usr/lib/firefox/browser/omni.ja
-d omni
just extracts the files from /usr/lib/firefox/browser/omni.ja
into the /tmp/omni
directory; -q
suppresses output (just a list of files being inflated and extracted).
unzip
will likely exit with status 2
and you’ll get a warning and an error like this when running the unzip
command:
warning [omni.ja]: 50008544 extra bytes at beginning or within zipfile (attempting to process anyway)
error [omni.ja]: reported length of central directory is -50008544 bytes too long (Atari STZip zipfile? J.H.Holm ZIPSPLIT 1.1 zipfile?). Compensating...
Don’t worry about it.
This doesn’t affect the process; status 2
just means that some error was detected, but “[p]rocessing may have completed successfully anyway”, as the man page says.
Next, these two lines edit the appropriate files in-place.
The _preventClickSelectsAll
property controls if selection happens on a single click. Setting it to true
will prevent this behavior. The first line addresses the URL bar, the second line addresses the search bar.
sed -i 's/this\._preventClickSelectsAll = this\.focused;/this._preventClickSelectsAll = true;/' $urlbarinput_path
sed -i 's/this\._preventClickSelectsAll = this\._textbox\.focused;/this._preventClickSelectsAll = true;/' omni/chrome/browser/content/browser/search/searchbar.js
This creates a new omni.ja
with the changed file using the zip
utility (extra/zip
3.0-9
)1.
cd omni
zip -0DXqr omni.ja *
cd ..
It’s important to target *
(every file) inside omni/
, not the omni/
directory itself; we don’t want to create an omni.ja
with omni
as the root directory.
Getting in and out of the directory with cd
also ensures the correct file hierarchy, otherwise, zip
would still include the additional omni
root directory in the archive.
As for the options, -0
sets the compression level to no compression and simply stores the files; -D
avoids creating entries in the zip archive for directories; -X
does not save extra file attributes; -q
, again, suppresses output; -r
ensures that files are added recursively in their correct directory paths.
These are the options recommended in the MDN documentation.
You may have seen an older revision (before I edited it) that uses -9
(-qr9XD
, exactly) instead of -0
, but this causes issues: for instance, the localization of the tooltips that display keyboard shortcuts fails to load within the developer tools.
The answer at Possible to modify hardcoded Firefox JavaScript Ctrl-Tab panel behavior? mentions that -0
is the zip
option that creates an omni.ja
file with a file size closer to the original file.
Incidentally, that’s the only option that avoids this weird localization issue.
I explain this in detail in this GitHub issue.
Next, the created omni.ja
is moved to the Firefox browser
directory (and it replaces the file; don’t directly use an existing omni.ja
as the zip
target, or else the files will be nested into the existing ZIP), the permissions can be set like the original file, and in the end you can remove the /tmp/omni
directory.
mv omni/omni.ja /usr/lib/firefox/browser/omni.ja
chown ⟨user⟩:⟨group⟩ /usr/lib/firefox/browser/omni.ja
rm -r omni
It turns out that the chown
command may not be strictly necessary, but it ensures that the new omni.ja
has the same owner as the original file.
Alternatively, if you copied the original file as a non-root user to a backup directory, you can use this:
chown --reference=⟨your_backup_directory⟩/omni.ja /usr/lib/firefox/browser/omni.ja
chmod --reference=⟨your_backup_directory⟩/omni.ja /usr/lib/firefox/browser/omni.ja
Of course, you can use another file, like /usr/lib/firefox/browser/crashreporter-override.ini
as a reference.
Restoring an omni.ja
backup in case something goes wrong
If Firefox doesn’t seem to be running correctly after this process, or not at all, this process didn’t work, unfortunately. You can restore your backup by a simple mv
like this (possibly as root):
mv ⟨your_backup_directory⟩/omni.ja ⟨your_firefox_browser_directory⟩/omni.ja
Remember to purge the caches once again.
If you didn’t create an omni.ja
before, you need to re-download Firefox and extract the package to find a replacement omni.ja
.
As an aside, the suggested workaround on Bugzilla has a zip --update
command. The full commands would be:
unzip -q /usr/lib/firefox/browser/omni.ja $urlbarinput_path chrome/browser/content/browser/search/searchbar.js -d omni
# Instead of
# unzip -q /usr/lib/firefox/browser/omni.ja -d omni
… and …
zip -qr9XDu /usr/lib/firefox/browser/omni.ja *
# Instead of
# zip -qr9XD omni.ja *
# mv omni/omni.ja /usr/lib/firefox/browser/omni.ja
# chown ⟨username⟩:users /usr/lib/firefox/browser/omni.ja
Unfortunately, even with the knowledge about zip
file hierarchy, I can’t get this to work — it would be nice, though, as it would speed up the process a bit.
Instead, I get an error like this when starting Firefox:
XML Parsing Error: undefined entity
Location: chrome://browser/content/browser.xhtml
Line Number 740, Column 15:
<toolbarbutton id="UITourTooltipClose" class="close-icon"
--------------^
I wonder if Mozilla automatically reports such errors even if I tampered with the build…
Related questions:
1: I haven’t tested all versions, but this should continue to work for later versions, most earlier versions, and it should work on all release channels of Firefox — after the behavior change of March 2020.