Splitting Appstartup from Appshell
Implementation Details

This document is meant to accompany the patch in bug 237745. It is an explanation of the changes in that patch (which look massive, but are fairly controlled).

The design goal was to allow firefox to continue development without forcing massive changes in the existing seamonkey codebase and startup sequence.

The major change in the patch splits nsIAppShellService into two pieces: nsIAppShellService remains in appshell (gecko/tier-9), and handles window-opening and hidden-window tasks; nsIAppStartup lives in xpfe/components (toolkit-specific/tier-50) and handles running the event loop and quitting.

Original nsIAppShellService
new nsIAppShellService
nsIAppStartup
void initialize(in nsICmdLineService aCmdLineService,
                in nsISupports nativeAppSupportOrSplashScreen);

void initialize(in nsICmdLineService aCmdLineService,
                in nsISupports nativeAppSupportOrSplashScreen);
void doProfileStartup(in nsICmdLineService aCmdLineService, in boolean canInteract);

void doProfileStartup(in nsICmdLineService aCmdLineService, in boolean canInteract);
readonly attribute nsINativeAppSupport nativeAppSupport;

readonly attribute nsINativeAppSupport nativeAppSupport;
void run();

void run();
void quit(in PRUint32 aFerocity);

void quit(in PRUint32 aFerocity);
nsIXULWindow createTopLevelWindow(in nsIXULWindow aParent,
                                  in nsIURI aUrl,
                                  in boolean aShowWindow,
                                  in boolean aLoadDefaultPage,
                                  in PRUint32 aChromeMask,
                                  in long aInitialWidth,
                                  in long aInitialHeight);
nsIXULWindow createTopLevelWindow(in nsIXULWindow aParent,
                                  in nsIURI aUrl,
                                  in boolean aShowWindow,
                                  in boolean aLoadDefaultPage,
                                  in PRUint32 aChromeMask,
                                  in long aInitialWidth,
in nsIAppShell aAppShell,
                                  in long aInitialHeight);

void closeTopLevelWindow(in nsIXULWindow aWindow);
void closeTopLevelWindow(in nsIXULWindow aWindow);

void createHiddenWindow();
void createHiddenWindow(in nsIAppShell aAppShell);

readonly attribute nsIXULWindow hiddenWindow;
readonly attribute nsIXULWindow hiddenWindow;

readonly attribute nsIDOMWindowInternal hiddenDOMWindow;
readonly attribute nsIDOMWindowInternal hiddenDOMWindow;

void getHiddenWindowAndJSContext(out nsIDOMWindowInternal aHiddenDOMWindow,
                                 out JSContext aJSContext);
void getHiddenWindowAndJSContext(out nsIDOMWindowInternal aHiddenDOMWindow,
                                 out JSContext aJSContext);

void registerTopLevelWindow(in nsIXULWindow aWindow);
void registerTopLevelWindow(in nsIXULWindow aWindow);

void unregisterTopLevelWindow(in nsIXULWindow aWindow);
void unregisterTopLevelWindow(in nsIXULWindow aWindow);

void topLevelWindowIsModal(in nsIXULWindow aWindow, in boolean aModal);
void topLevelWindowIsModal(in nsIXULWindow aWindow, in boolean aModal);

void hideSplashScreen();

void hideSplashScreen();
void enterLastWindowClosingSurvivalArea();

void enterLastWindowClosingSurvivalArea();
void exitLastWindowClosingSurvivalArea();

void exitLastWindowClosingSurvivalArea();
boolean createStartupState(in long aWindowWidth, in long aWindowHeight);

boolean createStartupState(in long aWindowWidth, in long aWindowHeight);
void ensure1Window(in nsICmdLineService aCmdLineService);

void ensure1Window(in nsICmdLineService aCmdLineService);

The new nsIAppShell parameter to createTopLevelWindow and createHiddenWindow are an artifact of the appstartup separation... nsAppStartup holds onto the primordial nsIAppShell as mAppShell, and passes it to nsIAppShellService when needed.

The following interfaces, and their implementations move from appshell to appstartup. They have been moved unchanged (or changed only to use the appstartup interface):

In my patch these files have been CVS removed and CVS added. Before actually landing, they should be moved in the CVS repository, to preserve CVS log/blame.

These interfaces need to move because the new toolkit intends to fork them imminently; they are tied to the seamonkey startup process, which is being revampled. The command-line handler interface is currently not powerful enough to handle the needs of thunderbird, requiring bad #ifdefs in the appshell code. Native app support has lots of code to handle quicklaunch and profile-selection, which is moot in the new toolkit.

The appleevents code, which was previously linked into appshell, are now linked into the appstartup code (appcomps component shared-lib). No changes were made to this code, except that nsAppleEvents.h was moved to the xpfe/bootstrap/appleevents directory to preserve the build order.

The XPFE nsIWindowCreator implementation, which previously was linked into the mozilla binary as nsWindowCreator, was integrated with nsAppStartup. This was a pure code-copying exercise, no substantive changes were made. This was necessary so that nsAppStartup can pass its mAppShell member to the window-creator functions.

The profile code moves from gecko (tier 9) to the toolkit (tier 50). The new toolkit is going to a semi-single-profile setup.

Because the code in editor/composer is part of gecko (midas), I rewrote the composer command-line handling component (nsEditorService) as a little JS component, which is only built when mozilla composer is built. NOTE: I probably need to copy this for NVU/standalone composer. This was necessary so that gecko components (midas) would not depend on non-gecko interfaces (nsICmdLineHandler).

The remaining changes in this patch are all updates from the appshell->appstartup interface, or changes to the build system so that files are built in the proper order and tier.

--BDS