From MozillaWiki
Jump to: navigation, search

This is the top-level work page for the Tab Candy team.


Important Pages



Useful bug queries:

Also, quick search is your friend. There's an intro screen-cast to get you started, and a reference for all the codes you can use.

If you see a bug assigned to someone but with a status of "NEW" (as opposed to "ASSIGNED"), they're probably not actually working on it... feel free to grab it for yourself (and update the status of course).


Getting Started


There's a variety of useful info over at the MDC Developer Guide.

These instructions assume you're on a Mac; please update with info for other platforms as needed.

TabCandy is part of Firefox, so to build it you need to build Firefox. Use the basic instructions.

You can work with the mozilla-central branch, but we also have a tabcandy-central branch (though it's currently frozen): ssh://

Once you've done a full build, for future builds you can just package up the various pieces TabCandy needs. One approach is to make a shell script like so:

make -s -j8 -C obj-ff-dbg/browser/locales && make -s -j8 -C obj-ff-dbg/browser/themes && make -s -j8 -C obj-ff-dbg/browser/base && make -s -j8 -C obj-ff-dbg/browser/app
obj-ff-dbg/dist/ -no-remote -P tcc

This builds just the pieces needed (assuming your build directy is "obj-ff-dbg") and then launches the app (with a profile named "tcc").

Or, for those who didn't make a debug build the script would look like:

make -s -j8 -C objdir-ff-release/browser/locales && make -s -j8 -C objdir-ff-release/browser/themes && make -s -j8 -C objdir-ff-release/browser/base && make -s -j8 -C objdir-ff-release/browser/app
objdir-ff-release/dist/ -no-remote -P tcc

You'll need to do a full rebuild every time you pull new code from mozilla-central, though.

The html and javascript files are in browser/base/content/tabview. The images and CSS file are in browser/themes/<platform>/browser/tabview. The tests are in browser/base/content/test/tabview.


All of our JavaScript files get concatenated into a single tabcandy.js, so error line numbers don't line up with the original source files. You can, however, go to chrome://browser/content/tabview.js, hit "view source", and then command+L is "go to line".


Tabcandy test locations:

  • Our tests are located in browser/base/content/test/tabview with a small number in browser/base/content/test

Here are some tips on writing tests for Tab Candy:

  • Using setTimeout() to delay a finish() call is frowned upon. It covers up the underlying problem(s), and has a high potential of causing intermittent unit test failures.
  • To close a window, register an observer with the window watcher, as shown in the whenWindowObservesOnce() call in this attachment: and then call finish() once you've received a proper "domwindowclosed" notification for that window.

Here are some troubleshooting tips:

  • If your test spawns a window, you may notice that you get unexpected failures in the private browsing tests even if you properly clean it up. This is caused by unresolved closed windows in the session store. To remove this symptom from affecting later tests, use code such as that shown in this attachment: to clear the session store's record of closed windows before calling finish().


  • Force RTL - for testing "right to left" orientation on "left to right" (e.g. English) systems
  • Frame Rate Monitor - for analyzing animation speed
  • DOM Inspector - works even for chrome such as chrome://browser/content/tabview.html
  • Chromebug - Firebug for chrome

Mercurial Queues

Very handy for managing multiple patches in flight. Pop one on, work with it, pop it off again. See to get started.

Once you have it all set up and do that init dance, you need to create the patch you'll be working on. You can either do this by doing hg qnew <patchname> (actually, we recommend hg qnew -U -e <patchname>, which will give the patch your username and give you a chance to enter its commit message) or by importing a patch. To import, grab the patch and hg qimport <patchname>.

Either way, you then apply the patch with hg qpush <patchname>, at which point you have the patch applied, and you can make live edits.

To update the patch do hg qrefresh. Edit, refresh, edit, refresh, etc.

To update the patch's commit message, do hg qref -e (which will open your editor).

When done, do hg qrefresh and then hg qpop. Now the patch is no longer being worked on. Grab the patch from .hg/patches/<patchname>.


Also see How to Submit a Patch on MDC.

  1. Create a bug in bugzilla describing what your patch will do/fix, or use an existing bug if appropriate
  2. If the patch fixes a bug or adds a feature (rather than, say, code clean-up, string changes, style changes, etc), it should have a unit test.
  3. Regardless of whether you're adding a test, try all the browser chrome tests locally: make -C <objdir> mochitest-browser-chrome
  4. Attach your patch to the bug and assign it for feedback from one of the Panorama team (mitcho, raymondlee, seandunn)
  5. Once you've got f+, mark it r? for review (generally to iangilman, but other potentials include dao, dietrich, dolske, gavin; ask in #tabcandy if you're not sure who to assign it to)
  6. Push your patch to tryserver to make sure it doesn't break anything:
    1. Update your m-c local repo
    2. Apply the patch you would want to push to mozilla-central
    3. hg push -f ssh://
    4. Check the results at:
    5. Add a comment to the bug in question with a link to your try run like so:
  7. Once they've given you an r+, you'll need approval (unless it's already marked as a blocker, which means it's already approved for landing, or if it's a test fix):
    1. Mark it with a question mark under "approval 2.0", if the reviewer hasn't already done so
    2. If it's a rush, poke someone to do the approval 2.0 (beltzner, johnath, dietrich, gavin, dolske are good candidates, or ask in #tabcandy if unsure who)
  8. Once you've got your approval, make a fresh patch with the commit message giving the bug number and title (if you haven't already done that), and updated with "r=foo a=bar"
  9. Mark the bug for checkin, by adding the keyword "checkin-needed" to it.
  10. If it's urgent, poke someone who can land it, such as iangilman or ehsan

Also, make sure to read

Reading the tinderbox tea leaves

Once you've pushed to a repo that builds (such as mozilla-central or try), go to the tinderbox pushlog (here are the links for mozilla-central and try). Shortly your push should show up. Watch the letters to the right of your push for signs of danger.

  • Gray means it hasn't run yet
  • Green means it's good
  • Red is for broken builds
  • Orange is for tests that fail

When you get an orange, you need to determine if it's your fault, or if it's a known intermittent failure. The first thing to do is click on the orange letter; it'll bring up a bank of info at the bottom of the window, along with a blue panel listing potential bug matches. If you see an open bug that looks like a likely match, you're good. If this is on mozilla-central, hit the "add a comment" link in the lower-left to star it. Note that if the matching bug is not suggested, you can just type in the word "bug" and the bug number in the "comment" dialog, but please then also add the url to the log into the bug.

If this looks like a new issue, try the "view brief log" or "view full log" links in the lower left for clues. The failure should be listed at the top, and additional useful information may be found at the very bottom prefixed by "TinderboxPrint:". If you still don't think it's your bug, try searching bugzilla for a match. If no luck, try asking around on IRC.

Merging mozilla-central to tabcandy-central

  1. Find a stable build at (no reds, no unstarred oranges, no gray Bs), and grab its revision number
  2. Make sure your local tabcandy-central repo is up to date and there's no outgoing changes pending or uncommitted work
  3. hg pull -r <revision> ssh://
  4. hg merge
  5. Fix conflicts if there are any (once you've fixed them, you can use hg resolve -ma to mark them all as resolved)
  6. hg ci -m 'Merge mozilla-central to tabcandy-central.'
  7. hg push

Also, don't forget to rebuild minefield with all the new code to make sure nothing's broken. Whether you do this before or after pushing is up to your sense of risk. :)

Committing to mozilla-central

Also see Committing Rules and Responsibilities on MDC as well as Tree Rules.

You'll need level 3 access and a patch that's ready to go (see the section on Landing, above). These instructions assume you're using Mercurial Queues.

  1. Take a look at the tree to make sure the coast is clear
  2. Check in with the sheriff on duty (you can find them on the user list for #developers on IRC)
  3. In bugzilla, grab the URL patch you want to apply (e.g.
  4. In the terminal, go to your local repository and make sure you don't have any unpushed changes
  5. hg qimport <patch url> && hg qpush
  6. hg pull -u --rebase
  7. Take care of merge conflicts if needed
  8. Make sure the patch has the correct commit message including bug number, bug title, and reviewers. hg qrefresh -e
  9. Make sure the patch has the correct username. hg qrefresh -u 'User Name <>'
  10. hg qfinish -a
  11. hg outgoing to make sure everything looks cool
  12. hg push
  13. Update the bug with a link to the change (e.g., and resolve it as fixed.
  14. Watch the tree to make sure you didn't burn it down!

Code Documentation

You can find the documentation here.

We're using Natural Docs. There's a shell script (only tested on Mac) that runs Natural Docs on our code and converts the comments in the JavaScript to HTML docs. It'll generate a folder, naturaldocs-data, that'll be ignored by hg; you should ignore it too... it's just cache for the script.

Even though the TabCandy code is now in the tabcandy-central branch, we're still keeping the documentation in the old tabcandy branch. The docs script,, assumes your tabcandy-central folder is next to your tabcandy folder.

Z-Index Map

  • -999999: background gradient
  • -103 to -101: trenches
  • -99 to -1: Phantom groups (from dragging on the background, or stacking tabs on each other)
  • 0 to 99996: groups and tabs. Each time a group or orphan tab is dragged, its z-index is incremented 1. All of a group's children tabs are indexed in order above the group.
  • 99997 to 99999: expanded stack shield, tray, tabs
  • 999999: "front" for zoom and drag
  • 1000000: Action buttons (search, exit)
  • 1000001: Search shade
  • 1000010: search result tabs
  • 1000050: Search entry box

Style Guide

  • Use spaces, not tabs, with two spaces per "tab stop".
  • 80 character line length limit.
  • Prefer native methods over libraries where appropriate. For instance, use Array.forEach() rather than iQ.each() (note that for each( has issues and should generally be avoided).
  • Assert text should be written in terms of what should happen rather than what did or did not happen, e.g. Utils.assert(a == 2, "a should be equal to 2"). This way it's clear both when reading the code and when reading the console/log.

Do No Harm

In terms of breakage, we should rank them in the following scale, based on the principle of "do no harm":

  1. Anything that breaks the experience for people who never enter Panorama mode (i.e., start with a fresh profile and use the browser normally, never once entering the Panorama UI (or even triggering Panorama, such as happens when you pull up the right-click menu on a tab in the tab strip)). We should be good here, since in this scenario Panorama just lays dormant, but of course we need to verify.
  2. Anything that breaks if you enter Panorama but then exit immediately and otherwise continue to use the browser normally. In this scenario, the browser should behave as it always has, even though Panorama is in the background watching things. Again for testing this should start with a fresh profile (or at least kill your sessionstore). Also note that you need to initialize Panorama once per session.
  3. Anything that breaks if you use Panorama extensively, but with only one window open in your browser.
  4. Anything that breaks if you use Panorama with multiple windows open.

Sub-scenarios in the bottom three categories include starting Panorama right at the beginning of your session versus using the browser for a while and then starting Panorama.

Within this hierarchy of course we have the usual prioritization from data loss at the top, down to annoyance at the bottom.

Please use this hierarchy to guide your testing and bug fixing.