How to patch unwanted behavior out of firefox

One of the fundamental principles of firefox that led to its success was the fact that much of the browser was written in a high level and highly dynamic language, i.e., javascript with xml added for good measure. This is what permitted easy development of extensions - if the browser is already written in javascript, it is simple to expose hooks to extensions also written in javascript. Other browsers required extensions written in C or C++ which took orders more effort.

Even as firefox caters less to power users and more to "less technical" ones, sometimes with no options out of the box to restore power user-friendly behavior, the browser UI is still written in javascript and thus quite easy to change to work in the Right Way.

This essay will follow the path of a typical change that has no pref for it and thus must be done in source, but - because it is a UI change - can be done in javascript. It does not require recompiling firefox. Let's get started.

The change I want to make is to restore the old tab bar behavior when tabs are closed, where the remaining tabs expanded to fill the tab bar width. In current firefox releases the tabs do not expand immediately but only when the mouse cursor leaves the tab bar.

Generally speaking, there are 4 solution levels to such problems:

  1. The problem is common enough that there is a forum topic or stackoverflow question with the solution, which could be a user pref.
  2. The problem is not as common, but enough people care about it that there is a pref. Often the prefs can be found via a web search for approximate keywords.
  3. There is no pref, but the code responsible for the behavior in question is in javascript/xul. The code can be patched rather easily without recompiling the entire browser.
  4. There is no pref and the responsible code is in C or C++. Browser recompilation is required to fix it.

In any event, the first step is to run some web searches to see what the world knows about the problem at hand. My initial query was "firefox tab expand immediately" which found this which was not particularly helpful, and this essay which I wholeheartedly agree with, but still does not solve the problem at hand. Revising the search query to "firefox tab close expand" found this bug as result #5.

Here I should explain how firefox changes happen. Someone has an idea for a change. That person creates a bugzilla bug describing the change. The idea is either approved or rejected by whoever is in charge of the facility that the idea affects. If the idea is approved, someone else would write code for it. The code is attached to the bugzilla bug while it is being developed. Eventually the code is reviewed and accepted into the main tree. Subsequent releases of the browser have the new behavior.

In modern days (let's say, since firefox 2.0) much if not most of the discussions and decisions regarding whether a change should or should not be made happen behind closed doors. I'm guessing employees of mozilla, paid for the for-profit corporation, have meetings where they discuss these things. The code development may also happen in private. What remains public is the bug where at least there is a title for the change, maybe some sort of rationalization (sometimes the rationalization is entirely missing, and sometimes it simply says "that's what chrome does"), and the patch.

Now that we have found the ticket we can confirm that the description matches our general issue ("other tabs should not resize") and that the change is in the browser today (status is verified fixed). The next thing is to skim the entire bug to see if there is a pref to turn the behavior off. In this case, there is not a pref. We must change the code.

Under "attachments", there is a link to the most recent version of the patch. I will call this the original patch. I want to make my own patch, which I will call the nullifying patch, to negate the effects of the original patch. As such I look for big functions/methods that can be skipped by adding a "return" on top, or alternatively added calls to such functions and methods that can be commented out. I want to make as few changes as possible to future-proof the nullifying patch, because firefox development is ongoing and I want to avoid conflicts should the code added by the original patch be changed in a future firefox release.

The result is addition of three return statements in each of the three functions added by the original patch. Here is the nullifying patch.

Now that we have a patch, we need to apply it to our browser. Javascript and xml files are typically located in jar files, which are basically zip archives. There are a few ways of finding these files on your computer. A good starting point is locate command:

% locate jar |grep jar$

Since I use Debian GNU/Linux, my browser is called iceweasel rather than firefox, therefore my jar is located at /usr/share/iceweasel/browser/chrome/browser.jar.

Another option is to check files installed by firefox and related packages:

% dpkg -L iceweasel
% dpkg -L xulrunner-24.0

If on your system all of the browser's files are located in a single directory, which is notoriously not the case on Debian, you can grep the directory for the file name of the file you are trying to patch:

% grep -r tabbrowser.xml /path/to/firefox/install

Note that you should grep for the file name rather than file contents because the contents may be compressed whereas the file name will not be.

Assuming you have located the jar which contains the desired files, the rest is straightforward:

% mkdir /tmp/work
% cd /tmp/work
% unzip /usr/share/iceweasel/browser/chrome/browser.jar
% wget
% patch -p0 <firefox-24-resize-tabs-immediately-on-close.diff
% rm firefox-24-resize-tabs-immediately-on-close.diff
% zip -r browser.jar .
# cp /tmp/work/browser.jar /usr/share/iceweasel/browser/chrome/browser.jar

The last command needs to be run with superuser privileges, naturally.

Restart your firefox and enjoy a browser that is less annoying!