bug 313956: expand installer .exe contents to make complete mar. r=ted.
[gecko.git] / toolkit / xre / nsEmbedFunctions.cpp
blob53ec37fe3f448a7ebea1342c02c4700b5e0def51
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is Mozilla libXUL embedding.
16 * The Initial Developer of the Original Code is
17 * Benjamin Smedberg <benjamin@smedbergs.us>
19 * Portions created by the Initial Developer are Copyright (C) 2005
20 * the Mozilla Foundation. All Rights Reserved.
22 * Contributor(s):
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 #if defined(MOZ_WIDGET_QT)
39 #include "nsQAppInstance.h"
40 #endif
42 #ifdef MOZ_IPC
43 #include "base/basictypes.h"
44 #endif
46 #include "nsXULAppAPI.h"
48 #include <stdlib.h>
49 #if defined(MOZ_WIDGET_GTK2)
50 #include <glib.h>
51 #endif
53 #include "prenv.h"
55 #include "nsIAppShell.h"
56 #include "nsIAppStartupNotifier.h"
57 #include "nsIDirectoryService.h"
58 #include "nsILocalFile.h"
59 #include "nsIToolkitChromeRegistry.h"
60 #include "nsIToolkitProfile.h"
62 #if defined(OS_LINUX)
63 # define XP_LINUX
64 #endif
66 #ifdef XP_WIN
67 #include <process.h>
68 #endif
70 #include "nsAppDirectoryServiceDefs.h"
71 #include "nsAppRunner.h"
72 #include "nsAutoRef.h"
73 #include "nsDirectoryServiceDefs.h"
74 #include "nsExceptionHandler.h"
75 #include "nsString.h"
76 #include "nsThreadUtils.h"
77 #include "nsJSUtils.h"
78 #include "nsWidgetsCID.h"
79 #include "nsXREDirProvider.h"
81 #include "mozilla/Omnijar.h"
82 #ifdef MOZ_IPC
83 #if defined(XP_MACOSX)
84 #include "chrome/common/mach_ipc_mac.h"
85 #endif
86 #include "nsX11ErrorHandler.h"
87 #include "base/at_exit.h"
88 #include "base/command_line.h"
89 #include "base/message_loop.h"
90 #include "base/process_util.h"
91 #include "chrome/common/child_process.h"
92 #include "chrome/common/notification_service.h"
94 #include "mozilla/ipc/BrowserProcessSubThread.h"
95 #include "mozilla/ipc/GeckoChildProcessHost.h"
96 #include "mozilla/ipc/IOThreadChild.h"
97 #include "mozilla/ipc/ProcessChild.h"
98 #include "ScopedXREEmbed.h"
100 #include "mozilla/jetpack/JetpackProcessChild.h"
101 #include "mozilla/plugins/PluginProcessChild.h"
102 #include "mozilla/dom/ContentProcess.h"
103 #include "mozilla/dom/ContentParent.h"
104 #include "mozilla/dom/ContentChild.h"
106 #include "mozilla/jsipc/ContextWrapperParent.h"
108 #include "mozilla/ipc/TestShellParent.h"
109 #include "mozilla/ipc/XPCShellEnvironment.h"
111 #ifdef MOZ_IPDL_TESTS
112 #include "mozilla/_ipdltest/IPDLUnitTests.h"
113 #include "mozilla/_ipdltest/IPDLUnitTestProcessChild.h"
115 using mozilla::_ipdltest::IPDLUnitTestProcessChild;
116 #endif // ifdef MOZ_IPDL_TESTS
118 using mozilla::ipc::BrowserProcessSubThread;
119 using mozilla::ipc::GeckoChildProcessHost;
120 using mozilla::ipc::IOThreadChild;
121 using mozilla::ipc::ProcessChild;
122 using mozilla::ipc::ScopedXREEmbed;
124 using mozilla::jetpack::JetpackProcessChild;
125 using mozilla::plugins::PluginProcessChild;
126 using mozilla::dom::ContentProcess;
127 using mozilla::dom::ContentParent;
128 using mozilla::dom::ContentChild;
130 using mozilla::jsipc::PContextWrapperParent;
131 using mozilla::jsipc::ContextWrapperParent;
133 using mozilla::ipc::TestShellParent;
134 using mozilla::ipc::TestShellCommandParent;
135 using mozilla::ipc::XPCShellEnvironment;
137 using mozilla::startup::sChildProcessType;
138 #endif
140 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
142 #ifdef XP_WIN
143 static const PRUnichar kShellLibraryName[] = L"shell32.dll";
144 #endif
146 nsresult
147 XRE_LockProfileDirectory(nsILocalFile* aDirectory,
148 nsISupports* *aLockObject)
150 nsCOMPtr<nsIProfileLock> lock;
152 nsresult rv = NS_LockProfilePath(aDirectory, nsnull, nsnull,
153 getter_AddRefs(lock));
154 if (NS_SUCCEEDED(rv))
155 NS_ADDREF(*aLockObject = lock);
157 return rv;
160 static PRInt32 sInitCounter;
162 nsresult
163 XRE_InitEmbedding2(nsILocalFile *aLibXULDirectory,
164 nsILocalFile *aAppDirectory,
165 nsIDirectoryServiceProvider *aAppDirProvider)
167 // Initialize some globals to make nsXREDirProvider happy
168 static char* kNullCommandLine[] = { nsnull };
169 gArgv = kNullCommandLine;
170 gArgc = 0;
172 NS_ENSURE_ARG(aLibXULDirectory);
174 if (++sInitCounter > 1) // XXXbsmedberg is this really the right solution?
175 return NS_OK;
177 if (!aAppDirectory)
178 aAppDirectory = aLibXULDirectory;
180 nsresult rv;
182 new nsXREDirProvider; // This sets gDirServiceProvider
183 if (!gDirServiceProvider)
184 return NS_ERROR_OUT_OF_MEMORY;
186 rv = gDirServiceProvider->Initialize(aAppDirectory, aLibXULDirectory,
187 aAppDirProvider);
188 if (NS_FAILED(rv))
189 return rv;
191 rv = NS_InitXPCOM2(nsnull, aAppDirectory, gDirServiceProvider);
192 if (NS_FAILED(rv))
193 return rv;
195 // We do not need to autoregister components here. The CheckCompatibility()
196 // bits in nsAppRunner.cpp check for an invalidation flag in
197 // compatibility.ini.
198 // If the app wants to autoregister every time (for instance, if it's debug),
199 // it can do so after we return from this function.
201 nsCOMPtr<nsIObserver> startupNotifier
202 (do_CreateInstance(NS_APPSTARTUPNOTIFIER_CONTRACTID));
203 if (!startupNotifier)
204 return NS_ERROR_FAILURE;
206 startupNotifier->Observe(nsnull, APPSTARTUP_TOPIC, nsnull);
208 return NS_OK;
211 void
212 XRE_NotifyProfile()
214 NS_ASSERTION(gDirServiceProvider, "XRE_InitEmbedding was not called!");
215 gDirServiceProvider->DoStartup();
218 void
219 XRE_TermEmbedding()
221 if (--sInitCounter != 0)
222 return;
224 NS_ASSERTION(gDirServiceProvider,
225 "XRE_TermEmbedding without XRE_InitEmbedding");
227 gDirServiceProvider->DoShutdown();
228 NS_ShutdownXPCOM(nsnull);
229 delete gDirServiceProvider;
232 const char*
233 XRE_ChildProcessTypeToString(GeckoProcessType aProcessType)
235 return (aProcessType < GeckoProcessType_End) ?
236 kGeckoProcessTypeString[aProcessType] : nsnull;
239 GeckoProcessType
240 XRE_StringToChildProcessType(const char* aProcessTypeString)
242 for (int i = 0;
243 i < (int) NS_ARRAY_LENGTH(kGeckoProcessTypeString);
244 ++i) {
245 if (!strcmp(kGeckoProcessTypeString[i], aProcessTypeString)) {
246 return static_cast<GeckoProcessType>(i);
249 return GeckoProcessType_Invalid;
252 #ifdef MOZ_IPC
253 namespace mozilla {
254 namespace startup {
255 GeckoProcessType sChildProcessType = GeckoProcessType_Default;
259 #if defined(MOZ_CRASHREPORTER)
260 // FIXME/bug 539522: this out-of-place function is stuck here because
261 // IPDL wants access to this crashreporter interface, and
262 // crashreporter is built in such a way to make that awkward
263 PRBool
264 XRE_TakeMinidumpForChild(PRUint32 aChildPid, nsILocalFile** aDump)
266 return CrashReporter::TakeMinidumpForChild(aChildPid, aDump);
269 PRBool
270 XRE_SetRemoteExceptionHandler(const char* aPipe/*= 0*/)
272 #if defined(XP_WIN) || defined(XP_MACOSX)
273 return CrashReporter::SetRemoteExceptionHandler(nsDependentCString(aPipe));
274 #elif defined(OS_LINUX)
275 return CrashReporter::SetRemoteExceptionHandler();
276 #else
277 # error "OOP crash reporter unsupported on this platform"
278 #endif
280 #endif // if defined(MOZ_CRASHREPORTER)
282 #if defined(XP_WIN)
283 void
284 SetTaskbarGroupId(const nsString& aId)
286 typedef HRESULT (WINAPI * SetCurrentProcessExplicitAppUserModelIDPtr)(PCWSTR AppID);
288 SetCurrentProcessExplicitAppUserModelIDPtr funcAppUserModelID = nsnull;
290 HMODULE hDLL = ::LoadLibraryW(kShellLibraryName);
292 funcAppUserModelID = (SetCurrentProcessExplicitAppUserModelIDPtr)
293 GetProcAddress(hDLL, "SetCurrentProcessExplicitAppUserModelID");
295 if (!funcAppUserModelID) {
296 ::FreeLibrary(hDLL);
297 return;
300 if (FAILED(funcAppUserModelID(aId.get()))) {
301 NS_WARNING("SetCurrentProcessExplicitAppUserModelID failed for child process.");
304 if (hDLL)
305 ::FreeLibrary(hDLL);
307 #endif
309 nsresult
310 XRE_InitChildProcess(int aArgc,
311 char* aArgv[],
312 GeckoProcessType aProcess)
314 NS_ENSURE_ARG_MIN(aArgc, 2);
315 NS_ENSURE_ARG_POINTER(aArgv);
316 NS_ENSURE_ARG_POINTER(aArgv[0]);
318 sChildProcessType = aProcess;
320 // Complete 'task_t' exchange for Mac OS X. This structure has the same size
321 // regardless of architecture so we don't have any cross-arch issues here.
322 #ifdef XP_MACOSX
323 if (aArgc < 1)
324 return 1;
325 const char* const mach_port_name = aArgv[--aArgc];
327 const int kTimeoutMs = 1000;
329 MachSendMessage child_message(0);
330 if (!child_message.AddDescriptor(mach_task_self())) {
331 NS_WARNING("child AddDescriptor(mach_task_self()) failed.");
332 return 1;
335 ReceivePort child_recv_port;
336 mach_port_t raw_child_recv_port = child_recv_port.GetPort();
337 if (!child_message.AddDescriptor(raw_child_recv_port)) {
338 NS_WARNING("Adding descriptor to message failed");
339 return 1;
342 MachPortSender child_sender(mach_port_name);
343 kern_return_t err = child_sender.SendMessage(child_message, kTimeoutMs);
344 if (err != KERN_SUCCESS) {
345 NS_WARNING("child SendMessage() failed");
346 return 1;
349 MachReceiveMessage parent_message;
350 err = child_recv_port.WaitForMessage(&parent_message, kTimeoutMs);
351 if (err != KERN_SUCCESS) {
352 NS_WARNING("child WaitForMessage() failed");
353 return 1;
356 if (parent_message.GetTranslatedPort(0) == MACH_PORT_NULL) {
357 NS_WARNING("child GetTranslatedPort(0) failed");
358 return 1;
360 err = task_set_bootstrap_port(mach_task_self(),
361 parent_message.GetTranslatedPort(0));
362 if (err != KERN_SUCCESS) {
363 NS_WARNING("child task_set_bootstrap_port() failed");
364 return 1;
366 #endif
368 #if defined(MOZ_CRASHREPORTER)
369 if (aArgc < 1)
370 return 1;
371 const char* const crashReporterArg = aArgv[--aArgc];
373 # if defined(XP_WIN) || defined(XP_MACOSX)
374 // on windows and mac, |crashReporterArg| is the named pipe on which the
375 // server is listening for requests, or "-" if crash reporting is
376 // disabled.
377 if (0 != strcmp("-", crashReporterArg)
378 && !XRE_SetRemoteExceptionHandler(crashReporterArg))
379 return 1;
380 # elif defined(OS_LINUX)
381 // on POSIX, |crashReporterArg| is "true" if crash reporting is
382 // enabled, false otherwise
383 if (0 != strcmp("false", crashReporterArg)
384 && !XRE_SetRemoteExceptionHandler(NULL))
385 return 1;
386 # else
387 # error "OOP crash reporting unsupported on this platform"
388 # endif
389 #endif // if defined(MOZ_CRASHREPORTER)
391 gArgv = aArgv;
392 gArgc = aArgc;
394 SetupErrorHandling(aArgv[0]);
396 #if defined(MOZ_WIDGET_GTK2)
397 g_thread_init(NULL);
398 #endif
400 #if defined(MOZ_WIDGET_QT)
401 nsQAppInstance::AddRef();
402 #endif
404 if (PR_GetEnv("MOZ_DEBUG_CHILD_PROCESS")) {
405 #ifdef OS_POSIX
406 printf("\n\nCHILDCHILDCHILDCHILD\n debug me @%d\n\n", getpid());
407 sleep(30);
408 #elif defined(OS_WIN)
409 printf("\n\nCHILDCHILDCHILDCHILD\n debug me @%d\n\n", _getpid());
410 Sleep(30000);
411 #endif
414 // child processes launched by GeckoChildProcessHost get this magic
415 // argument appended to their command lines
416 const char* const parentPIDString = aArgv[aArgc-1];
417 NS_ABORT_IF_FALSE(parentPIDString, "NULL parent PID");
418 --aArgc;
420 char* end = 0;
421 base::ProcessId parentPID = strtol(parentPIDString, &end, 10);
422 NS_ABORT_IF_FALSE(!*end, "invalid parent PID");
424 base::ProcessHandle parentHandle;
425 bool ok = base::OpenProcessHandle(parentPID, &parentHandle);
426 NS_ABORT_IF_FALSE(ok, "can't open handle to parent");
428 #if defined(XP_WIN)
429 // On Win7+, register the application user model id passed in by
430 // parent. This insures windows created by the container properly
431 // group with the parent app on the Win7 taskbar.
432 const char* const appModelUserId = aArgv[aArgc-1];
433 --aArgc;
434 if (appModelUserId) {
435 // '-' implies no support
436 if (*appModelUserId != '-') {
437 nsString appId;
438 appId.AssignWithConversion(nsDependentCString(appModelUserId));
439 // The version string is encased in quotes
440 appId.Trim(NS_LITERAL_CSTRING("\"").get());
441 // Set the id
442 SetTaskbarGroupId(appId);
445 #endif
447 base::AtExitManager exitManager;
448 NotificationService notificationService;
450 NS_LogInit();
452 int rv = XRE_InitCommandLine(aArgc, aArgv);
453 if (NS_FAILED(rv)) {
454 NS_LogTerm();
455 return NS_ERROR_FAILURE;
458 MessageLoop::Type uiLoopType;
459 switch (aProcess) {
460 case GeckoProcessType_Content:
461 // Content processes need the XPCOM/chromium frankenventloop
462 uiLoopType = MessageLoop::TYPE_MOZILLA_CHILD;
463 break;
464 default:
465 uiLoopType = MessageLoop::TYPE_UI;
466 break;
470 // This is a lexical scope for the MessageLoop below. We want it
471 // to go out of scope before NS_LogTerm() so that we don't get
472 // spurious warnings about XPCOM objects being destroyed from a
473 // static context.
475 // Associate this thread with a UI MessageLoop
476 MessageLoop uiMessageLoop(uiLoopType);
478 nsAutoPtr<ProcessChild> process;
480 switch (aProcess) {
481 case GeckoProcessType_Default:
482 NS_RUNTIMEABORT("This makes no sense");
483 break;
485 case GeckoProcessType_Plugin:
486 process = new PluginProcessChild(parentHandle);
487 break;
489 case GeckoProcessType_Content:
490 process = new ContentProcess(parentHandle);
491 break;
493 case GeckoProcessType_Jetpack:
494 process = new JetpackProcessChild(parentHandle);
495 break;
497 case GeckoProcessType_IPDLUnitTest:
498 #ifdef MOZ_IPDL_TESTS
499 process = new IPDLUnitTestProcessChild(parentHandle);
500 #else
501 NS_RUNTIMEABORT("rebuild with --enable-ipdl-tests");
502 #endif
503 break;
505 default:
506 NS_RUNTIMEABORT("Unknown main thread class");
509 if (!process->Init()) {
510 NS_LogTerm();
511 return NS_ERROR_FAILURE;
514 // Run the UI event loop on the main thread.
515 uiMessageLoop.MessageLoop::Run();
517 // Allow ProcessChild to clean up after itself before going out of
518 // scope and being deleted
519 process->CleanUp();
520 #ifdef MOZ_OMNIJAR
521 mozilla::SetOmnijar(nsnull);
522 #endif
526 NS_LogTerm();
527 return XRE_DeinitCommandLine();
530 MessageLoop*
531 XRE_GetIOMessageLoop()
533 if (sChildProcessType == GeckoProcessType_Default) {
534 return BrowserProcessSubThread::GetMessageLoop(BrowserProcessSubThread::IO);
536 return IOThreadChild::message_loop();
539 namespace {
541 class MainFunctionRunnable : public nsRunnable
543 public:
544 NS_DECL_NSIRUNNABLE
546 MainFunctionRunnable(MainFunction aFunction,
547 void* aData)
548 : mFunction(aFunction),
549 mData(aData)
551 NS_ASSERTION(aFunction, "Don't give me a null pointer!");
554 private:
555 MainFunction mFunction;
556 void* mData;
559 } /* anonymous namespace */
561 NS_IMETHODIMP
562 MainFunctionRunnable::Run()
564 mFunction(mData);
565 return NS_OK;
568 nsresult
569 XRE_InitParentProcess(int aArgc,
570 char* aArgv[],
571 MainFunction aMainFunction,
572 void* aMainFunctionData)
574 NS_ENSURE_ARG_MIN(aArgc, 1);
575 NS_ENSURE_ARG_POINTER(aArgv);
576 NS_ENSURE_ARG_POINTER(aArgv[0]);
578 gArgc = aArgc;
579 gArgv = aArgv;
580 int rv = XRE_InitCommandLine(gArgc, gArgv);
581 if (NS_FAILED(rv))
582 return NS_ERROR_FAILURE;
584 ScopedXREEmbed embed;
587 embed.Start();
589 nsCOMPtr<nsIAppShell> appShell(do_GetService(kAppShellCID));
590 NS_ENSURE_TRUE(appShell, NS_ERROR_FAILURE);
592 if (aMainFunction) {
593 nsCOMPtr<nsIRunnable> runnable =
594 new MainFunctionRunnable(aMainFunction, aMainFunctionData);
595 NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
597 nsresult rv = NS_DispatchToCurrentThread(runnable);
598 NS_ENSURE_SUCCESS(rv, rv);
601 // Do event loop
602 if (NS_FAILED(appShell->Run())) {
603 NS_WARNING("Failed to run appshell");
604 return NS_ERROR_FAILURE;
608 return XRE_DeinitCommandLine();
611 #ifdef MOZ_IPDL_TESTS
612 //-----------------------------------------------------------------------------
613 // IPDL unit test
616 XRE_RunIPDLTest(int aArgc, char** aArgv)
618 if (aArgc < 2) {
619 fprintf(stderr, "TEST-UNEXPECTED-FAIL | <---> | insufficient #args, need at least 2\n");
620 return 1;
623 void* data = reinterpret_cast<void*>(aArgv[aArgc-1]);
625 nsresult rv =
626 XRE_InitParentProcess(
627 --aArgc, aArgv, mozilla::_ipdltest::IPDLUnitTestMain, data);
628 NS_ENSURE_SUCCESS(rv, 1);
630 return 0;
632 #endif // ifdef MOZ_IPDL_TESTS
634 nsresult
635 XRE_RunAppShell()
637 nsCOMPtr<nsIAppShell> appShell(do_GetService(kAppShellCID));
638 #if defined(XP_MACOSX)
640 // In content processes that want XPCOM (and hence want
641 // AppShell), we usually run our hybrid event loop through
642 // MessagePump::Run(), by way of nsBaseAppShell::Run(). The
643 // Cocoa nsAppShell impl, however, implements its own Run()
644 // that's unaware of MessagePump. That's all rather suboptimal,
645 // but oddly enough not a problem... usually.
647 // The problem with this setup comes during startup.
648 // XPCOM-in-subprocesses depends on IPC, e.g. to init the pref
649 // service, so we have to init IPC first. But, IPC also
650 // indirectly kinda-depends on XPCOM, because MessagePump
651 // schedules work from off-main threads (e.g. IO thread) by
652 // using NS_DispatchToMainThread(). If the IO thread receives a
653 // Message from the parent before nsThreadManager is
654 // initialized, then DispatchToMainThread() will fail, although
655 // MessagePump will remember the task. This race condition
656 // isn't a problem when appShell->Run() ends up in
657 // MessagePump::Run(), because MessagePump will immediate see it
658 // has work to do. It *is* a problem when we end up in [NSApp
659 // run], because it's not aware that MessagePump has work that
660 // needs to be processed; that was supposed to be signaled by
661 // nsIRunnable(s).
663 // So instead of hacking Cocoa nsAppShell or rewriting the
664 // event-loop system, we compromise here by processing any tasks
665 // that might have been enqueued on MessagePump, *before*
666 // MessagePump::ScheduleWork was able to successfully
667 // DispatchToMainThread().
668 MessageLoop* loop = MessageLoop::current();
669 bool couldNest = loop->NestableTasksAllowed();
671 loop->SetNestableTasksAllowed(true);
672 loop->PostTask(FROM_HERE, new MessageLoop::QuitTask());
673 loop->Run();
675 loop->SetNestableTasksAllowed(couldNest);
677 #endif // XP_MACOSX
678 return appShell->Run();
681 template<>
682 struct RunnableMethodTraits<ContentChild>
684 static void RetainCallee(ContentChild* obj) { }
685 static void ReleaseCallee(ContentChild* obj) { }
688 void
689 XRE_ShutdownChildProcess()
691 NS_ABORT_IF_FALSE(MessageLoopForUI::current(), "Wrong thread!");
693 MessageLoop* ioLoop = XRE_GetIOMessageLoop();
694 NS_ABORT_IF_FALSE(!!ioLoop, "Bad shutdown order");
696 // Quit() sets off the following chain of events
697 // (1) UI loop starts quitting
698 // (2) UI loop returns from Run() in XRE_InitChildProcess()
699 // (3) ProcessChild goes out of scope and terminates the IO thread
700 // (4) ProcessChild joins the IO thread
701 // (5) exit()
702 MessageLoop::current()->Quit();
703 #if defined(XP_MACOSX)
704 nsCOMPtr<nsIAppShell> appShell(do_GetService(kAppShellCID));
705 if (appShell) {
706 // On Mac, we might be only above nsAppShell::Run(), not
707 // MessagePump::Run(). See XRE_RunAppShell(). To account for
708 // that case, we fire off an Exit() here. If we were indeed
709 // above MessagePump::Run(), this Exit() is just superfluous.
710 appShell->Exit();
712 #endif // XP_MACOSX
715 namespace {
716 TestShellParent* gTestShellParent = nsnull;
717 TestShellParent* GetOrCreateTestShellParent()
719 if (!gTestShellParent) {
720 ContentParent* parent = ContentParent::GetSingleton();
721 NS_ENSURE_TRUE(parent, nsnull);
722 gTestShellParent = parent->CreateTestShell();
723 NS_ENSURE_TRUE(gTestShellParent, nsnull);
725 return gTestShellParent;
729 bool
730 XRE_SendTestShellCommand(JSContext* aCx,
731 JSString* aCommand,
732 void* aCallback)
734 TestShellParent* tsp = GetOrCreateTestShellParent();
735 NS_ENSURE_TRUE(tsp, false);
737 nsDependentJSString command;
738 NS_ENSURE_TRUE(command.init(aCx, aCommand), NS_ERROR_FAILURE);
740 if (!aCallback) {
741 return tsp->SendExecuteCommand(command);
744 TestShellCommandParent* callback = static_cast<TestShellCommandParent*>(
745 tsp->SendPTestShellCommandConstructor(command));
746 NS_ENSURE_TRUE(callback, false);
748 jsval callbackVal = *reinterpret_cast<jsval*>(aCallback);
749 NS_ENSURE_TRUE(callback->SetCallback(aCx, callbackVal), false);
751 return true;
754 bool
755 XRE_GetChildGlobalObject(JSContext* aCx, JSObject** aGlobalP)
757 TestShellParent* tsp = GetOrCreateTestShellParent();
758 return tsp && tsp->GetGlobalJSObject(aCx, aGlobalP);
761 bool
762 XRE_ShutdownTestShell()
764 if (!gTestShellParent)
765 return true;
766 return ContentParent::GetSingleton()->DestroyTestShell(gTestShellParent);
769 #ifdef MOZ_X11
770 void
771 XRE_InstallX11ErrorHandler()
773 InstallX11ErrorHandler();
775 #endif
777 #endif // MOZ_IPC