Changes

Jump to: navigation, search

Dive into Mozilla Modifying Firefox Lab

1,975 bytes added, 12:48, 16 March 2007
Success, and some bugs
[[Dive into Mozilla]] > [[Dive into Mozilla Day 5]] > Modifying Firefox Lab
 
=Introduction=
==Search 1 - finding a UI string==
We're looking for a unique string--"New Tab"==, --so we'll use [http://lxr.mozilla.org LXR's] '''Text Search''' feature. Here are the results you get when you search for "New Tab":
<blockquote>http://lxr.mozilla.org/seamonkey/search?string=New+Tab</blockquote>
Lots of results, many of which point to comments in the code. However, the first result looks interesting:
<blockquote>http://lxr.mozilla.org/seamonkey/source/toolkit/locales/en-US/chrome/global/tabbrowser.dtd#2</blockquote>
Here we see the DTD file describing the key/value pairs for the en-US localized strings. Mozilla uses this technique to allow localizers to translate strings in an application into many different languages without having to change hard-coded strings in the code (you can read more about localization, DTDs, and Entities [http://developer.mozilla.org/en/docs/XUL_Tutorial:Localization here])
Repeating the search with the '''newTab.label''' ENTITY value instead of the "New Tab" string makes a big difference--we have many fewer hits:
<blockquote>http://lxr.mozilla.org/seamonkey/search?string=newTab.label</blockquote>
Not surprisingly, the first result is the same DTD file (i.e., tabbrowser.dtd) we already found. The second result looks interesting, though:
<blockquote>http://lxr.mozilla.org/seamonkey/source/toolkit/content/widgets/tabbrowser.xml#80</blockquote>
Here we see the code to generate the pop-up context menu for a tab (i.e., what you get when you right-click on a tab in the browser):
<pre>
<xul:menuitem label="&newTab.label;" accesskey="&newTab.accesskey;" xbl:inherits="oncommand=onnewtab"/>
</pre>
Armed with this new information, we are even closer to finding the right spot to begin working. We've gone from UI string to XML ENTITY to function. All we have to do now is find that function:
<blockquote>http://lxr.mozilla.org/seamonkey/search?string=onnewtab</blockquote>
This returns many results for things we aren't interested in, including files rooted in /suite, /db, etc. Since we are interested in finding this behaviour in Firefox, we need to focus on the files rooted in '''/browser'''. One looks particularly interesting:
<blockquote>http://lxr.mozilla.org/seamonkey/source/browser/base/content/browser.xul#503</blockquote>
In this case, the tabbrowser widget has the onnewtab property set to another function, '''BrowserOpenTab();''' (i.e., Firefox seems to handle tab creation in a non-standard way, providing its own method instead of using the default). Since we want to find the definition of this function, we search for '''"function BrowserOpenTab("''', which returns two results:
<blockquote>http://lxr.mozilla.org/seamonkey/search?string=function+browseropentab%28</blockquote>
Again, we're interested in Firefox (i.e., browser) instead of SeaMonkey (i.e., suite), so we skip to the second result:
<blockquote>http://lxr.mozilla.org/seamonkey/source/browser/base/content/browser.js#1802</blockquote>
This shows us that we need to be looking for yet another function, '''loadOneTab()'''. Another search:
<blockquote>http://lxr.mozilla.org/seamonkey/search?string=loadonetab</blockquote>
The first result is not surprising, and we're back to the tabbrowser widget. The '''loadOneTab''' method calls another method to actually create and insert the new tab:
Since '''addTab''' is a method of '''this''' we can search within the current document (CTRL+F) to find the '''addTab''' method. Finally we've found the right spot!
<blockquote>http://lxr.mozilla.org/seamonkey/source/toolkit/content/widgets/tabbrowser.xml#1160</blockquote>
this.mTabContainer.appendChild(t);
}
I then repackage the toolkit.jar file(change ''objdir'' to your objdir name):
$ cd mozilla/''objdir''/toolkit/content
$ make
then run the browser to test (NOTE: ''minefield'' is my testing profile):
$ export XPCOM_DEBUG_BREAK=warn
$ ../../dist/bin/firefox.exe -p minefield --no-remote
}
==Success, and some bugs== After repackaging the toolkit.jar file and running the browser, I'm able to confirm that this last change has been successful. Opening a new tab now works in the way I originally described. I make a few more tests to insure that I haven't broken anything else, for example, what happens if I am on the last tab and not in the middle. This works, which makes me realize that using '''append()''' is probably not necessary at all, and I can safely shorten my code down to the following:  // Insert tab after current tab, not at end. var currentTabIndex = this.mTabContainer.selectedIndex; this.mTabContainer.insertBefore(t, this.mTabContainer.childNodes.item(currentTabIndex + 1)); This means that six lines of code become two, and with that reduction in number of lines, hopefully a reduction in new bugs I've added (NOTE: within reason, favour fewer rather than more lines of code). Speaking of bugs, a closer read of '''addTab''' (see [http://lxr.mozilla.org/seamonkey/source/toolkit/content/widgets/tabbrowser.xml#1219 line 1219]) would indicate that we've introduced a few with our new positioning code:  // wire up a progress listener for the new browser object. var position = '''this.mTabContainer.childNodes.length-1;''' var tabListener = this.mTabProgressListener(t, b, blank); ... this.mTabListeners[position] = tabListener; this.mTabFilters[position] = filter; ... t._tPos = position; This will break tab deletion, among other things, since the positions of newly created tabs will be wrong internally. Where the assumption before was that the newly created tab was at the end of the list, the new code breaks that. Therefore, we also need to update the value of '''position'''
After repackaging the toolkit.jar file and running // wire up a progress listener for the new browser, I'm able to confirm that this last change has been successfulobject. Opening a new tab now works in the way I originally described. var position = currentTabIndex + 1 I make a few more tests to insure that I haven't broken anything else (e.g., "what happens if I am on the last tab and not in the middle?")No other obvious defects are visible from our changes.
=Reflections=
Another trick worth trying when you're making lots of JavaScript changes like this is to add the following line to your .mozconfig file:
ac_add_options --enable-chrome-format=flat
This will cause the .jar files to be expanded so that you can edit the .xml/.js/.xul files in place and skip the repackaging step above (see http://www.mozilla.org/build/jar-packaging.html). If you also use the [http://ted.mielczarek.org/code/mozilla/extensiondev/index.html Extension Developer's extension] you can reload the chrome without restarting the browser.

Navigation menu