Bug 628949 - Update visible region / glass regions after we paint. r=roc a=2.0.
[mozilla-central.git] / toolkit / xre / nsAppRunner.cpp
blobac8e9affdc9aa039d9ba3a2c415749027feb957f
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is Mozilla Communicator client code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
24 * Benjamin Smedberg <benjamin@smedbergs.us>
25 * Ben Goodger <ben@mozilla.org>
26 * Fredrik Holmqvist <thesuckiestemail@yahoo.se>
27 * Ben Turner <mozilla@songbirdnest.com>
28 * Sergei Dolgov <sergei_d@fi.tartu.ee>
30 * Alternatively, the contents of this file may be used under the terms of
31 * either the GNU General Public License Version 2 or later (the "GPL"), or
32 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
33 * in which case the provisions of the GPL or the LGPL are applicable instead
34 * of those above. If you wish to allow use of your version of this file only
35 * under the terms of either the GPL or the LGPL, and not to allow others to
36 * use your version of this file under the terms of the MPL, indicate your
37 * decision by deleting the provisions above and replace them with the notice
38 * and other provisions required by the GPL or the LGPL. If you do not delete
39 * the provisions above, a recipient may use your version of this file under
40 * the terms of any one of the MPL, the GPL or the LGPL.
42 * ***** END LICENSE BLOCK ***** */
44 #if defined(XP_OS2) && defined(MOZ_OS2_HIGH_MEMORY)
45 // os2safe.h has to be included before os2.h, needed for high mem
46 #include <os2safe.h>
47 #endif
49 #define XPCOM_TRANSLATE_NSGM_ENTRY_POINT 1
51 #if defined(MOZ_WIDGET_QT)
52 #include <QtGui/QApplication>
53 #include <QtCore/QScopedPointer>
54 #include <QtGui/QApplication>
55 #include <QtGui/QInputContextFactory>
56 #include <QtGui/QInputContext>
57 #endif // MOZ_WIDGET_QT
59 #ifdef MOZ_IPC
60 #include "mozilla/dom/ContentParent.h"
61 using mozilla::dom::ContentParent;
62 #endif
64 #include "nsAppRunner.h"
65 #include "nsUpdateDriver.h"
67 #ifdef XP_MACOSX
68 #include "MacLaunchHelper.h"
69 #include "MacApplicationDelegate.h"
70 #include "MacAutoreleasePool.h"
71 #endif
73 #ifdef XP_OS2
74 #include "private/pprthred.h"
75 #endif
76 #include "prmem.h"
77 #include "prnetdb.h"
78 #include "prprf.h"
79 #include "prproces.h"
80 #include "prenv.h"
82 #include "nsIAppShellService.h"
83 #include "nsIAppStartup.h"
84 #include "nsIAppStartupNotifier.h"
85 #include "nsIMutableArray.h"
86 #include "nsICategoryManager.h"
87 #include "nsIChromeRegistry.h"
88 #include "nsICommandLineRunner.h"
89 #include "nsIComponentManager.h"
90 #include "nsIComponentRegistrar.h"
91 #include "nsIContentHandler.h"
92 #include "nsIDialogParamBlock.h"
93 #include "nsIDOMWindow.h"
94 #include "nsIFastLoadService.h" // for PLATFORM_FASL_SUFFIX
95 #include "mozilla/ModuleUtils.h"
96 #include "nsIIOService2.h"
97 #include "nsIObserverService.h"
98 #include "nsINativeAppSupport.h"
99 #include "nsIProcess.h"
100 #include "nsIProfileUnlocker.h"
101 #include "nsIPromptService.h"
102 #include "nsIServiceManager.h"
103 #include "nsIStringBundle.h"
104 #include "nsISupportsPrimitives.h"
105 #include "nsITimelineService.h"
106 #include "nsIToolkitChromeRegistry.h"
107 #include "nsIToolkitProfile.h"
108 #include "nsIToolkitProfileService.h"
109 #include "nsIURI.h"
110 #include "nsIWindowCreator.h"
111 #include "nsIWindowMediator.h"
112 #include "nsIWindowWatcher.h"
113 #include "nsIXULAppInfo.h"
114 #include "nsIXULRuntime.h"
115 #include "nsPIDOMWindow.h"
116 #include "nsIBaseWindow.h"
117 #include "nsIWidget.h"
118 #include "nsIDocShell.h"
119 #include "nsAppShellCID.h"
121 #include "mozilla/FunctionTimer.h"
123 #ifdef XP_WIN
124 #include "nsIWinAppHelper.h"
125 #include <windows.h>
126 #include "cairo/cairo-features.h"
128 #ifndef PROCESS_DEP_ENABLE
129 #define PROCESS_DEP_ENABLE 0x1
130 #endif
131 #endif
133 #include "nsCRT.h"
134 #include "nsCOMPtr.h"
135 #include "nsDirectoryServiceDefs.h"
136 #include "nsDirectoryServiceUtils.h"
137 #include "nsEmbedCID.h"
138 #include "nsNetUtil.h"
139 #include "nsReadableUtils.h"
140 #include "nsStaticComponents.h"
141 #include "nsXPCOM.h"
142 #include "nsXPCOMCIDInternal.h"
143 #include "nsXPIDLString.h"
144 #include "nsVersionComparator.h"
146 #include "nsAppDirectoryServiceDefs.h"
147 #include "nsXULAppAPI.h"
148 #include "nsXREDirProvider.h"
149 #include "nsToolkitCompsCID.h"
151 #include "nsINIParser.h"
152 #include "mozilla/Omnijar.h"
154 #include <stdlib.h>
156 #if defined(MOZ_SPLASHSCREEN)
157 #include "nsSplashScreen.h"
158 #endif
160 #ifdef XP_UNIX
161 #include <sys/stat.h>
162 #include <unistd.h>
163 #include <pwd.h>
164 #endif
166 #ifdef XP_BEOS
167 // execv() behaves bit differently in R5 and Zeta, looks unreliable in such situation
168 //#include <unistd.h>
169 #include <AppKit.h>
170 #include <AppFileInfo.h>
171 #endif //XP_BEOS
173 #ifdef XP_WIN
174 #ifndef WINCE
175 #include <process.h>
176 #include <shlobj.h>
177 #endif
178 #include "nsThreadUtils.h"
179 #endif
181 #ifdef XP_MACOSX
182 #include "nsILocalFileMac.h"
183 #include "nsCommandLineServiceMac.h"
184 #endif
186 // for X remote support
187 #ifdef MOZ_ENABLE_XREMOTE
188 #include "XRemoteClient.h"
189 #include "nsIRemoteService.h"
190 #endif
192 #ifdef NS_TRACE_MALLOC
193 #include "nsTraceMalloc.h"
194 #endif
196 #if defined(DEBUG) && defined(XP_WIN32)
197 #include <malloc.h>
198 #endif
200 #if defined (XP_MACOSX)
201 #include <Carbon/Carbon.h>
202 #endif
204 #ifdef DEBUG
205 #include "prlog.h"
206 #endif
208 #ifdef MOZ_JPROF
209 #include "jprof.h"
210 #endif
212 #ifdef MOZ_CRASHREPORTER
213 #include "nsExceptionHandler.h"
214 #include "nsICrashReporter.h"
215 #define NS_CRASHREPORTER_CONTRACTID "@mozilla.org/toolkit/crash-reporter;1"
216 #include "nsIPrefService.h"
217 #endif
219 #ifdef MOZ_IPC
220 #include "base/command_line.h"
221 #endif
223 #include "mozilla/FunctionTimer.h"
225 #ifdef ANDROID
226 #include "AndroidBridge.h"
227 #endif
229 #ifdef WINCE
230 class WindowsMutex {
231 public:
232 WindowsMutex(const wchar_t *name) {
233 mHandle = CreateMutexW(0, FALSE, name);
236 ~WindowsMutex() {
237 Unlock();
238 CloseHandle(mHandle);
241 PRBool Lock(DWORD timeout = INFINITE) {
242 DWORD state = WaitForSingleObject(mHandle, timeout);
243 return state == WAIT_OBJECT_0;
246 void Unlock() {
247 if (mHandle)
248 ReleaseMutex(mHandle);
251 protected:
252 HANDLE mHandle;
254 #endif
256 extern PRUint32 gRestartMode;
257 extern void InstallSignalHandlers(const char *ProgramName);
258 #include "nsX11ErrorHandler.h"
260 #define FILE_COMPATIBILITY_INFO NS_LITERAL_CSTRING("compatibility.ini")
261 #define FILE_INVALIDATE_CACHES NS_LITERAL_CSTRING(".purgecaches")
263 int gArgc;
264 char **gArgv;
266 static const char gToolkitVersion[] = NS_STRINGIFY(GRE_MILESTONE);
267 static const char gToolkitBuildID[] = NS_STRINGIFY(GRE_BUILDID);
269 static int gRestartArgc;
270 static char **gRestartArgv;
272 #ifdef MOZ_WIDGET_QT
273 static int gQtOnlyArgc;
274 static char **gQtOnlyArgv;
275 #endif
277 #if defined(MOZ_WIDGET_GTK2)
278 #if defined(DEBUG) || defined(NS_BUILD_REFCNT_LOGGING) \
279 || defined(NS_TRACE_MALLOC)
280 #define CLEANUP_MEMORY 1
281 #define PANGO_ENABLE_BACKEND
282 #include <pango/pangofc-fontmap.h>
283 #endif
284 #include <gtk/gtk.h>
285 #ifdef MOZ_X11
286 #include <gdk/gdkx.h>
287 #endif /* MOZ_X11 */
288 #include "nsGTKToolkit.h"
289 #endif
291 // Save literal putenv string to environment variable.
292 static void
293 SaveToEnv(const char *putenv)
295 char *expr = strdup(putenv);
296 if (expr)
297 PR_SetEnv(expr);
298 // We intentionally leak |expr| here since it is required by PR_SetEnv.
301 // Save the given word to the specified environment variable.
302 static void
303 SaveWordToEnv(const char *name, const nsACString & word)
305 char *expr = PR_smprintf("%s=%s", name, PromiseFlatCString(word).get());
306 if (expr)
307 PR_SetEnv(expr);
308 // We intentionally leak |expr| here since it is required by PR_SetEnv.
311 // Save the path of the given file to the specified environment variable.
312 static void
313 SaveFileToEnv(const char *name, nsIFile *file)
315 #ifdef XP_WIN
316 nsAutoString path;
317 file->GetPath(path);
318 SetEnvironmentVariableW(NS_ConvertASCIItoUTF16(name).get(), path.get());
319 #else
320 nsCAutoString path;
321 file->GetNativePath(path);
322 SaveWordToEnv(name, path);
323 #endif
326 // Load the path of a file saved with SaveFileToEnv
327 static already_AddRefed<nsILocalFile>
328 GetFileFromEnv(const char *name)
330 nsresult rv;
331 nsILocalFile *file = nsnull;
333 #ifdef XP_WIN
334 WCHAR path[_MAX_PATH];
335 if (!GetEnvironmentVariableW(NS_ConvertASCIItoUTF16(name).get(),
336 path, _MAX_PATH))
337 return nsnull;
339 rv = NS_NewLocalFile(nsDependentString(path), PR_TRUE, &file);
340 if (NS_FAILED(rv))
341 return nsnull;
343 return file;
344 #else
345 const char *arg = PR_GetEnv(name);
346 if (!arg || !*arg)
347 return nsnull;
349 rv = NS_NewNativeLocalFile(nsDependentCString(arg), PR_TRUE, &file);
350 if (NS_FAILED(rv))
351 return nsnull;
353 return file;
354 #endif
357 // Save the path of the given word to the specified environment variable
358 // provided the environment variable does not have a value.
359 static void
360 SaveWordToEnvIfUnset(const char *name, const nsACString & word)
362 const char *val = PR_GetEnv(name);
363 if (!(val && *val))
364 SaveWordToEnv(name, word);
367 // Save the path of the given file to the specified environment variable
368 // provided the environment variable does not have a value.
369 static void
370 SaveFileToEnvIfUnset(const char *name, nsIFile *file)
372 const char *val = PR_GetEnv(name);
373 if (!(val && *val))
374 SaveFileToEnv(name, file);
377 static PRBool
378 strimatch(const char* lowerstr, const char* mixedstr)
380 while(*lowerstr) {
381 if (!*mixedstr) return PR_FALSE; // mixedstr is shorter
382 if (tolower(*mixedstr) != *lowerstr) return PR_FALSE; // no match
384 ++lowerstr;
385 ++mixedstr;
388 if (*mixedstr) return PR_FALSE; // lowerstr is shorter
390 return PR_TRUE;
394 * Output a string to the user. This method is really only meant to be used to
395 * output last-ditch error messages designed for developers NOT END USERS.
397 * @param isError
398 * Pass true to indicate severe errors.
399 * @param fmt
400 * printf-style format string followed by arguments.
402 static void Output(PRBool isError, const char *fmt, ... )
404 va_list ap;
405 va_start(ap, fmt);
407 #if defined(XP_WIN) && !MOZ_WINCONSOLE
408 char *msg = PR_vsmprintf(fmt, ap);
409 if (msg)
411 UINT flags = MB_OK;
412 if (isError)
413 flags |= MB_ICONERROR;
414 else
415 flags |= MB_ICONINFORMATION;
417 wchar_t wide_msg[1024];
418 MultiByteToWideChar(CP_ACP,
420 msg,
422 wide_msg,
423 sizeof(wide_msg) / sizeof(wchar_t));
425 MessageBoxW(NULL, wide_msg, L"XULRunner", flags);
426 PR_smprintf_free(msg);
428 #else
429 vfprintf(stderr, fmt, ap);
430 #endif
432 va_end(ap);
435 enum RemoteResult {
436 REMOTE_NOT_FOUND = 0,
437 REMOTE_FOUND = 1,
438 REMOTE_ARG_BAD = 2
441 enum ArgResult {
442 ARG_NONE = 0,
443 ARG_FOUND = 1,
444 ARG_BAD = 2 // you wanted a param, but there isn't one
447 static void RemoveArg(char **argv)
449 do {
450 *argv = *(argv + 1);
451 ++argv;
452 } while (*argv);
454 --gArgc;
458 * Check for a commandline flag. If the flag takes a parameter, the
459 * parameter is returned in aParam. Flags may be in the form -arg or
460 * --arg (or /arg on win32/OS2).
462 * @param aArg the parameter to check. Must be lowercase.
463 * @param aCheckOSInt if true returns ARG_BAD if the osint argument is present
464 * when aArg is also present.
465 * @param if non-null, the -arg <data> will be stored in this pointer. This is *not*
466 * allocated, but rather a pointer to the argv data.
468 static ArgResult
469 CheckArg(const char* aArg, PRBool aCheckOSInt = PR_FALSE, const char **aParam = nsnull, PRBool aRemArg = PR_TRUE)
471 NS_ABORT_IF_FALSE(gArgv, "gArgv must be initialized before CheckArg()");
473 char **curarg = gArgv + 1; // skip argv[0]
474 ArgResult ar = ARG_NONE;
476 while (*curarg) {
477 char *arg = curarg[0];
479 if (arg[0] == '-'
480 #if defined(XP_WIN) || defined(XP_OS2)
481 || *arg == '/'
482 #endif
484 ++arg;
485 if (*arg == '-')
486 ++arg;
488 if (strimatch(aArg, arg)) {
489 if (aRemArg)
490 RemoveArg(curarg);
491 if (!aParam) {
492 ar = ARG_FOUND;
493 break;
496 if (*curarg) {
497 if (**curarg == '-'
498 #if defined(XP_WIN) || defined(XP_OS2)
499 || **curarg == '/'
500 #endif
502 return ARG_BAD;
504 *aParam = *curarg;
505 if (aRemArg)
506 RemoveArg(curarg);
507 ar = ARG_FOUND;
508 break;
510 return ARG_BAD;
514 ++curarg;
517 if (aCheckOSInt && ar == ARG_FOUND) {
518 ArgResult arOSInt = CheckArg("osint");
519 if (arOSInt == ARG_FOUND) {
520 ar = ARG_BAD;
521 PR_fprintf(PR_STDERR, "Error: argument -osint is invalid\n");
525 return ar;
528 #if defined(XP_WIN)
530 * Check for a commandline flag from the windows shell and remove it from the
531 * argv used when restarting. Flags MUST be in the form -arg.
533 * @param aArg the parameter to check. Must be lowercase.
535 static ArgResult
536 CheckArgShell(const char* aArg)
538 char **curarg = gRestartArgv + 1; // skip argv[0]
540 while (*curarg) {
541 char *arg = curarg[0];
543 if (arg[0] == '-') {
544 ++arg;
546 if (strimatch(aArg, arg)) {
547 do {
548 *curarg = *(curarg + 1);
549 ++curarg;
550 } while (*curarg);
552 --gRestartArgc;
554 return ARG_FOUND;
558 ++curarg;
561 return ARG_NONE;
565 * Enabled Native App Support to process DDE messages when the app needs to
566 * restart and the app has been launched by the Windows shell to open an url.
567 * When aWait is false this will process the DDE events manually. This prevents
568 * Windows from displaying an error message due to the DDE message not being
569 * acknowledged.
571 static void
572 ProcessDDE(nsINativeAppSupport* aNative, PRBool aWait)
574 // When the app is launched by the windows shell the windows shell
575 // expects the app to be available for DDE messages and if it isn't
576 // windows displays an error dialog. To prevent the error the DDE server
577 // is enabled and pending events are processed when the app needs to
578 // restart after it was launched by the shell with the requestpending
579 // argument. The requestpending pending argument is removed to
580 // differentiate it from being launched when an app restart is not
581 // required.
582 ArgResult ar;
583 ar = CheckArgShell("requestpending");
584 if (ar == ARG_FOUND) {
585 aNative->Enable(); // enable win32 DDE responses
586 if (aWait) {
587 nsIThread *thread = NS_GetCurrentThread();
588 // This is just a guesstimate based on testing different values.
589 // If count is 8 or less windows will display an error dialog.
590 PRInt32 count = 20;
591 while(--count >= 0) {
592 NS_ProcessNextEvent(thread);
593 PR_Sleep(PR_MillisecondsToInterval(1));
598 #endif
600 PRBool gSafeMode = PR_FALSE;
603 * The nsXULAppInfo object implements nsIFactory so that it can be its own
604 * singleton.
606 class nsXULAppInfo : public nsIXULAppInfo,
607 #ifdef XP_WIN
608 public nsIWinAppHelper,
609 #endif
610 #ifdef MOZ_CRASHREPORTER
611 public nsICrashReporter,
612 #endif
613 public nsIXULRuntime
616 public:
617 NS_DECL_ISUPPORTS_INHERITED
618 NS_DECL_NSIXULAPPINFO
619 NS_DECL_NSIXULRUNTIME
620 #ifdef MOZ_CRASHREPORTER
621 NS_DECL_NSICRASHREPORTER
622 #endif
623 #ifdef XP_WIN
624 NS_DECL_NSIWINAPPHELPER
625 #endif
628 NS_INTERFACE_MAP_BEGIN(nsXULAppInfo)
629 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXULRuntime)
630 NS_INTERFACE_MAP_ENTRY(nsIXULRuntime)
631 #ifdef XP_WIN
632 NS_INTERFACE_MAP_ENTRY(nsIWinAppHelper)
633 #endif
634 #ifdef MOZ_CRASHREPORTER
635 NS_INTERFACE_MAP_ENTRY(nsICrashReporter)
636 #endif
637 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIXULAppInfo, gAppData)
638 NS_INTERFACE_MAP_END
640 NS_IMETHODIMP_(nsrefcnt)
641 nsXULAppInfo::AddRef()
643 return 1;
646 NS_IMETHODIMP_(nsrefcnt)
647 nsXULAppInfo::Release()
649 return 1;
652 NS_IMETHODIMP
653 nsXULAppInfo::GetVendor(nsACString& aResult)
655 aResult.Assign(gAppData->vendor);
657 return NS_OK;
660 NS_IMETHODIMP
661 nsXULAppInfo::GetName(nsACString& aResult)
663 aResult.Assign(gAppData->name);
665 return NS_OK;
668 NS_IMETHODIMP
669 nsXULAppInfo::GetID(nsACString& aResult)
671 aResult.Assign(gAppData->ID);
673 return NS_OK;
676 NS_IMETHODIMP
677 nsXULAppInfo::GetVersion(nsACString& aResult)
679 aResult.Assign(gAppData->version);
681 return NS_OK;
684 NS_IMETHODIMP
685 nsXULAppInfo::GetPlatformVersion(nsACString& aResult)
687 aResult.Assign(gToolkitVersion);
689 return NS_OK;
692 NS_IMETHODIMP
693 nsXULAppInfo::GetAppBuildID(nsACString& aResult)
695 aResult.Assign(gAppData->buildID);
697 return NS_OK;
700 NS_IMETHODIMP
701 nsXULAppInfo::GetPlatformBuildID(nsACString& aResult)
703 aResult.Assign(gToolkitBuildID);
705 return NS_OK;
708 NS_IMETHODIMP
709 nsXULAppInfo::GetLogConsoleErrors(PRBool *aResult)
711 *aResult = gLogConsoleErrors;
712 return NS_OK;
715 NS_IMETHODIMP
716 nsXULAppInfo::SetLogConsoleErrors(PRBool aValue)
718 gLogConsoleErrors = aValue;
719 return NS_OK;
722 NS_IMETHODIMP
723 nsXULAppInfo::GetInSafeMode(PRBool *aResult)
725 *aResult = gSafeMode;
726 return NS_OK;
729 NS_IMETHODIMP
730 nsXULAppInfo::GetOS(nsACString& aResult)
732 aResult.AssignLiteral(OS_TARGET);
733 return NS_OK;
736 NS_IMETHODIMP
737 nsXULAppInfo::GetXPCOMABI(nsACString& aResult)
739 #ifdef TARGET_XPCOM_ABI
740 aResult.AssignLiteral(TARGET_XPCOM_ABI);
741 return NS_OK;
742 #else
743 return NS_ERROR_NOT_AVAILABLE;
744 #endif
747 NS_IMETHODIMP
748 nsXULAppInfo::GetWidgetToolkit(nsACString& aResult)
750 aResult.AssignLiteral(MOZ_WIDGET_TOOLKIT);
751 return NS_OK;
754 // Ensure that the GeckoProcessType enum, defined in xpcom/build/nsXULAppAPI.h,
755 // is synchronized with the const unsigned longs defined in
756 // xpcom/system/nsIXULRuntime.idl.
757 #define SYNC_ENUMS(a,b) \
758 PR_STATIC_ASSERT(nsIXULRuntime::PROCESS_TYPE_ ## a == \
759 static_cast<int>(GeckoProcessType_ ## b));
761 SYNC_ENUMS(DEFAULT, Default)
762 SYNC_ENUMS(PLUGIN, Plugin)
763 SYNC_ENUMS(CONTENT, Content)
764 SYNC_ENUMS(JETPACK, Jetpack)
765 SYNC_ENUMS(IPDLUNITTEST, IPDLUnitTest)
767 // .. and ensure that that is all of them:
768 PR_STATIC_ASSERT(GeckoProcessType_IPDLUnitTest + 1 == GeckoProcessType_End);
770 NS_IMETHODIMP
771 nsXULAppInfo::GetProcessType(PRUint32* aResult)
773 NS_ENSURE_ARG_POINTER(aResult);
774 *aResult = XRE_GetProcessType();
775 return NS_OK;
778 NS_IMETHODIMP
779 nsXULAppInfo::EnsureContentProcess()
781 #ifdef MOZ_IPC
782 if (XRE_GetProcessType() != GeckoProcessType_Default)
783 return NS_ERROR_NOT_AVAILABLE;
785 ContentParent* c = ContentParent::GetSingleton();
786 if (!c)
787 return NS_ERROR_NOT_AVAILABLE;
788 return NS_OK;
789 #else
790 return NS_ERROR_NOT_AVAILABLE;
791 #endif
794 NS_IMETHODIMP
795 nsXULAppInfo::InvalidateCachesOnRestart()
797 nsCOMPtr<nsIFile> file;
798 nsresult rv = NS_GetSpecialDirectory(NS_APP_PROFILE_DIR_STARTUP,
799 getter_AddRefs(file));
800 if (NS_FAILED(rv))
801 return rv;
802 if (!file)
803 return NS_ERROR_NOT_AVAILABLE;
805 file->AppendNative(FILE_COMPATIBILITY_INFO);
807 nsCOMPtr<nsILocalFile> localFile(do_QueryInterface(file));
808 nsINIParser parser;
809 rv = parser.Init(localFile);
810 if (NS_FAILED(rv)) {
811 // This fails if compatibility.ini is not there, so we'll
812 // flush the caches on the next restart anyways.
813 return NS_OK;
816 nsCAutoString buf;
817 rv = parser.GetString("Compatibility", "InvalidateCaches", buf);
819 if (NS_FAILED(rv)) {
820 PRFileDesc *fd = nsnull;
821 localFile->OpenNSPRFileDesc(PR_RDWR | PR_APPEND, 0600, &fd);
822 if (!fd) {
823 NS_ERROR("could not create output stream");
824 return NS_ERROR_NOT_AVAILABLE;
826 static const char kInvalidationHeader[] = NS_LINEBREAK "InvalidateCaches=1" NS_LINEBREAK;
827 rv = PR_Write(fd, kInvalidationHeader, sizeof(kInvalidationHeader) - 1);
828 PR_Close(fd);
830 if (NS_FAILED(rv))
831 return rv;
833 return NS_OK;
836 #ifdef XP_WIN
837 // Matches the enum in WinNT.h for the Vista SDK but renamed so that we can
838 // safely build with the Vista SDK and without it.
839 typedef enum
841 VistaTokenElevationTypeDefault = 1,
842 VistaTokenElevationTypeFull,
843 VistaTokenElevationTypeLimited
844 } VISTA_TOKEN_ELEVATION_TYPE;
846 // avoid collision with TokeElevationType enum in WinNT.h
847 // of the Vista SDK
848 #define VistaTokenElevationType static_cast< TOKEN_INFORMATION_CLASS >( 18 )
850 NS_IMETHODIMP
851 nsXULAppInfo::GetUserCanElevate(PRBool *aUserCanElevate)
853 #ifdef WINCE
854 *aUserCanElevate = PR_FALSE;
855 return NS_OK;
856 #else
857 HANDLE hToken;
859 VISTA_TOKEN_ELEVATION_TYPE elevationType;
860 DWORD dwSize;
862 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken) ||
863 !GetTokenInformation(hToken, VistaTokenElevationType, &elevationType,
864 sizeof(elevationType), &dwSize)) {
865 *aUserCanElevate = PR_FALSE;
867 else {
868 // The possible values returned for elevationType and their meanings are:
869 // TokenElevationTypeDefault: The token does not have a linked token
870 // (e.g. UAC disabled or a standard user, so they can't be elevated)
871 // TokenElevationTypeFull: The token is linked to an elevated token
872 // (e.g. UAC is enabled and the user is already elevated so they can't
873 // be elevated again)
874 // TokenElevationTypeLimited: The token is linked to a limited token
875 // (e.g. UAC is enabled and the user is not elevated, so they can be
876 // elevated)
877 *aUserCanElevate = (elevationType == VistaTokenElevationTypeLimited);
880 if (hToken)
881 CloseHandle(hToken);
883 return NS_OK;
884 #endif // WINCE
886 #endif
888 #ifdef MOZ_CRASHREPORTER
889 NS_IMETHODIMP
890 nsXULAppInfo::GetEnabled(PRBool *aEnabled)
892 *aEnabled = CrashReporter::GetEnabled();
893 return NS_OK;
896 NS_IMETHODIMP
897 nsXULAppInfo::SetEnabled(PRBool aEnabled)
899 if (aEnabled) {
900 if (CrashReporter::GetEnabled())
901 // no point in erroring for double-enabling
902 return NS_OK;
904 nsCOMPtr<nsILocalFile> xreDirectory;
905 if (gAppData) {
906 xreDirectory = gAppData->xreDirectory;
908 else {
909 // We didn't get started through XRE_Main, probably
910 nsCOMPtr<nsIFile> greDir;
911 NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(greDir));
912 if (!greDir)
913 return NS_ERROR_FAILURE;
915 xreDirectory = do_QueryInterface(greDir);
916 if (!xreDirectory)
917 return NS_ERROR_FAILURE;
919 return CrashReporter::SetExceptionHandler(xreDirectory, true);
921 else {
922 if (!CrashReporter::GetEnabled())
923 // no point in erroring for double-disabling
924 return NS_OK;
926 return CrashReporter::UnsetExceptionHandler();
930 NS_IMETHODIMP
931 nsXULAppInfo::GetServerURL(nsIURL** aServerURL)
933 if (!CrashReporter::GetEnabled())
934 return NS_ERROR_NOT_INITIALIZED;
936 nsCAutoString data;
937 if (!CrashReporter::GetServerURL(data)) {
938 return NS_ERROR_FAILURE;
940 nsCOMPtr<nsIURI> uri;
941 NS_NewURI(getter_AddRefs(uri), data);
942 if (!uri)
943 return NS_ERROR_FAILURE;
945 nsCOMPtr<nsIURL> url;
946 url = do_QueryInterface(uri);
947 NS_ADDREF(*aServerURL = url);
949 return NS_OK;
952 NS_IMETHODIMP
953 nsXULAppInfo::SetServerURL(nsIURL* aServerURL)
955 PRBool schemeOk;
956 // only allow https or http URLs
957 nsresult rv = aServerURL->SchemeIs("https", &schemeOk);
958 NS_ENSURE_SUCCESS(rv, rv);
959 if (!schemeOk) {
960 rv = aServerURL->SchemeIs("http", &schemeOk);
961 NS_ENSURE_SUCCESS(rv, rv);
963 if (!schemeOk)
964 return NS_ERROR_INVALID_ARG;
966 nsCAutoString spec;
967 rv = aServerURL->GetSpec(spec);
968 NS_ENSURE_SUCCESS(rv, rv);
970 return CrashReporter::SetServerURL(spec);
973 NS_IMETHODIMP
974 nsXULAppInfo::GetMinidumpPath(nsILocalFile** aMinidumpPath)
976 if (!CrashReporter::GetEnabled())
977 return NS_ERROR_NOT_INITIALIZED;
979 nsAutoString path;
980 if (!CrashReporter::GetMinidumpPath(path))
981 return NS_ERROR_FAILURE;
983 nsresult rv = NS_NewLocalFile(path, PR_FALSE, aMinidumpPath);
984 NS_ENSURE_SUCCESS(rv, rv);
985 return NS_OK;
988 NS_IMETHODIMP
989 nsXULAppInfo::SetMinidumpPath(nsILocalFile* aMinidumpPath)
991 nsAutoString path;
992 nsresult rv = aMinidumpPath->GetPath(path);
993 NS_ENSURE_SUCCESS(rv, rv);
994 return CrashReporter::SetMinidumpPath(path);
997 NS_IMETHODIMP
998 nsXULAppInfo::AnnotateCrashReport(const nsACString& key,
999 const nsACString& data)
1001 return CrashReporter::AnnotateCrashReport(key, data);
1004 NS_IMETHODIMP
1005 nsXULAppInfo::AppendAppNotesToCrashReport(const nsACString& data)
1007 return CrashReporter::AppendAppNotesToCrashReport(data);
1010 NS_IMETHODIMP
1011 nsXULAppInfo::WriteMinidumpForException(void* aExceptionInfo)
1013 #ifdef XP_WIN32
1014 return CrashReporter::WriteMinidumpForException(static_cast<EXCEPTION_POINTERS*>(aExceptionInfo));
1015 #else
1016 return NS_ERROR_NOT_IMPLEMENTED;
1017 #endif
1020 NS_IMETHODIMP
1021 nsXULAppInfo::AppendObjCExceptionInfoToAppNotes(void* aException)
1023 #ifdef XP_MACOSX
1024 return CrashReporter::AppendObjCExceptionInfoToAppNotes(aException);
1025 #else
1026 return NS_ERROR_NOT_IMPLEMENTED;
1027 #endif
1030 NS_IMETHODIMP
1031 nsXULAppInfo::GetSubmitReports(PRBool* aEnabled)
1033 return CrashReporter::GetSubmitReports(aEnabled);
1036 NS_IMETHODIMP
1037 nsXULAppInfo::SetSubmitReports(PRBool aEnabled)
1039 return CrashReporter::SetSubmitReports(aEnabled);
1042 #endif
1044 static const nsXULAppInfo kAppInfo;
1045 static nsresult AppInfoConstructor(nsISupports* aOuter,
1046 REFNSIID aIID, void **aResult)
1048 NS_ENSURE_NO_AGGREGATION(aOuter);
1050 return const_cast<nsXULAppInfo*>(&kAppInfo)->
1051 QueryInterface(aIID, aResult);
1054 PRBool gLogConsoleErrors
1055 #ifdef DEBUG
1056 = PR_TRUE;
1057 #else
1058 = PR_FALSE;
1059 #endif
1061 #define NS_ENSURE_TRUE_LOG(x, ret) \
1062 PR_BEGIN_MACRO \
1063 if (NS_UNLIKELY(!(x))) { \
1064 NS_WARNING("NS_ENSURE_TRUE(" #x ") failed"); \
1065 gLogConsoleErrors = PR_TRUE; \
1066 return ret; \
1068 PR_END_MACRO
1070 #define NS_ENSURE_SUCCESS_LOG(res, ret) \
1071 NS_ENSURE_TRUE_LOG(NS_SUCCEEDED(res), ret)
1074 * Because we're starting/stopping XPCOM several times in different scenarios,
1075 * this class is a stack-based critter that makes sure that XPCOM is shut down
1076 * during early returns.
1079 class ScopedXPCOMStartup
1081 public:
1082 ScopedXPCOMStartup() :
1083 mServiceManager(nsnull) { }
1084 ~ScopedXPCOMStartup();
1086 nsresult Initialize();
1087 nsresult SetWindowCreator(nsINativeAppSupport* native);
1089 static nsresult CreateAppSupport(nsISupports* aOuter, REFNSIID aIID, void** aResult);
1091 private:
1092 nsIServiceManager* mServiceManager;
1093 static nsINativeAppSupport* gNativeAppSupport;
1096 ScopedXPCOMStartup::~ScopedXPCOMStartup()
1098 NS_IF_RELEASE(gNativeAppSupport);
1100 if (mServiceManager) {
1101 #ifdef XP_MACOSX
1102 // On OS X, we need a pool to catch cocoa objects that are autoreleased
1103 // during teardown.
1104 mozilla::MacAutoreleasePool pool;
1105 #endif
1107 nsCOMPtr<nsIAppStartup> appStartup (do_GetService(NS_APPSTARTUP_CONTRACTID));
1108 if (appStartup)
1109 appStartup->DestroyHiddenWindow();
1111 gDirServiceProvider->DoShutdown();
1113 WriteConsoleLog();
1115 NS_ShutdownXPCOM(mServiceManager);
1116 mServiceManager = nsnull;
1120 // {95d89e3e-a169-41a3-8e56-719978e15b12}
1121 #define APPINFO_CID \
1122 { 0x95d89e3e, 0xa169, 0x41a3, { 0x8e, 0x56, 0x71, 0x99, 0x78, 0xe1, 0x5b, 0x12 } }
1124 // {0C4A446C-EE82-41f2-8D04-D366D2C7A7D4}
1125 static const nsCID kNativeAppSupportCID =
1126 { 0xc4a446c, 0xee82, 0x41f2, { 0x8d, 0x4, 0xd3, 0x66, 0xd2, 0xc7, 0xa7, 0xd4 } };
1128 // {5F5E59CE-27BC-47eb-9D1F-B09CA9049836}
1129 static const nsCID kProfileServiceCID =
1130 { 0x5f5e59ce, 0x27bc, 0x47eb, { 0x9d, 0x1f, 0xb0, 0x9c, 0xa9, 0x4, 0x98, 0x36 } };
1132 static already_AddRefed<nsIFactory>
1133 ProfileServiceFactoryConstructor(const mozilla::Module& module, const mozilla::Module::CIDEntry& entry)
1135 nsCOMPtr<nsIFactory> factory;
1136 NS_NewToolkitProfileFactory(getter_AddRefs(factory));
1137 return factory.forget();
1140 NS_DEFINE_NAMED_CID(APPINFO_CID);
1142 static const mozilla::Module::CIDEntry kXRECIDs[] = {
1143 { &kAPPINFO_CID, false, NULL, AppInfoConstructor },
1144 { &kProfileServiceCID, false, ProfileServiceFactoryConstructor, NULL },
1145 { &kNativeAppSupportCID, false, NULL, ScopedXPCOMStartup::CreateAppSupport },
1146 { NULL }
1149 static const mozilla::Module::ContractIDEntry kXREContracts[] = {
1150 { XULAPPINFO_SERVICE_CONTRACTID, &kAPPINFO_CID },
1151 { XULRUNTIME_SERVICE_CONTRACTID, &kAPPINFO_CID },
1152 #ifdef MOZ_CRASHREPORTER
1153 { NS_CRASHREPORTER_CONTRACTID, &kAPPINFO_CID },
1154 #endif
1155 { NS_PROFILESERVICE_CONTRACTID, &kProfileServiceCID },
1156 { NS_NATIVEAPPSUPPORT_CONTRACTID, &kNativeAppSupportCID },
1157 { NULL }
1160 static const mozilla::Module kXREModule = {
1161 mozilla::Module::kVersion,
1162 kXRECIDs,
1163 kXREContracts
1166 NSMODULE_DEFN(Apprunner) = &kXREModule;
1168 nsresult
1169 ScopedXPCOMStartup::Initialize()
1171 NS_ASSERTION(gDirServiceProvider, "Should not get here!");
1173 nsresult rv;
1175 #ifndef MOZ_ENABLE_LIBXUL
1176 #ifndef _BUILD_STATIC_BIN
1177 XRE_AddStaticComponent(&kXREModule);
1178 #else
1179 for (const mozilla::Module *const *const *staticModules = kPStaticModules;
1180 *staticModules; ++staticModules)
1181 XRE_AddStaticComponent(**staticModules);
1182 #endif
1183 #endif
1185 rv = NS_InitXPCOM2(&mServiceManager, gDirServiceProvider->GetAppDir(),
1186 gDirServiceProvider);
1187 if (NS_FAILED(rv)) {
1188 NS_ERROR("Couldn't start xpcom!");
1189 mServiceManager = nsnull;
1191 else {
1192 nsCOMPtr<nsIComponentRegistrar> reg =
1193 do_QueryInterface(mServiceManager);
1194 NS_ASSERTION(reg, "Service Manager doesn't QI to Registrar.");
1197 return rv;
1201 * This is a little factory class that serves as a singleton-service-factory
1202 * for the nativeappsupport object.
1204 class nsSingletonFactory : public nsIFactory
1206 public:
1207 NS_DECL_ISUPPORTS
1208 NS_DECL_NSIFACTORY
1210 nsSingletonFactory(nsISupports* aSingleton);
1211 ~nsSingletonFactory() { }
1213 private:
1214 nsCOMPtr<nsISupports> mSingleton;
1217 nsSingletonFactory::nsSingletonFactory(nsISupports* aSingleton)
1218 : mSingleton(aSingleton)
1220 NS_ASSERTION(mSingleton, "Singleton was null!");
1223 NS_IMPL_ISUPPORTS1(nsSingletonFactory, nsIFactory)
1225 NS_IMETHODIMP
1226 nsSingletonFactory::CreateInstance(nsISupports* aOuter,
1227 const nsIID& aIID,
1228 void* *aResult)
1230 NS_ENSURE_NO_AGGREGATION(aOuter);
1232 return mSingleton->QueryInterface(aIID, aResult);
1235 NS_IMETHODIMP
1236 nsSingletonFactory::LockFactory(PRBool)
1238 return NS_OK;
1242 * Set our windowcreator on the WindowWatcher service.
1244 nsresult
1245 ScopedXPCOMStartup::SetWindowCreator(nsINativeAppSupport* native)
1247 NS_TIME_FUNCTION;
1248 nsresult rv;
1250 NS_IF_ADDREF(gNativeAppSupport = native);
1252 // Inform the chrome registry about OS accessibility
1253 nsCOMPtr<nsIToolkitChromeRegistry> cr =
1254 mozilla::services::GetToolkitChromeRegistryService();
1255 NS_TIME_FUNCTION_MARK("Got ToolkitChromeRegistry service");
1257 if (cr)
1258 cr->CheckForOSAccessibility();
1260 NS_TIME_FUNCTION_MARK("OS Accessibility check");
1262 nsCOMPtr<nsIWindowCreator> creator (do_GetService(NS_APPSTARTUP_CONTRACTID));
1263 if (!creator) return NS_ERROR_UNEXPECTED;
1265 NS_TIME_FUNCTION_MARK("Got AppStartup service");
1267 nsCOMPtr<nsIWindowWatcher> wwatch
1268 (do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
1269 NS_ENSURE_SUCCESS(rv, rv);
1271 NS_TIME_FUNCTION_MARK("Got WindowWatcher service");
1273 return wwatch->SetWindowCreator(creator);
1276 /* static */ nsresult
1277 ScopedXPCOMStartup::CreateAppSupport(nsISupports* aOuter, REFNSIID aIID, void** aResult)
1279 if (aOuter)
1280 return NS_ERROR_NO_AGGREGATION;
1282 if (!gNativeAppSupport)
1283 return NS_ERROR_NOT_INITIALIZED;
1285 return gNativeAppSupport->QueryInterface(aIID, aResult);
1288 nsINativeAppSupport* ScopedXPCOMStartup::gNativeAppSupport;
1291 * A helper class which calls NS_LogInit/NS_LogTerm in its scope.
1293 class ScopedLogging
1295 public:
1296 ScopedLogging() { NS_LogInit(); }
1297 ~ScopedLogging() { NS_LogTerm(); }
1300 static void DumpArbitraryHelp()
1302 nsresult rv;
1304 ScopedLogging log;
1307 ScopedXPCOMStartup xpcom;
1308 xpcom.Initialize();
1310 nsCOMPtr<nsICommandLineRunner> cmdline
1311 (do_CreateInstance("@mozilla.org/toolkit/command-line;1"));
1312 if (!cmdline)
1313 return;
1315 nsCString text;
1316 rv = cmdline->GetHelpText(text);
1317 if (NS_SUCCEEDED(rv))
1318 printf("%s", text.get());
1322 // English text needs to go into a dtd file.
1323 // But when this is called we have no components etc. These strings must either be
1324 // here, or in a native resource file.
1325 static void
1326 DumpHelp()
1328 printf("Usage: %s [ options ... ] [URL]\n"
1329 " where options include:\n\n", gArgv[0]);
1331 #ifdef MOZ_X11
1332 printf("X11 options\n"
1333 " --display=DISPLAY X display to use\n"
1334 " --sync Make X calls synchronous\n"
1335 " --no-xshm Don't use X shared memory extension\n"
1336 " --xim-preedit=STYLE\n"
1337 " --xim-status=STYLE\n");
1338 #endif
1339 #ifdef XP_UNIX
1340 printf(" --g-fatal-warnings Make all warnings fatal\n"
1341 "\n%s options\n", gAppData->name);
1342 #endif
1344 printf(" -h or -help Print this message.\n"
1345 " -v or -version Print %s version.\n"
1346 " -P <profile> Start with <profile>.\n"
1347 " -migration Start with migration wizard.\n"
1348 " -ProfileManager Start with ProfileManager.\n"
1349 " -no-remote Open new instance, not a new window in running instance.\n"
1350 " -UILocale <locale> Start with <locale> resources as UI Locale.\n"
1351 " -safe-mode Disables extensions and themes for this session.\n", gAppData->name);
1353 #if defined(XP_WIN) || defined(XP_OS2)
1354 printf(" -console Start %s with a debugging console.\n", gAppData->name);
1355 #endif
1357 // this works, but only after the components have registered. so if you drop in a new command line handler, -help
1358 // won't not until the second run.
1359 // out of the bug, because we ship a component.reg file, it works correctly.
1360 DumpArbitraryHelp();
1363 #ifdef DEBUG_warren
1364 #ifdef XP_WIN
1365 #define _CRTDBG_MAP_ALLOC
1366 #include <crtdbg.h>
1367 #endif
1368 #endif
1370 #if defined(FREEBSD)
1371 // pick up fpsetmask prototype.
1372 #include <ieeefp.h>
1373 #endif
1375 static inline void
1376 DumpVersion()
1378 printf("%s %s %s",
1379 gAppData->vendor ? gAppData->vendor : "", gAppData->name, gAppData->version);
1380 if (gAppData->copyright)
1381 printf(", %s", gAppData->copyright);
1382 printf("\n");
1385 #ifdef MOZ_ENABLE_XREMOTE
1386 // use int here instead of a PR type since it will be returned
1387 // from main - just to keep types consistent
1388 static int
1389 HandleRemoteArgument(const char* remote, const char* aDesktopStartupID)
1391 nsresult rv;
1392 ArgResult ar;
1394 const char *profile = 0;
1395 nsCAutoString program(gAppData->name);
1396 ToLowerCase(program);
1397 const char *username = getenv("LOGNAME");
1399 ar = CheckArg("p", PR_FALSE, &profile);
1400 if (ar == ARG_BAD) {
1401 PR_fprintf(PR_STDERR, "Error: argument -p requires a profile name\n");
1402 return 1;
1405 const char *temp = nsnull;
1406 ar = CheckArg("a", PR_FALSE, &temp);
1407 if (ar == ARG_BAD) {
1408 PR_fprintf(PR_STDERR, "Error: argument -a requires an application name\n");
1409 return 1;
1410 } else if (ar == ARG_FOUND) {
1411 program.Assign(temp);
1414 ar = CheckArg("u", PR_FALSE, &username);
1415 if (ar == ARG_BAD) {
1416 PR_fprintf(PR_STDERR, "Error: argument -u requires a username\n");
1417 return 1;
1420 XRemoteClient client;
1421 rv = client.Init();
1422 if (NS_FAILED(rv)) {
1423 PR_fprintf(PR_STDERR, "Error: Failed to connect to X server.\n");
1424 return 1;
1427 nsXPIDLCString response;
1428 PRBool success = PR_FALSE;
1429 rv = client.SendCommand(program.get(), username, profile, remote,
1430 aDesktopStartupID, getter_Copies(response), &success);
1431 // did the command fail?
1432 if (NS_FAILED(rv)) {
1433 PR_fprintf(PR_STDERR, "Error: Failed to send command: %s\n",
1434 response ? response.get() : "No response included");
1435 return 1;
1438 if (!success) {
1439 PR_fprintf(PR_STDERR, "Error: No running window found\n");
1440 return 2;
1443 return 0;
1446 static RemoteResult
1447 RemoteCommandLine(const char* aDesktopStartupID)
1449 nsresult rv;
1450 ArgResult ar;
1452 nsCAutoString program(gAppData->name);
1453 ToLowerCase(program);
1454 const char *username = getenv("LOGNAME");
1456 const char *temp = nsnull;
1457 ar = CheckArg("a", PR_TRUE, &temp);
1458 if (ar == ARG_BAD) {
1459 PR_fprintf(PR_STDERR, "Error: argument -a requires an application name\n");
1460 return REMOTE_ARG_BAD;
1461 } else if (ar == ARG_FOUND) {
1462 program.Assign(temp);
1465 ar = CheckArg("u", PR_TRUE, &username);
1466 if (ar == ARG_BAD) {
1467 PR_fprintf(PR_STDERR, "Error: argument -u requires a username\n");
1468 return REMOTE_ARG_BAD;
1471 XRemoteClient client;
1472 rv = client.Init();
1473 if (NS_FAILED(rv))
1474 return REMOTE_NOT_FOUND;
1476 nsXPIDLCString response;
1477 PRBool success = PR_FALSE;
1478 rv = client.SendCommandLine(program.get(), username, nsnull,
1479 gArgc, gArgv, aDesktopStartupID,
1480 getter_Copies(response), &success);
1481 // did the command fail?
1482 if (NS_FAILED(rv) || !success)
1483 return REMOTE_NOT_FOUND;
1485 return REMOTE_FOUND;
1487 #endif // MOZ_ENABLE_XREMOTE
1489 #ifdef XP_MACOSX
1490 static char const *gBinaryPath;
1491 #endif
1493 nsresult
1494 XRE_GetBinaryPath(const char* argv0, nsILocalFile* *aResult)
1496 nsresult rv;
1497 nsCOMPtr<nsILocalFile> lf;
1499 // We need to use platform-specific hackery to find the
1500 // path of this executable. This is copied, with some modifications, from
1501 // nsGREDirServiceProvider.cpp
1503 #ifdef XP_WIN
1504 PRUnichar exePath[MAXPATHLEN];
1506 if (!::GetModuleFileNameW(0, exePath, MAXPATHLEN))
1507 return NS_ERROR_FAILURE;
1509 rv = NS_NewLocalFile(nsDependentString(exePath), PR_TRUE,
1510 getter_AddRefs(lf));
1511 if (NS_FAILED(rv))
1512 return rv;
1514 #elif defined(XP_MACOSX)
1515 if (gBinaryPath)
1516 return NS_NewNativeLocalFile(nsDependentCString(gBinaryPath), PR_FALSE,
1517 aResult);
1519 NS_NewNativeLocalFile(EmptyCString(), PR_TRUE, getter_AddRefs(lf));
1520 nsCOMPtr<nsILocalFileMac> lfm (do_QueryInterface(lf));
1521 if (!lfm)
1522 return NS_ERROR_FAILURE;
1524 // Works even if we're not bundled.
1525 CFBundleRef appBundle = CFBundleGetMainBundle();
1526 if (!appBundle)
1527 return NS_ERROR_FAILURE;
1529 CFURLRef executableURL = CFBundleCopyExecutableURL(appBundle);
1530 if (!executableURL)
1531 return NS_ERROR_FAILURE;
1532 rv = lfm->InitWithCFURL(executableURL);
1533 CFRelease(executableURL);
1534 if (NS_FAILED(rv))
1535 return rv;
1537 // Callers expect a normalized path.
1538 lfm->Normalize();
1540 #elif defined(XP_UNIX)
1541 struct stat fileStat;
1542 char exePath[MAXPATHLEN];
1543 char tmpPath[MAXPATHLEN];
1545 rv = NS_ERROR_FAILURE;
1547 // on unix, there is no official way to get the path of the current binary.
1548 // instead of using the MOZILLA_FIVE_HOME hack, which doesn't scale to
1549 // multiple applications, we will try a series of techniques:
1551 // 1) look for /proc/<pid>/exe which is a symlink to the executable on newer
1552 // Linux kernels
1553 // 2) use realpath() on argv[0], which works unless we're loaded from the
1554 // PATH
1555 // 3) manually walk through the PATH and look for ourself
1556 // 4) give up
1558 // #ifdef __linux__
1559 // Commented out because it used to not work because it used to not deal
1560 // with readlink not null-terminating the buffer.
1561 #if 0
1562 int r = readlink("/proc/self/exe", exePath, MAXPATHLEN);
1564 if (r > 0 && r < MAXPATHLEN) {
1565 exePath[r] = '\0';
1566 if (stat(exePath, &fileStat) == 0) {
1567 rv = NS_OK;
1571 #endif
1572 if (NS_FAILED(rv) &&
1573 realpath(argv0, exePath) && stat(exePath, &fileStat) == 0) {
1574 rv = NS_OK;
1577 if (NS_FAILED(rv)) {
1578 const char *path = getenv("PATH");
1579 if (!path)
1580 return NS_ERROR_FAILURE;
1582 char *pathdup = strdup(path);
1583 if (!pathdup)
1584 return NS_ERROR_OUT_OF_MEMORY;
1586 PRBool found = PR_FALSE;
1587 char *newStr = pathdup;
1588 char *token;
1589 while ( (token = nsCRT::strtok(newStr, ":", &newStr)) ) {
1590 sprintf(tmpPath, "%s/%s", token, argv0);
1591 if (realpath(tmpPath, exePath) && stat(exePath, &fileStat) == 0) {
1592 found = PR_TRUE;
1593 break;
1596 free(pathdup);
1597 if (!found)
1598 return NS_ERROR_FAILURE;
1601 rv = NS_NewNativeLocalFile(nsDependentCString(exePath), PR_TRUE,
1602 getter_AddRefs(lf));
1603 if (NS_FAILED(rv))
1604 return rv;
1606 #elif defined(XP_OS2)
1607 PPIB ppib;
1608 PTIB ptib;
1609 char exePath[MAXPATHLEN];
1611 DosGetInfoBlocks( &ptib, &ppib);
1612 DosQueryModuleName( ppib->pib_hmte, MAXPATHLEN, exePath);
1613 rv = NS_NewNativeLocalFile(nsDependentCString(exePath), PR_TRUE,
1614 getter_AddRefs(lf));
1615 if (NS_FAILED(rv))
1616 return rv;
1618 #elif defined(XP_BEOS)
1619 int32 cookie = 0;
1620 image_info info;
1622 if(get_next_image_info(0, &cookie, &info) != B_OK)
1623 return NS_ERROR_FAILURE;
1625 rv = NS_NewNativeLocalFile(nsDependentCString(info.name), PR_TRUE,
1626 getter_AddRefs(lf));
1627 if (NS_FAILED(rv))
1628 return rv;
1630 #else
1631 #error Oops, you need platform-specific code here
1632 #endif
1634 NS_ADDREF(*aResult = lf);
1635 return NS_OK;
1638 #define NS_ERROR_LAUNCHED_CHILD_PROCESS NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_PROFILE, 200)
1640 #ifdef XP_WIN
1641 #include "nsWindowsRestart.cpp"
1642 #include <shellapi.h>
1644 typedef BOOL (WINAPI* SetProcessDEPPolicyFunc)(DWORD dwFlags);
1645 #endif
1647 #if defined(XP_OS2) && (__KLIBC__ == 0 && __KLIBC_MINOR__ >= 6) // broken kLibc
1648 // Copy the environment maintained by the C library into an ASCIIZ array
1649 // that can be used to pass it on to the OS/2 Dos* APIs (which otherwise
1650 // don't know anything about the stuff set by PR_SetEnv() or setenv()).
1651 char *createEnv()
1653 // just allocate the maximum amount (24 kB = 0x60000 bytes), to be able to
1654 // copy the existing environment
1655 char *env = (char *)calloc(0x6000, sizeof(char));
1656 if (!env) {
1657 return NULL;
1660 // walk along the environ string array of the C library and copy
1661 // everything (that fits) into the output environment array, leaving
1662 // null bytes between the entries
1663 char *penv = env; // movable pointer to result environment ASCIIZ array
1664 int i = 0, space = 0x6000;
1665 while (environ[i] && environ[i][0]) {
1666 int len = strlen(environ[i]);
1667 if (space - len <= 0) {
1668 break;
1670 strcpy(penv, environ[i]);
1671 i++; // next environment variable
1672 penv += len + 1; // jump to after next null byte
1673 space -= len - 1; // subtract consumed length from usable space
1676 return env;
1679 // OS2LaunchChild() is there to replace _execv() which is broken in the C
1680 // runtime library that comes with GCC 3.3.5 on OS/2. It uses createEnv()
1681 // to copy the process environment and add necessary variables
1683 // returns -1 on failure and 0 on success
1684 int OS2LaunchChild(const char *aExePath, int aArgc, char **aArgv)
1686 // find total length of aArgv
1687 int len = 0;
1688 for (int i = 0; i < aArgc; i++) {
1689 len += strlen(aArgv[i]) + 1; // plus space in between
1691 len++; // leave space for null byte at end
1692 // allocate enough space for all strings and nulls,
1693 // calloc helpfully initializes to null
1694 char *args = (char *)calloc(len, sizeof(char));
1695 if (!args) {
1696 return -1;
1698 char *pargs = args; // extra pointer to after the last argument
1699 // build argument list in the format the DosStartSession() wants,
1700 // adding spaces between the arguments
1701 for (int i = 0; i < aArgc; i++, *pargs++ = ' ') {
1702 strcpy(pargs, aArgv[i]);
1703 pargs += strlen(aArgv[i]);
1705 if (aArgc > 1) {
1706 *(pargs-1) = '\0'; // replace last space
1708 *pargs = '\0';
1709 // make sure that the program is separated by null byte
1710 pargs = strchr(args, ' ');
1711 if (pargs) {
1712 *pargs = '\0';
1715 char *env = createEnv();
1717 char error[CCHMAXPATH] = { 0 };
1718 RESULTCODES crc = { 0 };
1719 ULONG rc = DosExecPgm(error, sizeof(error), EXEC_ASYNC, args, env,
1720 &crc, (PSZ)aExePath);
1721 free(args); // done with the arguments
1722 if (env) {
1723 free(env);
1725 if (rc != NO_ERROR) {
1726 return -1;
1729 return 0;
1731 #endif
1733 // If aBlankCommandLine is true, then the application will be launched with a
1734 // blank command line instead of being launched with the same command line that
1735 // it was initially started with.
1736 static nsresult LaunchChild(nsINativeAppSupport* aNative,
1737 PRBool aBlankCommandLine = PR_FALSE)
1739 aNative->Quit(); // release DDE mutex, if we're holding it
1741 // Restart this process by exec'ing it into the current process
1742 // if supported by the platform. Otherwise, use NSPR.
1744 if (aBlankCommandLine) {
1745 #if defined(MOZ_WIDGET_QT)
1746 // Remove only arguments not given to Qt
1747 gRestartArgc = gQtOnlyArgc;
1748 gRestartArgv = gQtOnlyArgv;
1749 #else
1750 gRestartArgc = 1;
1751 gRestartArgv[gRestartArgc] = nsnull;
1752 #endif
1755 SaveToEnv("MOZ_LAUNCHED_CHILD=1");
1757 #if defined(ANDROID)
1758 mozilla::AndroidBridge::Bridge()->ScheduleRestart();
1759 #else
1760 #if defined(XP_MACOSX)
1761 CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv, PR_TRUE);
1762 PRUint32 restartMode = 0;
1763 #if defined(MOZ_ENABLE_LIBXUL)
1764 restartMode = gRestartMode;
1765 #endif
1766 LaunchChildMac(gRestartArgc, gRestartArgv, restartMode);
1767 #else
1768 nsCOMPtr<nsILocalFile> lf;
1769 nsresult rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf));
1770 if (NS_FAILED(rv))
1771 return rv;
1773 #if defined(XP_WIN)
1774 nsAutoString exePath;
1775 rv = lf->GetPath(exePath);
1776 if (NS_FAILED(rv))
1777 return rv;
1779 if (!WinLaunchChild(exePath.get(), gRestartArgc, gRestartArgv))
1780 return NS_ERROR_FAILURE;
1782 #else
1783 nsCAutoString exePath;
1784 rv = lf->GetNativePath(exePath);
1785 if (NS_FAILED(rv))
1786 return rv;
1788 #if defined(XP_OS2) && (__KLIBC__ == 0 && __KLIBC_MINOR__ >= 6)
1789 // implementation of _execv() is broken with kLibc 0.6.x and later
1790 if (OS2LaunchChild(exePath.get(), gRestartArgc, gRestartArgv) == -1)
1791 return NS_ERROR_FAILURE;
1792 #elif defined(XP_OS2)
1793 if (_execv(exePath.get(), gRestartArgv) == -1)
1794 return NS_ERROR_FAILURE;
1795 #elif defined(XP_UNIX)
1796 if (execv(exePath.get(), gRestartArgv) == -1)
1797 return NS_ERROR_FAILURE;
1798 #elif defined(XP_BEOS)
1799 extern char **environ;
1800 status_t res;
1801 res = resume_thread(load_image(gRestartArgc,(const char **)gRestartArgv,(const char **)environ));
1802 if (res != B_OK)
1803 return NS_ERROR_FAILURE;
1804 #else
1805 PRProcess* process = PR_CreateProcess(exePath.get(), gRestartArgv,
1806 nsnull, nsnull);
1807 if (!process) return NS_ERROR_FAILURE;
1809 PRInt32 exitCode;
1810 PRStatus failed = PR_WaitProcess(process, &exitCode);
1811 if (failed || exitCode)
1812 return NS_ERROR_FAILURE;
1813 #endif // XP_OS2 series
1814 #endif // WP_WIN
1815 #endif // WP_MACOSX
1816 #endif // ANDROID
1818 return NS_ERROR_LAUNCHED_CHILD_PROCESS;
1821 static const char kProfileProperties[] =
1822 "chrome://mozapps/locale/profile/profileSelection.properties";
1824 static nsresult
1825 ProfileLockedDialog(nsILocalFile* aProfileDir, nsILocalFile* aProfileLocalDir,
1826 nsIProfileUnlocker* aUnlocker,
1827 nsINativeAppSupport* aNative, nsIProfileLock* *aResult)
1829 nsresult rv;
1831 ScopedXPCOMStartup xpcom;
1832 rv = xpcom.Initialize();
1833 NS_ENSURE_SUCCESS(rv, rv);
1835 rv = xpcom.SetWindowCreator(aNative);
1836 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
1838 { //extra scoping is needed so we release these components before xpcom shutdown
1839 nsCOMPtr<nsIStringBundleService> sbs =
1840 mozilla::services::GetStringBundleService();
1841 NS_ENSURE_TRUE(sbs, NS_ERROR_FAILURE);
1843 nsCOMPtr<nsIStringBundle> sb;
1844 sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb));
1845 NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE);
1847 NS_ConvertUTF8toUTF16 appName(gAppData->name);
1848 const PRUnichar* params[] = {appName.get(), appName.get()};
1850 nsXPIDLString killMessage;
1851 #ifndef XP_MACOSX
1852 static const PRUnichar kRestartNoUnlocker[] = {'r','e','s','t','a','r','t','M','e','s','s','a','g','e','N','o','U','n','l','o','c','k','e','r','\0'}; // "restartMessageNoUnlocker"
1853 static const PRUnichar kRestartUnlocker[] = {'r','e','s','t','a','r','t','M','e','s','s','a','g','e','U','n','l','o','c','k','e','r','\0'}; // "restartMessageUnlocker"
1854 #else
1855 static const PRUnichar kRestartNoUnlocker[] = {'r','e','s','t','a','r','t','M','e','s','s','a','g','e','N','o','U','n','l','o','c','k','e','r','M','a','c','\0'}; // "restartMessageNoUnlockerMac"
1856 static const PRUnichar kRestartUnlocker[] = {'r','e','s','t','a','r','t','M','e','s','s','a','g','e','U','n','l','o','c','k','e','r','M','a','c','\0'}; // "restartMessageUnlockerMac"
1857 #endif
1859 sb->FormatStringFromName(aUnlocker ? kRestartUnlocker : kRestartNoUnlocker,
1860 params, 2, getter_Copies(killMessage));
1862 nsXPIDLString killTitle;
1863 sb->FormatStringFromName(NS_LITERAL_STRING("restartTitle").get(),
1864 params, 1, getter_Copies(killTitle));
1866 if (!killMessage || !killTitle)
1867 return NS_ERROR_FAILURE;
1869 nsCOMPtr<nsIPromptService> ps
1870 (do_GetService(NS_PROMPTSERVICE_CONTRACTID));
1871 NS_ENSURE_TRUE(ps, NS_ERROR_FAILURE);
1873 PRUint32 flags = nsIPromptService::BUTTON_TITLE_OK * nsIPromptService::BUTTON_POS_0;
1875 if (aUnlocker) {
1876 flags =
1877 nsIPromptService::BUTTON_TITLE_CANCEL * nsIPromptService::BUTTON_POS_0 +
1878 nsIPromptService::BUTTON_TITLE_IS_STRING * nsIPromptService::BUTTON_POS_1 +
1879 nsIPromptService::BUTTON_POS_1_DEFAULT;
1882 PRInt32 button;
1883 PRBool checkState;
1884 rv = ps->ConfirmEx(nsnull, killTitle, killMessage, flags,
1885 killTitle, nsnull, nsnull, nsnull, &checkState, &button);
1886 NS_ENSURE_SUCCESS_LOG(rv, rv);
1888 if (button == 1 && aUnlocker) {
1889 rv = aUnlocker->Unlock(nsIProfileUnlocker::FORCE_QUIT);
1890 if (NS_FAILED(rv)) return rv;
1892 return NS_LockProfilePath(aProfileDir, aProfileLocalDir, nsnull, aResult);
1895 return NS_ERROR_ABORT;
1899 static nsresult
1900 ProfileMissingDialog(nsINativeAppSupport* aNative)
1902 nsresult rv;
1904 ScopedXPCOMStartup xpcom;
1905 rv = xpcom.Initialize();
1906 NS_ENSURE_SUCCESS(rv, rv);
1908 rv = xpcom.SetWindowCreator(aNative);
1909 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
1911 { //extra scoping is needed so we release these components before xpcom shutdown
1912 nsCOMPtr<nsIStringBundleService> sbs =
1913 mozilla::services::GetStringBundleService();
1914 NS_ENSURE_TRUE(sbs, NS_ERROR_FAILURE);
1916 nsCOMPtr<nsIStringBundle> sb;
1917 sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb));
1918 NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE);
1920 NS_ConvertUTF8toUTF16 appName(gAppData->name);
1921 const PRUnichar* params[] = {appName.get(), appName.get()};
1923 nsXPIDLString missingMessage;
1925 // profileMissing
1926 static const PRUnichar kMissing[] = {'p','r','o','f','i','l','e','M','i','s','s','i','n','g','\0'};
1927 sb->FormatStringFromName(kMissing, params, 2, getter_Copies(missingMessage));
1929 nsXPIDLString missingTitle;
1930 sb->FormatStringFromName(NS_LITERAL_STRING("profileMissingTitle").get(),
1931 params, 1, getter_Copies(missingTitle));
1933 if (missingMessage && missingTitle) {
1934 nsCOMPtr<nsIPromptService> ps
1935 (do_GetService(NS_PROMPTSERVICE_CONTRACTID));
1936 NS_ENSURE_TRUE(ps, NS_ERROR_FAILURE);
1938 ps->Alert(nsnull, missingTitle, missingMessage);
1941 return NS_ERROR_ABORT;
1945 static const char kProfileManagerURL[] =
1946 "chrome://mozapps/content/profile/profileSelection.xul";
1948 static nsresult
1949 ShowProfileManager(nsIToolkitProfileService* aProfileSvc,
1950 nsINativeAppSupport* aNative)
1952 nsresult rv;
1954 nsCOMPtr<nsILocalFile> profD, profLD;
1955 PRUnichar* profileNamePtr;
1956 nsCAutoString profileName;
1959 ScopedXPCOMStartup xpcom;
1960 rv = xpcom.Initialize();
1961 NS_ENSURE_SUCCESS(rv, rv);
1963 rv = xpcom.SetWindowCreator(aNative);
1964 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
1966 #ifdef XP_MACOSX
1967 CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv, PR_TRUE);
1968 #endif
1970 #ifdef XP_WIN
1971 // we don't have to wait here because profile manager window will pump
1972 // and DDE message will be handled
1973 ProcessDDE(aNative, PR_FALSE);
1974 #endif
1976 { //extra scoping is needed so we release these components before xpcom shutdown
1977 nsCOMPtr<nsIWindowWatcher> windowWatcher
1978 (do_GetService(NS_WINDOWWATCHER_CONTRACTID));
1979 nsCOMPtr<nsIDialogParamBlock> ioParamBlock
1980 (do_CreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID));
1981 nsCOMPtr<nsIMutableArray> dlgArray (do_CreateInstance(NS_ARRAY_CONTRACTID));
1982 NS_ENSURE_TRUE(windowWatcher && ioParamBlock && dlgArray, NS_ERROR_FAILURE);
1984 ioParamBlock->SetObjects(dlgArray);
1986 nsCOMPtr<nsIAppStartup> appStartup
1987 (do_GetService(NS_APPSTARTUP_CONTRACTID));
1988 NS_ENSURE_TRUE(appStartup, NS_ERROR_FAILURE);
1990 nsCOMPtr<nsIDOMWindow> newWindow;
1991 rv = windowWatcher->OpenWindow(nsnull,
1992 kProfileManagerURL,
1993 "_blank",
1994 "centerscreen,chrome,modal,titlebar",
1995 ioParamBlock,
1996 getter_AddRefs(newWindow));
1998 NS_ENSURE_SUCCESS_LOG(rv, rv);
2000 aProfileSvc->Flush();
2002 PRInt32 dialogConfirmed;
2003 rv = ioParamBlock->GetInt(0, &dialogConfirmed);
2004 if (NS_FAILED(rv) || dialogConfirmed == 0) return NS_ERROR_ABORT;
2006 nsCOMPtr<nsIProfileLock> lock;
2007 rv = dlgArray->QueryElementAt(0, NS_GET_IID(nsIProfileLock),
2008 getter_AddRefs(lock));
2009 NS_ENSURE_SUCCESS_LOG(rv, rv);
2011 rv = lock->GetDirectory(getter_AddRefs(profD));
2012 NS_ENSURE_SUCCESS(rv, rv);
2014 rv = lock->GetLocalDirectory(getter_AddRefs(profLD));
2015 NS_ENSURE_SUCCESS(rv, rv);
2017 rv = ioParamBlock->GetString(0, &profileNamePtr);
2018 NS_ENSURE_SUCCESS(rv, rv);
2020 CopyUTF16toUTF8(profileNamePtr, profileName);
2021 NS_Free(profileNamePtr);
2023 lock->Unlock();
2027 SaveFileToEnv("XRE_PROFILE_PATH", profD);
2028 SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", profLD);
2029 SaveWordToEnv("XRE_PROFILE_NAME", profileName);
2031 PRBool offline = PR_FALSE;
2032 aProfileSvc->GetStartOffline(&offline);
2033 if (offline) {
2034 SaveToEnv("XRE_START_OFFLINE=1");
2037 return LaunchChild(aNative);
2040 static nsresult
2041 ImportProfiles(nsIToolkitProfileService* aPService,
2042 nsINativeAppSupport* aNative)
2044 nsresult rv;
2046 SaveToEnv("XRE_IMPORT_PROFILES=1");
2048 // try to import old-style profiles
2049 { // scope XPCOM
2050 ScopedXPCOMStartup xpcom;
2051 rv = xpcom.Initialize();
2052 if (NS_SUCCEEDED(rv)) {
2053 #ifdef XP_MACOSX
2054 CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv, PR_TRUE);
2055 #endif
2057 nsCOMPtr<nsIProfileMigrator> migrator
2058 (do_GetService(NS_PROFILEMIGRATOR_CONTRACTID));
2059 if (migrator) {
2060 migrator->Import();
2065 aPService->Flush();
2066 return LaunchChild(aNative);
2069 // Pick a profile. We need to end up with a profile lock.
2071 // 1) check for -profile <path>
2072 // 2) check for -P <name>
2073 // 3) check for -ProfileManager
2074 // 4) use the default profile, if there is one
2075 // 5) if there are *no* profiles, set up profile-migration
2076 // 6) display the profile-manager UI
2078 static PRBool gDoMigration = PR_FALSE;
2080 static nsresult
2081 SelectProfile(nsIProfileLock* *aResult, nsINativeAppSupport* aNative,
2082 PRBool* aStartOffline, nsACString* aProfileName)
2084 nsresult rv;
2085 ArgResult ar;
2086 const char* arg;
2087 *aResult = nsnull;
2088 *aStartOffline = PR_FALSE;
2090 ar = CheckArg("offline", PR_TRUE);
2091 if (ar == ARG_BAD) {
2092 PR_fprintf(PR_STDERR, "Error: argument -offline is invalid when argument -osint is specified\n");
2093 return NS_ERROR_FAILURE;
2096 arg = PR_GetEnv("XRE_START_OFFLINE");
2097 if ((arg && *arg) || ar)
2098 *aStartOffline = PR_TRUE;
2101 nsCOMPtr<nsILocalFile> lf = GetFileFromEnv("XRE_PROFILE_PATH");
2102 if (lf) {
2103 nsCOMPtr<nsILocalFile> localDir =
2104 GetFileFromEnv("XRE_PROFILE_LOCAL_PATH");
2105 if (!localDir) {
2106 localDir = lf;
2109 arg = PR_GetEnv("XRE_PROFILE_NAME");
2110 if (arg && *arg && aProfileName)
2111 aProfileName->Assign(nsDependentCString(arg));
2113 // Clear out flags that we handled (or should have handled!) last startup.
2114 const char *dummy;
2115 CheckArg("p", PR_FALSE, &dummy);
2116 CheckArg("profile", PR_FALSE, &dummy);
2117 CheckArg("profilemanager");
2119 return NS_LockProfilePath(lf, localDir, nsnull, aResult);
2122 ar = CheckArg("migration", PR_TRUE);
2123 if (ar == ARG_BAD) {
2124 PR_fprintf(PR_STDERR, "Error: argument -migration is invalid when argument -osint is specified\n");
2125 return NS_ERROR_FAILURE;
2126 } else if (ar == ARG_FOUND) {
2127 gDoMigration = PR_TRUE;
2130 ar = CheckArg("profile", PR_TRUE, &arg);
2131 if (ar == ARG_BAD) {
2132 PR_fprintf(PR_STDERR, "Error: argument -profile requires a path\n");
2133 return NS_ERROR_FAILURE;
2135 if (ar) {
2136 nsCOMPtr<nsILocalFile> lf;
2137 rv = XRE_GetFileFromPath(arg, getter_AddRefs(lf));
2138 NS_ENSURE_SUCCESS(rv, rv);
2140 nsCOMPtr<nsIProfileUnlocker> unlocker;
2142 // Check if the profile path exists and it's a directory.
2143 PRBool exists;
2144 lf->Exists(&exists);
2145 if (!exists) {
2146 rv = lf->Create(nsIFile::DIRECTORY_TYPE, 0700);
2147 NS_ENSURE_SUCCESS(rv, rv);
2150 // If a profile path is specified directory on the command line, then
2151 // assume that the temp directory is the same as the given directory.
2152 rv = NS_LockProfilePath(lf, lf, getter_AddRefs(unlocker), aResult);
2153 if (NS_SUCCEEDED(rv))
2154 return rv;
2156 return ProfileLockedDialog(lf, lf, unlocker, aNative, aResult);
2159 nsCOMPtr<nsIToolkitProfileService> profileSvc;
2160 rv = NS_NewToolkitProfileService(getter_AddRefs(profileSvc));
2161 if (rv == NS_ERROR_FILE_ACCESS_DENIED)
2162 PR_fprintf(PR_STDERR, "Error: Access was denied while trying to open files in " \
2163 "your profile directory.\n");
2164 NS_ENSURE_SUCCESS(rv, rv);
2166 ar = CheckArg("createprofile", PR_TRUE, &arg);
2167 if (ar == ARG_BAD) {
2168 PR_fprintf(PR_STDERR, "Error: argument -createprofile requires a profile name\n");
2169 return NS_ERROR_FAILURE;
2171 if (ar) {
2172 nsCOMPtr<nsIToolkitProfile> profile;
2174 const char* delim = strchr(arg, ' ');
2175 if (delim) {
2176 nsCOMPtr<nsILocalFile> lf;
2177 rv = NS_NewNativeLocalFile(nsDependentCString(delim + 1),
2178 PR_TRUE, getter_AddRefs(lf));
2179 if (NS_FAILED(rv)) {
2180 PR_fprintf(PR_STDERR, "Error: profile path not valid.\n");
2181 return rv;
2184 // As with -profile, assume that the given path will be used for both the
2185 // main profile directory and the temp profile directory.
2186 rv = profileSvc->CreateProfile(lf, lf, nsDependentCSubstring(arg, delim),
2187 getter_AddRefs(profile));
2188 } else {
2189 rv = profileSvc->CreateProfile(nsnull, nsnull, nsDependentCString(arg),
2190 getter_AddRefs(profile));
2192 // Some pathological arguments can make it this far
2193 if (NS_FAILED(rv)) {
2194 PR_fprintf(PR_STDERR, "Error creating profile.\n");
2195 return rv;
2197 rv = NS_ERROR_ABORT;
2198 profileSvc->Flush();
2200 // XXXben need to ensure prefs.js exists here so the tinderboxes will
2201 // not go orange.
2202 nsCOMPtr<nsILocalFile> prefsJSFile;
2203 profile->GetRootDir(getter_AddRefs(prefsJSFile));
2204 prefsJSFile->AppendNative(NS_LITERAL_CSTRING("prefs.js"));
2205 nsCAutoString pathStr;
2206 prefsJSFile->GetNativePath(pathStr);
2207 PR_fprintf(PR_STDERR, "Success: created profile '%s' at '%s'\n", arg, pathStr.get());
2208 PRBool exists;
2209 prefsJSFile->Exists(&exists);
2210 if (!exists)
2211 prefsJSFile->Create(nsIFile::NORMAL_FILE_TYPE, 0644);
2212 // XXXdarin perhaps 0600 would be better?
2214 return rv;
2217 PRUint32 count;
2218 rv = profileSvc->GetProfileCount(&count);
2219 NS_ENSURE_SUCCESS(rv, rv);
2221 if (gAppData->flags & NS_XRE_ENABLE_PROFILE_MIGRATOR) {
2222 arg = PR_GetEnv("XRE_IMPORT_PROFILES");
2223 if (!count && (!arg || !*arg)) {
2224 return ImportProfiles(profileSvc, aNative);
2228 ar = CheckArg("p", PR_FALSE, &arg);
2229 if (ar == ARG_BAD) {
2230 ar = CheckArg("osint");
2231 if (ar == ARG_FOUND) {
2232 PR_fprintf(PR_STDERR, "Error: argument -p is invalid when argument -osint is specified\n");
2233 return NS_ERROR_FAILURE;
2235 return ShowProfileManager(profileSvc, aNative);
2237 if (ar) {
2238 ar = CheckArg("osint");
2239 if (ar == ARG_FOUND) {
2240 PR_fprintf(PR_STDERR, "Error: argument -p is invalid when argument -osint is specified\n");
2241 return NS_ERROR_FAILURE;
2243 nsCOMPtr<nsIToolkitProfile> profile;
2244 rv = profileSvc->GetProfileByName(nsDependentCString(arg),
2245 getter_AddRefs(profile));
2246 if (NS_SUCCEEDED(rv)) {
2247 nsCOMPtr<nsIProfileUnlocker> unlocker;
2248 rv = profile->Lock(nsnull, aResult);
2249 if (NS_SUCCEEDED(rv)) {
2250 if (aProfileName)
2251 aProfileName->Assign(nsDependentCString(arg));
2252 return NS_OK;
2255 nsCOMPtr<nsILocalFile> profileDir;
2256 rv = profile->GetRootDir(getter_AddRefs(profileDir));
2257 NS_ENSURE_SUCCESS(rv, rv);
2259 nsCOMPtr<nsILocalFile> profileLocalDir;
2260 rv = profile->GetLocalDir(getter_AddRefs(profileLocalDir));
2261 NS_ENSURE_SUCCESS(rv, rv);
2263 return ProfileLockedDialog(profileDir, profileLocalDir, unlocker,
2264 aNative, aResult);
2267 return ShowProfileManager(profileSvc, aNative);
2270 ar = CheckArg("profilemanager", PR_TRUE);
2271 if (ar == ARG_BAD) {
2272 PR_fprintf(PR_STDERR, "Error: argument -profilemanager is invalid when argument -osint is specified\n");
2273 return NS_ERROR_FAILURE;
2274 } else if (ar == ARG_FOUND) {
2275 return ShowProfileManager(profileSvc, aNative);
2278 if (!count) {
2279 gDoMigration = PR_TRUE;
2281 // create a default profile
2282 nsCOMPtr<nsIToolkitProfile> profile;
2283 nsresult rv = profileSvc->CreateProfile(nsnull, // choose a default dir for us
2284 nsnull, // choose a default dir for us
2285 NS_LITERAL_CSTRING("default"),
2286 getter_AddRefs(profile));
2287 if (NS_SUCCEEDED(rv)) {
2288 profileSvc->Flush();
2289 rv = profile->Lock(nsnull, aResult);
2290 if (NS_SUCCEEDED(rv)) {
2291 if (aProfileName)
2292 aProfileName->Assign(NS_LITERAL_CSTRING("default"));
2293 return NS_OK;
2298 PRBool useDefault = PR_TRUE;
2299 if (count > 1)
2300 profileSvc->GetStartWithLastProfile(&useDefault);
2302 if (useDefault) {
2303 nsCOMPtr<nsIToolkitProfile> profile;
2304 // GetSelectedProfile will auto-select the only profile if there's just one
2305 profileSvc->GetSelectedProfile(getter_AddRefs(profile));
2306 if (profile) {
2307 nsCOMPtr<nsIProfileUnlocker> unlocker;
2308 rv = profile->Lock(getter_AddRefs(unlocker), aResult);
2309 if (NS_SUCCEEDED(rv)) {
2310 // Try to grab the profile name.
2311 if (aProfileName) {
2312 rv = profile->GetName(*aProfileName);
2313 if (NS_FAILED(rv))
2314 aProfileName->Truncate(0);
2316 return NS_OK;
2319 nsCOMPtr<nsILocalFile> profileDir;
2320 rv = profile->GetRootDir(getter_AddRefs(profileDir));
2321 NS_ENSURE_SUCCESS(rv, rv);
2323 nsCOMPtr<nsILocalFile> profileLocalDir;
2324 rv = profile->GetRootDir(getter_AddRefs(profileLocalDir));
2325 NS_ENSURE_SUCCESS(rv, rv);
2327 return ProfileLockedDialog(profileDir, profileLocalDir, unlocker,
2328 aNative, aResult);
2332 return ShowProfileManager(profileSvc, aNative);
2335 /**
2336 * Checks the compatibility.ini file to see if we have updated our application
2337 * or otherwise invalidated our caches. If the application has been updated,
2338 * we return PR_FALSE; otherwise, we return PR_TRUE. We also write the status
2339 * of the caches (valid/invalid) into the return param aCachesOK. The aCachesOK
2340 * is always invalid if the application has been updated.
2342 static PRBool
2343 CheckCompatibility(nsIFile* aProfileDir, const nsCString& aVersion,
2344 const nsCString& aOSABI, nsIFile* aXULRunnerDir,
2345 nsIFile* aAppDir, nsILocalFile* aFlagFile,
2346 PRBool* aCachesOK)
2348 *aCachesOK = PR_FALSE;
2349 nsCOMPtr<nsIFile> file;
2350 aProfileDir->Clone(getter_AddRefs(file));
2351 if (!file)
2352 return PR_FALSE;
2353 file->AppendNative(FILE_COMPATIBILITY_INFO);
2355 nsINIParser parser;
2356 nsCOMPtr<nsILocalFile> localFile(do_QueryInterface(file));
2357 nsresult rv = parser.Init(localFile);
2358 if (NS_FAILED(rv))
2359 return PR_FALSE;
2361 nsCAutoString buf;
2362 rv = parser.GetString("Compatibility", "LastVersion", buf);
2363 if (NS_FAILED(rv) || !aVersion.Equals(buf))
2364 return PR_FALSE;
2366 rv = parser.GetString("Compatibility", "LastOSABI", buf);
2367 if (NS_FAILED(rv) || !aOSABI.Equals(buf))
2368 return PR_FALSE;
2370 rv = parser.GetString("Compatibility", "LastPlatformDir", buf);
2371 if (NS_FAILED(rv))
2372 return PR_FALSE;
2374 nsCOMPtr<nsILocalFile> lf;
2375 rv = NS_NewNativeLocalFile(buf, PR_FALSE,
2376 getter_AddRefs(lf));
2377 if (NS_FAILED(rv))
2378 return PR_FALSE;
2380 PRBool eq;
2381 rv = lf->Equals(aXULRunnerDir, &eq);
2382 if (NS_FAILED(rv) || !eq)
2383 return PR_FALSE;
2385 if (aAppDir) {
2386 rv = parser.GetString("Compatibility", "LastAppDir", buf);
2387 if (NS_FAILED(rv))
2388 return PR_FALSE;
2390 rv = NS_NewNativeLocalFile(buf, PR_FALSE,
2391 getter_AddRefs(lf));
2392 if (NS_FAILED(rv))
2393 return PR_FALSE;
2395 rv = lf->Equals(aAppDir, &eq);
2396 if (NS_FAILED(rv) || !eq)
2397 return PR_FALSE;
2400 // If we see this flag, caches are invalid.
2401 rv = parser.GetString("Compatibility", "InvalidateCaches", buf);
2402 *aCachesOK = (NS_FAILED(rv) || !buf.EqualsLiteral("1"));
2404 PRBool purgeCaches = PR_FALSE;
2405 if (aFlagFile) {
2406 aFlagFile->Exists(&purgeCaches);
2409 *aCachesOK = !purgeCaches && *aCachesOK;
2410 return PR_TRUE;
2413 static void BuildVersion(nsCString &aBuf)
2415 aBuf.Assign(gAppData->version);
2416 aBuf.Append('_');
2417 aBuf.Append(gAppData->buildID);
2418 aBuf.Append('/');
2419 aBuf.Append(gToolkitBuildID);
2422 static void
2423 WriteVersion(nsIFile* aProfileDir, const nsCString& aVersion,
2424 const nsCString& aOSABI, nsIFile* aXULRunnerDir,
2425 nsIFile* aAppDir)
2427 nsCOMPtr<nsIFile> file;
2428 aProfileDir->Clone(getter_AddRefs(file));
2429 if (!file)
2430 return;
2431 file->AppendNative(FILE_COMPATIBILITY_INFO);
2433 nsCOMPtr<nsILocalFile> lf = do_QueryInterface(file);
2435 nsCAutoString platformDir;
2436 aXULRunnerDir->GetNativePath(platformDir);
2438 nsCAutoString appDir;
2439 if (aAppDir)
2440 aAppDir->GetNativePath(appDir);
2442 PRFileDesc *fd = nsnull;
2443 lf->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0600, &fd);
2444 if (!fd) {
2445 NS_ERROR("could not create output stream");
2446 return;
2449 static const char kHeader[] = "[Compatibility]" NS_LINEBREAK
2450 "LastVersion=";
2452 PR_Write(fd, kHeader, sizeof(kHeader) - 1);
2453 PR_Write(fd, aVersion.get(), aVersion.Length());
2455 static const char kOSABIHeader[] = NS_LINEBREAK "LastOSABI=";
2456 PR_Write(fd, kOSABIHeader, sizeof(kOSABIHeader) - 1);
2457 PR_Write(fd, aOSABI.get(), aOSABI.Length());
2459 static const char kPlatformDirHeader[] = NS_LINEBREAK "LastPlatformDir=";
2461 PR_Write(fd, kPlatformDirHeader, sizeof(kPlatformDirHeader) - 1);
2462 PR_Write(fd, platformDir.get(), platformDir.Length());
2464 static const char kAppDirHeader[] = NS_LINEBREAK "LastAppDir=";
2465 if (aAppDir) {
2466 PR_Write(fd, kAppDirHeader, sizeof(kAppDirHeader) - 1);
2467 PR_Write(fd, appDir.get(), appDir.Length());
2470 static const char kNL[] = NS_LINEBREAK;
2471 PR_Write(fd, kNL, sizeof(kNL) - 1);
2473 PR_Close(fd);
2476 static void RemoveComponentRegistries(nsIFile* aProfileDir, nsIFile* aLocalProfileDir,
2477 PRBool aRemoveEMFiles)
2479 nsCOMPtr<nsIFile> file;
2480 aProfileDir->Clone(getter_AddRefs(file));
2481 if (!file)
2482 return;
2484 if (aRemoveEMFiles) {
2485 file->SetNativeLeafName(NS_LITERAL_CSTRING("extensions.ini"));
2486 file->Remove(PR_FALSE);
2489 aLocalProfileDir->Clone(getter_AddRefs(file));
2490 if (!file)
2491 return;
2493 file->AppendNative(NS_LITERAL_CSTRING("XUL" PLATFORM_FASL_SUFFIX));
2494 file->Remove(PR_FALSE);
2496 file->SetNativeLeafName(NS_LITERAL_CSTRING("XPC" PLATFORM_FASL_SUFFIX));
2497 file->Remove(PR_FALSE);
2499 file->SetNativeLeafName(NS_LITERAL_CSTRING("startupCache"));
2500 file->Remove(PR_TRUE);
2503 // To support application initiated restart via nsIAppStartup.quit, we
2504 // need to save various environment variables, and then restore them
2505 // before re-launching the application.
2507 static struct {
2508 const char *name;
2509 char *value;
2510 } gSavedVars[] = {
2511 {"XUL_APP_FILE", nsnull}
2514 static void SaveStateForAppInitiatedRestart()
2516 for (size_t i = 0; i < NS_ARRAY_LENGTH(gSavedVars); ++i) {
2517 const char *s = PR_GetEnv(gSavedVars[i].name);
2518 if (s)
2519 gSavedVars[i].value = PR_smprintf("%s=%s", gSavedVars[i].name, s);
2523 static void RestoreStateForAppInitiatedRestart()
2525 for (size_t i = 0; i < NS_ARRAY_LENGTH(gSavedVars); ++i) {
2526 if (gSavedVars[i].value)
2527 PR_SetEnv(gSavedVars[i].value);
2531 #ifdef MOZ_CRASHREPORTER
2532 // When we first initialize the crash reporter we don't have a profile,
2533 // so we set the minidump path to $TEMP. Once we have a profile,
2534 // we set it to $PROFILE/minidumps, creating the directory
2535 // if needed.
2536 static void MakeOrSetMinidumpPath(nsIFile* profD)
2538 nsCOMPtr<nsIFile> dumpD;
2539 nsresult rv = profD->Clone(getter_AddRefs(dumpD));
2541 if(dumpD) {
2542 PRBool fileExists;
2543 //XXX: do some more error checking here
2544 dumpD->Append(NS_LITERAL_STRING("minidumps"));
2545 rv = dumpD->Exists(&fileExists);
2546 if(!fileExists) {
2547 dumpD->Create(nsIFile::DIRECTORY_TYPE, 0700);
2550 nsAutoString pathStr;
2551 if(NS_SUCCEEDED(dumpD->GetPath(pathStr)))
2552 CrashReporter::SetMinidumpPath(pathStr);
2555 #endif
2557 const nsXREAppData* gAppData = nsnull;
2559 #if defined(XP_OS2)
2560 // because we use early returns, we use a stack-based helper to un-set the OS2 FP handler
2561 class ScopedFPHandler {
2562 private:
2563 EXCEPTIONREGISTRATIONRECORD excpreg;
2565 public:
2566 ScopedFPHandler() { PR_OS2_SetFloatExcpHandler(&excpreg); }
2567 ~ScopedFPHandler() { PR_OS2_UnsetFloatExcpHandler(&excpreg); }
2569 #endif
2571 #ifdef MOZ_WIDGET_GTK2
2572 #include "prlink.h"
2573 typedef void (*_g_set_application_name_fn)(const gchar *application_name);
2574 typedef void (*_gtk_window_set_auto_startup_notification_fn)(gboolean setting);
2576 static PRFuncPtr FindFunction(const char* aName)
2578 PRLibrary *lib = nsnull;
2579 PRFuncPtr result = PR_FindFunctionSymbolAndLibrary(aName, &lib);
2580 // Since the library was already loaded, we can safely unload it here.
2581 if (lib) {
2582 PR_UnloadLibrary(lib);
2584 return result;
2587 static nsIWidget* GetMainWidget(nsIDOMWindow* aWindow)
2589 // get the native window for this instance
2590 nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(aWindow));
2591 NS_ENSURE_TRUE(window, nsnull);
2593 nsCOMPtr<nsIBaseWindow> baseWindow
2594 (do_QueryInterface(window->GetDocShell()));
2595 NS_ENSURE_TRUE(baseWindow, nsnull);
2597 nsCOMPtr<nsIWidget> mainWidget;
2598 baseWindow->GetMainWidget(getter_AddRefs(mainWidget));
2599 return mainWidget;
2602 static nsGTKToolkit* GetGTKToolkit()
2604 nsCOMPtr<nsIAppShellService> svc = do_GetService(NS_APPSHELLSERVICE_CONTRACTID);
2605 if (!svc)
2606 return nsnull;
2607 nsCOMPtr<nsIDOMWindowInternal> window;
2608 svc->GetHiddenDOMWindow(getter_AddRefs(window));
2609 if (!window)
2610 return nsnull;
2611 nsIWidget* widget = GetMainWidget(window);
2612 if (!widget)
2613 return nsnull;
2614 nsIToolkit* toolkit = widget->GetToolkit();
2615 if (!toolkit)
2616 return nsnull;
2617 return static_cast<nsGTKToolkit*>(toolkit);
2620 static void MOZ_gdk_display_close(GdkDisplay *display)
2622 // XXX wallpaper for bug 417163: don't close the Display if we're using the
2623 // Qt theme because we crash (in Qt code) when using jemalloc.
2624 PRBool theme_is_qt = PR_FALSE;
2625 GtkSettings* settings =
2626 gtk_settings_get_for_screen(gdk_display_get_default_screen(display));
2627 gchar *theme_name;
2628 g_object_get(settings, "gtk-theme-name", &theme_name, NULL);
2629 if (theme_name) {
2630 theme_is_qt = strcmp(theme_name, "Qt") == 0;
2631 if (theme_is_qt)
2632 NS_WARNING("wallpaper bug 417163 for Qt theme");
2633 g_free(theme_name);
2636 // gdk_display_close was broken prior to gtk+-2.10.0.
2637 // (http://bugzilla.gnome.org/show_bug.cgi?id=85715)
2638 // gdk_display_manager_set_default_display (gdk_display_manager_get(), NULL)
2639 // was also broken.
2640 if (gtk_check_version(2,10,0) != NULL) {
2641 #ifdef MOZ_X11
2642 // Version check failed - broken gdk_display_close.
2644 // Let the gdk structures leak but at least close the Display,
2645 // assuming that gdk will not use it again.
2646 Display* dpy = GDK_DISPLAY_XDISPLAY(display);
2647 if (!theme_is_qt)
2648 XCloseDisplay(dpy);
2649 #else
2650 gdk_display_close(display);
2651 #endif /* MOZ_X11 */
2653 else {
2654 #if CLEANUP_MEMORY
2655 // Get a (new) Pango context that holds a reference to the fontmap that
2656 // GTK has been using. gdk_pango_context_get() must be called while GTK
2657 // has a default display.
2658 PangoContext *pangoContext = gdk_pango_context_get();
2659 #endif
2661 PRBool buggyCairoShutdown = cairo_version() < CAIRO_VERSION_ENCODE(1, 4, 0);
2663 if (!buggyCairoShutdown) {
2664 // We should shut down GDK before we shut down libraries it depends on
2665 // like Pango and cairo. But if cairo shutdown is buggy, we should
2666 // shut down cairo first otherwise it may crash because of dangling
2667 // references to Display objects (see bug 469831).
2668 if (!theme_is_qt)
2669 gdk_display_close(display);
2672 #if CLEANUP_MEMORY
2673 // This doesn't take a reference.
2674 PangoFontMap *fontmap = pango_context_get_font_map(pangoContext);
2675 // Do some shutdown of the fontmap, which releases the fonts, clearing a
2676 // bunch of circular references from the fontmap through the fonts back to
2677 // itself. The shutdown that this does is much less than what's done by
2678 // the fontmap's finalize, though.
2679 if (PANGO_IS_FC_FONT_MAP(fontmap))
2680 pango_fc_font_map_shutdown(PANGO_FC_FONT_MAP(fontmap));
2681 g_object_unref(pangoContext);
2682 // PangoCairo still holds a reference to the fontmap.
2683 // Now that we have finished with GTK and Pango, we could unref fontmap,
2684 // which would allow us to call FcFini, but removing what is really
2685 // Pango's ref feels a bit evil. Pango-1.22 will have support for
2686 // pango_cairo_font_map_set_default(NULL), which would release the
2687 // reference on the old fontmap.
2689 #if GTK_CHECK_VERSION(2,8,0)
2690 // cairo_debug_reset_static_data() is prototyped through cairo.h included
2691 // by gtk.h.
2692 #ifdef cairo_debug_reset_static_data
2693 #error "Looks like we're including Mozilla's cairo instead of system cairo"
2694 #endif
2695 cairo_debug_reset_static_data();
2696 #endif // 2.8.0
2697 #endif // CLEANUP_MEMORY
2699 if (buggyCairoShutdown) {
2700 if (!theme_is_qt)
2701 gdk_display_close(display);
2705 #endif // MOZ_WIDGET_GTK2
2707 /**
2708 * NSPR will search for the "nspr_use_zone_allocator" symbol throughout
2709 * the process and use it to determine whether the application defines its own
2710 * memory allocator or not.
2712 * Since most applications (e.g. Firefox and Thunderbird) don't use any special
2713 * allocators and therefore don't define this symbol, NSPR must search the
2714 * entire process, which reduces startup performance.
2716 * By defining the symbol here, we can avoid the wasted lookup and hopefully
2717 * improve startup performance.
2719 NS_VISIBILITY_DEFAULT PRBool nspr_use_zone_allocator = PR_FALSE;
2721 #ifdef MOZ_SPLASHSCREEN
2722 #define MOZ_SPLASHSCREEN_UPDATE(_i) do { if (splashScreen) splashScreen->Update(_i); } while(0)
2723 #else
2724 #define MOZ_SPLASHSCREEN_UPDATE(_i) do { } while(0)
2725 #endif
2727 #ifdef CAIRO_HAS_DWRITE_FONT
2729 #include <dwrite.h>
2731 typedef HRESULT (WINAPI*DWriteCreateFactoryFunc)(
2732 __in DWRITE_FACTORY_TYPE factoryType,
2733 __in REFIID iid,
2734 __out IUnknown **factory
2737 #ifdef DEBUG_DWRITE_STARTUP
2739 #define LOGREGISTRY(msg) LogRegistryEvent(msg)
2741 // for use when monitoring process
2742 static void LogRegistryEvent(const wchar_t *msg)
2744 HKEY dummyKey;
2745 HRESULT hr;
2746 wchar_t buf[512];
2748 wsprintf(buf, L" log %s", msg);
2749 hr = RegOpenKeyEx(HKEY_LOCAL_MACHINE, buf, 0, KEY_READ, &dummyKey);
2750 if (SUCCEEDED(hr)) {
2751 RegCloseKey(dummyKey);
2754 #else
2756 #define LOGREGISTRY(msg)
2758 #endif
2760 static DWORD InitDwriteBG(LPVOID lpdwThreadParam)
2762 SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_BEGIN);
2763 LOGREGISTRY(L"loading dwrite.dll");
2764 HMODULE dwdll = LoadLibraryW(L"dwrite.dll");
2765 DWriteCreateFactoryFunc createDWriteFactory = (DWriteCreateFactoryFunc)
2766 GetProcAddress(dwdll, "DWriteCreateFactory");
2767 if (createDWriteFactory) {
2768 LOGREGISTRY(L"creating dwrite factory");
2769 IDWriteFactory *factory;
2770 HRESULT hr = createDWriteFactory(
2771 DWRITE_FACTORY_TYPE_SHARED,
2772 __uuidof(IDWriteFactory),
2773 reinterpret_cast<IUnknown**>(&factory));
2775 LOGREGISTRY(L"dwrite factory done");
2776 factory->Release();
2777 LOGREGISTRY(L"freed factory");
2779 SetThreadPriority(GetCurrentThread(), THREAD_MODE_BACKGROUND_END);
2780 return 0;
2782 #endif
2784 PRTime gXRE_mainTimestamp = 0;
2787 XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
2789 NS_TIME_FUNCTION;
2791 gXRE_mainTimestamp = PR_Now();
2793 #ifdef MOZ_SPLASHSCREEN
2794 nsSplashScreen *splashScreen = nsnull;
2795 #endif
2797 nsresult rv;
2798 ArgResult ar;
2799 NS_TIMELINE_MARK("enter main");
2801 #ifdef DEBUG
2802 if (PR_GetEnv("XRE_MAIN_BREAK"))
2803 NS_BREAK();
2804 #endif
2806 SetupErrorHandling(argv[0]);
2808 #ifdef CAIRO_HAS_DWRITE_FONT
2810 // Bug 602792 - when DWriteCreateFactory is called the dwrite client dll
2811 // starts the FntCache service if it isn't already running (it's set
2812 // to manual startup by default in Windows 7 RTM). Subsequent DirectWrite
2813 // calls cause the IDWriteFactory object to communicate with the FntCache
2814 // service with a timeout; if there's no response after the timeout, the
2815 // DirectWrite client library will assume the service isn't around and do
2816 // manual font file I/O on _all_ system fonts. To avoid this, load the
2817 // dwrite library and create a factory as early as possible so that the
2818 // FntCache service is ready by the time it's needed.
2820 OSVERSIONINFO vinfo;
2821 vinfo.dwOSVersionInfoSize = sizeof(vinfo);
2822 if (GetVersionEx(&vinfo) && vinfo.dwMajorVersion >= 6) {
2823 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&InitDwriteBG, NULL, 0, NULL);
2826 #endif
2828 #ifdef XP_UNIX
2829 const char *home = PR_GetEnv("HOME");
2830 if (!home || !*home) {
2831 struct passwd *pw = getpwuid(geteuid());
2832 if (!pw || !pw->pw_dir) {
2833 Output(PR_TRUE, "Could not determine HOME directory");
2834 return 1;
2836 SaveWordToEnv("HOME", nsDependentCString(pw->pw_dir));
2838 #endif
2840 #ifdef MOZ_ACCESSIBILITY_ATK
2841 // Reset GTK_MODULES, strip atk-bridge if exists
2842 // Mozilla will load libatk-bridge.so later if necessary
2843 const char* gtkModules = PR_GetEnv("GTK_MODULES");
2844 if (gtkModules && *gtkModules) {
2845 nsCString gtkModulesStr(gtkModules);
2846 gtkModulesStr.ReplaceSubstring("atk-bridge", "");
2847 char* expr = PR_smprintf("GTK_MODULES=%s", gtkModulesStr.get());
2848 if (expr)
2849 PR_SetEnv(expr);
2850 // We intentionally leak |expr| here since it is required by PR_SetEnv.
2853 // Suppress atk-bridge init at startup, it works after GNOME 2.24.2
2854 PR_SetEnv("NO_AT_BRIDGE=1");
2855 #endif
2857 gArgc = argc;
2858 gArgv = argv;
2860 NS_ENSURE_TRUE(aAppData, 2);
2862 #ifdef XP_MACOSX
2863 // The xulrunner stub executable tricks CFBundleGetMainBundle on
2864 // purpose into lying about the main bundle path. It will set
2865 // XRE_BINARY_PATH to inform us of our real location.
2866 gBinaryPath = getenv("XRE_BINARY_PATH");
2868 if (gBinaryPath && !*gBinaryPath)
2869 gBinaryPath = nsnull;
2870 #endif
2872 // Check for application.ini overrides
2873 const char* override = nsnull;
2874 ar = CheckArg("override", PR_TRUE, &override);
2875 if (ar == ARG_BAD) {
2876 Output(PR_TRUE, "Incorrect number of arguments passed to -override");
2877 return 1;
2879 else if (ar == ARG_FOUND) {
2880 nsCOMPtr<nsILocalFile> overrideLF;
2881 rv = XRE_GetFileFromPath(override, getter_AddRefs(overrideLF));
2882 if (NS_FAILED(rv)) {
2883 Output(PR_TRUE, "Error: unrecognized override.ini path.\n");
2884 return 1;
2887 nsXREAppData* overrideAppData = const_cast<nsXREAppData*>(aAppData);
2888 rv = XRE_ParseAppData(overrideLF, overrideAppData);
2889 if (NS_FAILED(rv)) {
2890 Output(PR_TRUE, "Couldn't read override.ini");
2891 return 1;
2895 ScopedAppData appData(aAppData);
2896 gAppData = &appData;
2898 // Check sanity and correctness of app data.
2900 if (!appData.name) {
2901 Output(PR_TRUE, "Error: App:Name not specified in application.ini\n");
2902 return 1;
2904 if (!appData.buildID) {
2905 Output(PR_TRUE, "Error: App:BuildID not specified in application.ini\n");
2906 return 1;
2909 #ifdef MOZ_SPLASHSCREEN
2910 // check to see if we need to do a splash screen
2911 PRBool wantsSplash = PR_TRUE;
2912 PRBool isNoSplash = (CheckArg("nosplash", PR_FALSE, NULL, PR_FALSE) == ARG_FOUND);
2913 isNoSplash |= (PR_GetEnv("NO_SPLASH") != 0);
2914 PRBool isNoRemote = (CheckArg("no-remote", PR_FALSE, NULL, PR_FALSE) == ARG_FOUND);
2916 #ifdef WINCE
2917 // synchronize startup; if it looks like we're going to have to
2918 // wait, then open up a splash screen
2919 WindowsMutex winStartupMutex(L"FirefoxStartupMutex");
2921 // try to lock the mutex, but only wait 100ms to do so
2922 PRBool needsMutexLock = ! winStartupMutex.Lock(100);
2924 // If we failed to lock the mutex quickly, then we'll want
2925 // a splash screen for sure.
2927 // If we did manage to lock it, then we'll only want one
2928 // a splash screen if there is no existing message window;
2929 // that is, if we are the first instance of the app.
2930 if (!needsMutexLock && !isNoRemote) {
2931 // check to see if there's a remote firefox up
2932 static PRUnichar classNameBuffer[128];
2933 _snwprintf(classNameBuffer, sizeof(classNameBuffer) / sizeof(PRUnichar),
2934 L"%S%s",
2935 gAppData->name, L"MessageWindow");
2936 HANDLE h = FindWindowW(classNameBuffer, 0);
2937 if (h) {
2938 // Someone else has the window, and we were able to grab the mutex,
2939 // meaning the other instance ahs presumably already finished starting
2940 // up by now. So no need for a splash screen.
2941 wantsSplash = PR_FALSE;
2942 CloseHandle(h);
2943 } else {
2944 // We couldn't find another window, and we were able to lock the mutex;
2945 // we're likely the first instance starting up, so make sure a splash
2946 // screen gets thrown up.
2947 wantsSplash = PR_TRUE;
2950 #endif //WINCE
2952 if (wantsSplash && !isNoSplash)
2953 splashScreen = nsSplashScreen::GetOrCreate();
2955 if (splashScreen)
2956 splashScreen->Open();
2958 #ifdef WINCE
2959 // Now that the splash screen is open, wait indefinitely
2960 // for the startup mutex on this thread if we need to.
2961 if (needsMutexLock)
2962 winStartupMutex.Lock();
2963 #endif //WINCE
2965 #endif //MOZ_SPLASHSCREEN
2968 ScopedLogging log;
2970 if (!appData.xreDirectory) {
2971 nsCOMPtr<nsILocalFile> lf;
2972 rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf));
2973 if (NS_FAILED(rv))
2974 return 2;
2976 nsCOMPtr<nsIFile> greDir;
2977 rv = lf->GetParent(getter_AddRefs(greDir));
2978 if (NS_FAILED(rv))
2979 return 2;
2981 rv = CallQueryInterface(greDir, &appData.xreDirectory);
2982 if (NS_FAILED(rv))
2983 return 2;
2986 if (appData.size > offsetof(nsXREAppData, minVersion)) {
2987 if (!appData.minVersion) {
2988 Output(PR_TRUE, "Error: Gecko:MinVersion not specified in application.ini\n");
2989 return 1;
2992 if (!appData.maxVersion) {
2993 // If no maxVersion is specified, we assume the app is only compatible
2994 // with the initial preview release. Do not increment this number ever!
2995 SetAllocatedString(appData.maxVersion, "1.*");
2998 if (NS_CompareVersions(appData.minVersion, gToolkitVersion) > 0 ||
2999 NS_CompareVersions(appData.maxVersion, gToolkitVersion) < 0) {
3000 Output(PR_TRUE, "Error: Platform version '%s' is not compatible with\n"
3001 "minVersion >= %s\nmaxVersion <= %s\n",
3002 gToolkitVersion,
3003 appData.minVersion, appData.maxVersion);
3004 return 1;
3008 nsXREDirProvider dirProvider;
3009 rv = dirProvider.Initialize(gAppData->directory, gAppData->xreDirectory);
3010 if (NS_FAILED(rv))
3011 return 1;
3013 #ifdef MOZ_CRASHREPORTER
3014 const char* crashreporterEnv = PR_GetEnv("MOZ_CRASHREPORTER");
3015 if (crashreporterEnv && *crashreporterEnv) {
3016 appData.flags |= NS_XRE_ENABLE_CRASH_REPORTER;
3019 if ((appData.flags & NS_XRE_ENABLE_CRASH_REPORTER) &&
3020 NS_SUCCEEDED(
3021 CrashReporter::SetExceptionHandler(appData.xreDirectory))) {
3022 if (appData.crashReporterURL)
3023 CrashReporter::SetServerURL(nsDependentCString(appData.crashReporterURL));
3025 // pass some basic info from the app data
3026 if (appData.vendor)
3027 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Vendor"),
3028 nsDependentCString(appData.vendor));
3029 if (appData.name)
3030 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProductName"),
3031 nsDependentCString(appData.name));
3032 if (appData.version)
3033 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Version"),
3034 nsDependentCString(appData.version));
3035 if (appData.buildID)
3036 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("BuildID"),
3037 nsDependentCString(appData.buildID));
3038 CrashReporter::SetRestartArgs(argc, argv);
3040 // annotate other data (user id etc)
3041 nsCOMPtr<nsILocalFile> userAppDataDir;
3042 if (NS_SUCCEEDED(dirProvider.GetUserAppDataDirectory(
3043 getter_AddRefs(userAppDataDir)))) {
3044 CrashReporter::SetupExtraData(userAppDataDir,
3045 nsDependentCString(appData.buildID));
3047 // see if we have a crashreporter-override.ini in the application directory
3048 nsCOMPtr<nsIFile> overrideini;
3049 PRBool exists;
3050 static char overrideEnv[MAXPATHLEN];
3051 if (NS_SUCCEEDED(dirProvider.GetAppDir()->Clone(getter_AddRefs(overrideini))) &&
3052 NS_SUCCEEDED(overrideini->AppendNative(NS_LITERAL_CSTRING("crashreporter-override.ini"))) &&
3053 NS_SUCCEEDED(overrideini->Exists(&exists)) &&
3054 exists) {
3055 #ifdef XP_WIN
3056 nsAutoString overridePathW;
3057 overrideini->GetPath(overridePathW);
3058 NS_ConvertUTF16toUTF8 overridePath(overridePathW);
3059 #else
3060 nsCAutoString overridePath;
3061 overrideini->GetNativePath(overridePath);
3062 #endif
3064 sprintf(overrideEnv, "MOZ_CRASHREPORTER_STRINGS_OVERRIDE=%s",
3065 overridePath.get());
3066 PR_SetEnv(overrideEnv);
3070 #endif
3072 #ifdef XP_MACOSX
3073 if (PR_GetEnv("MOZ_LAUNCHED_CHILD")) {
3074 // This is needed, on relaunch, to force the OS to use the "Cocoa Dock
3075 // API". Otherwise the call to ReceiveNextEvent() below will make it
3076 // use the "Carbon Dock API". For more info see bmo bug 377166.
3077 EnsureUseCocoaDockAPI();
3079 // When the app relaunches, the original process exits. This causes
3080 // the dock tile to stop bouncing, lose the "running" triangle, and
3081 // if the tile does not permanently reside in the Dock, even disappear.
3082 // This can be confusing to the user, who is expecting the app to launch.
3083 // Calling ReceiveNextEvent without requesting any event is enough to
3084 // cause a dock tile for the child process to appear.
3085 const EventTypeSpec kFakeEventList[] = { { INT_MAX, INT_MAX } };
3086 EventRef event;
3087 ::ReceiveNextEvent(GetEventTypeCount(kFakeEventList), kFakeEventList,
3088 kEventDurationNoWait, PR_FALSE, &event);
3091 if (CheckArg("foreground")) {
3092 // The original process communicates that it was in the foreground by
3093 // adding this argument. This new process, which is taking over for
3094 // the old one, should make itself the active application.
3095 ProcessSerialNumber psn;
3096 if (::GetCurrentProcess(&psn) == noErr)
3097 ::SetFrontProcess(&psn);
3099 #endif
3101 SaveToEnv("MOZ_LAUNCHED_CHILD=");
3103 gRestartArgc = gArgc;
3104 gRestartArgv = (char**) malloc(sizeof(char*) * (gArgc + 1 + (override ? 2 : 0)));
3105 if (!gRestartArgv) return 1;
3107 int i;
3108 for (i = 0; i < gArgc; ++i) {
3109 gRestartArgv[i] = gArgv[i];
3112 // Add the -override argument back (it is removed automatically be CheckArg) if there is one
3113 if (override) {
3114 gRestartArgv[gRestartArgc++] = const_cast<char*>("-override");
3115 gRestartArgv[gRestartArgc++] = const_cast<char*>(override);
3118 gRestartArgv[gRestartArgc] = nsnull;
3121 #if defined(XP_OS2)
3122 PRBool StartOS2App(int aArgc, char **aArgv);
3123 if (!StartOS2App(gArgc, gArgv))
3124 return 1;
3125 ScopedFPHandler handler;
3126 #endif /* XP_OS2 */
3128 if (PR_GetEnv("MOZ_SAFE_MODE_RESTART")) {
3129 gSafeMode = PR_TRUE;
3130 // unset the env variable
3131 PR_SetEnv("MOZ_SAFE_MODE_RESTART=");
3134 ar = CheckArg("safe-mode", PR_TRUE);
3135 if (ar == ARG_BAD) {
3136 PR_fprintf(PR_STDERR, "Error: argument -safe-mode is invalid when argument -osint is specified\n");
3137 return 1;
3138 } else if (ar == ARG_FOUND) {
3139 gSafeMode = PR_TRUE;
3142 #ifdef XP_WIN
3143 // If the shift key is pressed and the ctrl and / or alt keys are not pressed
3144 // during startup start in safe mode. GetKeyState returns a short and the high
3145 // order bit will be 1 if the key is pressed. By masking the returned short
3146 // with 0x8000 the result will be 0 if the key is not pressed and non-zero
3147 // otherwise.
3148 if (GetKeyState(VK_SHIFT) & 0x8000 &&
3149 !(GetKeyState(VK_CONTROL) & 0x8000) && !(GetKeyState(VK_MENU) & 0x8000)) {
3150 gSafeMode = PR_TRUE;
3152 #endif
3154 #ifdef XP_MACOSX
3155 if (GetCurrentEventKeyModifiers() & optionKey)
3156 gSafeMode = PR_TRUE;
3157 #endif
3159 // Handle -no-remote command line argument. Setup the environment to
3160 // better accommodate other components and various restart scenarios.
3161 ar = CheckArg("no-remote", PR_TRUE);
3162 if (ar == ARG_BAD) {
3163 PR_fprintf(PR_STDERR, "Error: argument -a requires an application name\n");
3164 return 1;
3165 } else if (ar == ARG_FOUND) {
3166 SaveToEnv("MOZ_NO_REMOTE=1");
3169 // Handle -help and -version command line arguments.
3170 // They should return quickly, so we deal with them here.
3171 if (CheckArg("h") || CheckArg("help") || CheckArg("?")) {
3172 DumpHelp();
3173 return 0;
3176 if (CheckArg("v") || CheckArg("version")) {
3177 DumpVersion();
3178 return 0;
3181 #ifdef NS_TRACE_MALLOC
3182 gArgc = argc = NS_TraceMallocStartupArgs(gArgc, gArgv);
3183 #endif
3185 MOZ_SPLASHSCREEN_UPDATE(20);
3187 rv = XRE_InitCommandLine(gArgc, gArgv);
3188 NS_ENSURE_SUCCESS(rv, 1);
3191 // Check for -register, which registers chrome and then exits immediately.
3192 ar = CheckArg("register", PR_TRUE);
3193 if (ar == ARG_BAD) {
3194 PR_fprintf(PR_STDERR, "Error: argument -register is invalid when argument -osint is specified\n");
3195 return 1;
3196 } else if (ar == ARG_FOUND) {
3197 ScopedXPCOMStartup xpcom;
3198 rv = xpcom.Initialize();
3199 NS_ENSURE_SUCCESS(rv, 1);
3202 nsCOMPtr<nsIChromeRegistry> chromeReg =
3203 mozilla::services::GetChromeRegistryService();
3204 NS_ENSURE_TRUE(chromeReg, 1);
3206 chromeReg->CheckForNewChrome();
3208 return 0;
3211 #if defined(MOZ_WIDGET_GTK2) || defined(MOZ_ENABLE_XREMOTE)
3212 // Stash DESKTOP_STARTUP_ID in malloc'ed memory because gtk_init will clear it.
3213 #define HAVE_DESKTOP_STARTUP_ID
3214 const char* desktopStartupIDEnv = PR_GetEnv("DESKTOP_STARTUP_ID");
3215 nsCAutoString desktopStartupID;
3216 if (desktopStartupIDEnv) {
3217 desktopStartupID.Assign(desktopStartupIDEnv);
3219 #endif
3221 #if defined(MOZ_WIDGET_QT)
3222 const char* qgraphicssystemARG = NULL;
3223 ar = CheckArg("graphicssystem", PR_TRUE, &qgraphicssystemARG, PR_FALSE);
3224 if (ar == ARG_FOUND)
3225 PR_SetEnv(PR_smprintf("MOZ_QT_GRAPHICSSYSTEM=%s", qgraphicssystemARG));
3227 QScopedPointer<QApplication> app(new QApplication(gArgc, gArgv));
3229 #if MOZ_PLATFORM_MAEMO > 5
3230 if (XRE_GetProcessType() == GeckoProcessType_Default) {
3231 // try to get the MInputContext if possible to support the MeeGo VKB
3232 QInputContext* inputContext = app->inputContext();
3233 if (inputContext && inputContext->identifierName() != "MInputContext") {
3234 QInputContext* context = QInputContextFactory::create("MInputContext",
3235 app.data());
3236 if (context)
3237 app->setInputContext(context);
3240 #endif
3241 QStringList nonQtArguments = app->arguments();
3242 gQtOnlyArgc = 1;
3243 gQtOnlyArgv = (char**) malloc(sizeof(char*)
3244 * (gRestartArgc - nonQtArguments.size() + 2));
3246 // copy binary path
3247 gQtOnlyArgv[0] = gRestartArgv[0];
3249 for (int i = 1; i < gRestartArgc; ++i) {
3250 if (!nonQtArguments.contains(gRestartArgv[i])) {
3251 // copy arguments used by Qt for later
3252 gQtOnlyArgv[gQtOnlyArgc++] = gRestartArgv[i];
3255 gQtOnlyArgv[gQtOnlyArgc] = nsnull;
3256 #endif
3257 #if defined(MOZ_WIDGET_GTK2)
3258 #ifdef MOZ_MEMORY
3259 // Disable the slice allocator, since jemalloc already uses similar layout
3260 // algorithms, and using a sub-allocator tends to increase fragmentation.
3261 // This must be done before g_thread_init() is called.
3262 g_slice_set_config(G_SLICE_CONFIG_ALWAYS_MALLOC, 1);
3263 #endif
3264 g_thread_init(NULL);
3265 // setup for private colormap. Ideally we'd like to do this
3266 // in nsAppShell::Create, but we need to get in before gtk
3267 // has been initialized to make sure everything is running
3268 // consistently.
3269 if (CheckArg("install"))
3270 gdk_rgb_set_install(TRUE);
3272 // Initialize GTK here for splash.
3274 // Open the display ourselves instead of using gtk_init, so that we can
3275 // close it without fear that one day gtk might clean up the display it
3276 // opens.
3277 if (!gtk_parse_args(&gArgc, &gArgv))
3278 return 1;
3280 // display_name is owned by gdk.
3281 const char *display_name = gdk_get_display_arg_name();
3282 if (display_name) {
3283 SaveWordToEnv("DISPLAY", nsDependentCString(display_name));
3284 } else {
3285 display_name = PR_GetEnv("DISPLAY");
3286 if (!display_name) {
3287 PR_fprintf(PR_STDERR, "Error: no display specified\n");
3288 return 1;
3291 #endif /* MOZ_WIDGET_GTK2 */
3293 #ifdef MOZ_ENABLE_XREMOTE
3294 // handle -remote now that xpcom is fired up
3296 const char* xremotearg;
3297 ar = CheckArg("remote", PR_TRUE, &xremotearg);
3298 if (ar == ARG_BAD) {
3299 PR_fprintf(PR_STDERR, "Error: -remote requires an argument\n");
3300 return 1;
3302 const char* desktopStartupIDPtr =
3303 desktopStartupID.IsEmpty() ? nsnull : desktopStartupID.get();
3304 if (ar) {
3305 return HandleRemoteArgument(xremotearg, desktopStartupIDPtr);
3308 if (!PR_GetEnv("MOZ_NO_REMOTE")) {
3309 // Try to remote the entire command line. If this fails, start up normally.
3310 RemoteResult rr = RemoteCommandLine(desktopStartupIDPtr);
3311 if (rr == REMOTE_FOUND)
3312 return 0;
3313 else if (rr == REMOTE_ARG_BAD)
3314 return 1;
3316 #endif
3318 #if defined(MOZ_WIDGET_GTK2)
3319 GdkDisplay* display = nsnull;
3320 display = gdk_display_open(display_name);
3321 if (!display) {
3322 PR_fprintf(PR_STDERR, "Error: cannot open display: %s\n", display_name);
3323 return 1;
3325 gdk_display_manager_set_default_display (gdk_display_manager_get(),
3326 display);
3328 // g_set_application_name () is only defined in glib2.2 and higher.
3329 _g_set_application_name_fn _g_set_application_name =
3330 (_g_set_application_name_fn)FindFunction("g_set_application_name");
3331 if (_g_set_application_name) {
3332 _g_set_application_name(gAppData->name);
3334 _gtk_window_set_auto_startup_notification_fn _gtk_window_set_auto_startup_notification =
3335 (_gtk_window_set_auto_startup_notification_fn)FindFunction("gtk_window_set_auto_startup_notification");
3336 if (_gtk_window_set_auto_startup_notification) {
3337 _gtk_window_set_auto_startup_notification(PR_FALSE);
3340 gtk_widget_set_default_colormap(gdk_rgb_get_colormap());
3341 #endif /* MOZ_WIDGET_GTK2 */
3342 #ifdef MOZ_X11
3343 // Do this after initializing GDK, or GDK will install its own handler.
3344 InstallX11ErrorHandler();
3345 #endif
3347 // Call the code to install our handler
3348 #ifdef MOZ_JPROF
3349 setupProfilingStuff();
3350 #endif
3352 // Try to allocate "native app support."
3353 nsCOMPtr<nsINativeAppSupport> nativeApp;
3354 rv = NS_CreateNativeAppSupport(getter_AddRefs(nativeApp));
3355 if (NS_FAILED(rv))
3356 return 1;
3358 PRBool canRun = PR_FALSE;
3359 rv = nativeApp->Start(&canRun);
3360 if (NS_FAILED(rv) || !canRun) {
3361 return 1;
3364 #if defined(MOZ_UPDATER) && !defined(ANDROID)
3365 // Check for and process any available updates
3366 nsCOMPtr<nsIFile> updRoot;
3367 PRBool persistent;
3368 rv = dirProvider.GetFile(XRE_UPDATE_ROOT_DIR, &persistent,
3369 getter_AddRefs(updRoot));
3370 // XRE_UPDATE_ROOT_DIR may fail. Fallback to appDir if failed
3371 if (NS_FAILED(rv))
3372 updRoot = dirProvider.GetAppDir();
3374 // Support for processing an update and exiting. The MOZ_PROCESS_UPDATES
3375 // environment variable will be part of the updater's environment and the
3376 // application that is relaunched by the updater. When the application is
3377 // relaunched by the updater it will be removed below and the application
3378 // will exit.
3379 if (CheckArg("process-updates")) {
3380 SaveToEnv("MOZ_PROCESS_UPDATES=1");
3382 ProcessUpdates(dirProvider.GetGREDir(),
3383 dirProvider.GetAppDir(),
3384 updRoot,
3385 gRestartArgc,
3386 gRestartArgv,
3387 appData.version);
3388 if (PR_GetEnv("MOZ_PROCESS_UPDATES")) {
3389 PR_SetEnv("MOZ_PROCESS_UPDATES=");
3390 return 0;
3392 #endif
3394 nsCOMPtr<nsIProfileLock> profileLock;
3395 PRBool startOffline = PR_FALSE;
3396 nsCAutoString profileName;
3398 rv = SelectProfile(getter_AddRefs(profileLock), nativeApp, &startOffline,
3399 &profileName);
3400 if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS ||
3401 rv == NS_ERROR_ABORT) return 0;
3403 if (NS_FAILED(rv)) {
3404 // We failed to choose or create profile - notify user and quit
3405 ProfileMissingDialog(nativeApp);
3406 return 1;
3409 nsCOMPtr<nsILocalFile> profD;
3410 rv = profileLock->GetDirectory(getter_AddRefs(profD));
3411 NS_ENSURE_SUCCESS(rv, 1);
3413 nsCOMPtr<nsILocalFile> profLD;
3414 rv = profileLock->GetLocalDirectory(getter_AddRefs(profLD));
3415 NS_ENSURE_SUCCESS(rv, 1);
3417 rv = dirProvider.SetProfile(profD, profLD);
3418 NS_ENSURE_SUCCESS(rv, 1);
3420 #if defined(WINCE) && defined(MOZ_SPLASHSCREEN)
3421 // give up the mutex, let other app startups happen
3422 winStartupMutex.Unlock();
3423 #endif
3425 //////////////////////// NOW WE HAVE A PROFILE ////////////////////////
3427 #ifdef MOZ_CRASHREPORTER
3428 if (appData.flags & NS_XRE_ENABLE_CRASH_REPORTER)
3429 MakeOrSetMinidumpPath(profD);
3430 #endif
3432 nsCAutoString version;
3433 BuildVersion(version);
3435 #ifdef TARGET_OS_ABI
3436 NS_NAMED_LITERAL_CSTRING(osABI, TARGET_OS_ABI);
3437 #else
3438 // No TARGET_XPCOM_ABI, but at least the OS is known
3439 NS_NAMED_LITERAL_CSTRING(osABI, OS_TARGET "_UNKNOWN");
3440 #endif
3442 // Check for version compatibility with the last version of the app this
3443 // profile was started with. The format of the version stamp is defined
3444 // by the BuildVersion function.
3445 // Also check to see if something has happened to invalidate our
3446 // fastload caches, like an extension upgrade or installation.
3448 // If we see .purgecaches, that means someone did a make.
3449 // Re-register components to catch potential changes.
3450 // We only offer this in debug builds, though.
3451 nsCOMPtr<nsILocalFile> flagFile;
3453 rv = NS_ERROR_FILE_NOT_FOUND;
3454 nsCOMPtr<nsIFile> fFlagFile;
3455 if (gAppData->directory) {
3456 rv = gAppData->directory->Clone(getter_AddRefs(fFlagFile));
3458 flagFile = do_QueryInterface(fFlagFile);
3459 if (flagFile) {
3460 flagFile->AppendNative(FILE_INVALIDATE_CACHES);
3463 PRBool cachesOK;
3464 PRBool versionOK = CheckCompatibility(profD, version, osABI,
3465 dirProvider.GetGREDir(),
3466 gAppData->directory, flagFile,
3467 &cachesOK);
3468 if (CheckArg("purgecaches")) {
3469 cachesOK = PR_FALSE;
3471 if (PR_GetEnv("MOZ_PURGE_CACHES")) {
3472 cachesOK = PR_FALSE;
3475 // Every time a profile is loaded by a build with a different version,
3476 // it updates the compatibility.ini file saying what version last wrote
3477 // the fastload caches. On subsequent launches if the version matches,
3478 // there is no need for re-registration. If the user loads the same
3479 // profile in different builds the component registry must be
3480 // re-generated to prevent mysterious component loading failures.
3482 if (gSafeMode) {
3483 RemoveComponentRegistries(profD, profLD, PR_FALSE);
3484 WriteVersion(profD, NS_LITERAL_CSTRING("Safe Mode"), osABI,
3485 dirProvider.GetGREDir(), gAppData->directory);
3487 else if (versionOK) {
3488 if (!cachesOK) {
3489 // Remove caches, forcing component re-registration.
3490 // The new list of additional components directories is derived from
3491 // information in "extensions.ini".
3492 RemoveComponentRegistries(profD, profLD, PR_FALSE);
3494 // Rewrite compatibility.ini to remove the flag
3495 WriteVersion(profD, version, osABI,
3496 dirProvider.GetGREDir(), gAppData->directory);
3498 // Nothing need be done for the normal startup case.
3500 else {
3501 // Remove caches, forcing component re-registration
3502 // with the default set of components (this disables any potentially
3503 // troublesome incompatible XPCOM components).
3504 RemoveComponentRegistries(profD, profLD, PR_TRUE);
3506 // Write out version
3507 WriteVersion(profD, version, osABI,
3508 dirProvider.GetGREDir(), gAppData->directory);
3511 if (flagFile) {
3512 flagFile->Remove(PR_TRUE);
3515 PRBool appInitiatedRestart = PR_FALSE;
3517 MOZ_SPLASHSCREEN_UPDATE(30);
3519 NS_TIME_FUNCTION_MARK("Next: ScopedXPCOMStartup");
3521 NS_TIME_FUNCTION_MARK("ScopedXPCOMStartup");
3523 // Allows the user to forcefully bypass the restart process at their
3524 // own risk. Useful for debugging or for tinderboxes where child
3525 // processes can be problematic.
3527 // Start the real application
3528 ScopedXPCOMStartup xpcom;
3529 rv = xpcom.Initialize();
3530 NS_TIME_FUNCTION_MARK("ScopedXPCOMStartup: Initialize");
3531 NS_ENSURE_SUCCESS(rv, 1);
3534 #ifdef NS_FUNCTION_TIMER
3535 // initialize some common services, so we don't pay the cost for these at odd times later on;
3536 // SetWindowCreator -> ChromeRegistry -> IOService -> SocketTransportService -> (nspr wspm init), Prefs
3538 nsCOMPtr<nsISupports> comp;
3540 comp = do_GetService("@mozilla.org/preferences-service;1");
3541 NS_TIME_FUNCTION_MARK("Pref Service");
3543 comp = do_GetService("@mozilla.org/network/socket-transport-service;1");
3544 NS_TIME_FUNCTION_MARK("Socket Transport Service");
3546 comp = do_GetService("@mozilla.org/network/dns-service;1");
3547 NS_TIME_FUNCTION_MARK("DNS Service");
3549 comp = do_GetService("@mozilla.org/network/io-service;1");
3550 NS_TIME_FUNCTION_MARK("IO Service");
3552 comp = do_GetService("@mozilla.org/chrome/chrome-registry;1");
3553 NS_TIME_FUNCTION_MARK("Chrome Registry Service");
3555 comp = do_GetService("@mozilla.org/focus-event-suppressor-service;1");
3556 NS_TIME_FUNCTION_MARK("Focus Event Suppressor Service");
3558 #endif
3560 rv = xpcom.SetWindowCreator(nativeApp);
3561 NS_TIME_FUNCTION_MARK("ScopedXPCOMStartup: SetWindowCreator");
3562 NS_ENSURE_SUCCESS(rv, 1);
3564 NS_TIME_FUNCTION_MARK("ScopedXPCOMStartup: Done");
3566 #ifdef MOZ_CRASHREPORTER
3567 // tell the crash reporter to also send the release channel
3568 nsCOMPtr<nsIPrefService> prefs = do_GetService("@mozilla.org/preferences-service;1", &rv);
3569 if (NS_SUCCEEDED(rv)) {
3570 nsCOMPtr<nsIPrefBranch> defaultPrefBranch;
3571 rv = prefs->GetDefaultBranch(nsnull, getter_AddRefs(defaultPrefBranch));
3573 if (NS_SUCCEEDED(rv)) {
3574 nsXPIDLCString sval;
3575 rv = defaultPrefBranch->GetCharPref("app.update.channel", getter_Copies(sval));
3576 if (NS_SUCCEEDED(rv)) {
3577 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ReleaseChannel"),
3578 sval);
3582 #endif
3584 NS_TIME_FUNCTION_MARK("Next: AppStartup");
3587 if (startOffline) {
3588 nsCOMPtr<nsIIOService2> io (do_GetService("@mozilla.org/network/io-service;1"));
3589 NS_ENSURE_TRUE(io, 1);
3590 io->SetManageOfflineStatus(PR_FALSE);
3591 io->SetOffline(PR_TRUE);
3595 NS_TIMELINE_ENTER("startupNotifier");
3596 nsCOMPtr<nsIObserver> startupNotifier
3597 (do_CreateInstance(NS_APPSTARTUPNOTIFIER_CONTRACTID, &rv));
3598 NS_ENSURE_SUCCESS(rv, 1);
3600 startupNotifier->Observe(nsnull, APPSTARTUP_TOPIC, nsnull);
3601 NS_TIMELINE_LEAVE("startupNotifier");
3604 NS_TIME_FUNCTION_MARK("Finished startupNotifier");
3606 nsCOMPtr<nsIAppStartup2> appStartup
3607 (do_GetService(NS_APPSTARTUP_CONTRACTID));
3608 NS_ENSURE_TRUE(appStartup, 1);
3610 NS_TIME_FUNCTION_MARK("Created AppStartup");
3612 if (gDoMigration) {
3613 nsCOMPtr<nsIFile> file;
3614 dirProvider.GetAppDir()->Clone(getter_AddRefs(file));
3615 file->AppendNative(NS_LITERAL_CSTRING("override.ini"));
3616 nsINIParser parser;
3617 nsCOMPtr<nsILocalFile> localFile(do_QueryInterface(file));
3618 nsresult rv = parser.Init(localFile);
3619 if (NS_SUCCEEDED(rv)) {
3620 nsCAutoString buf;
3621 rv = parser.GetString("XRE", "EnableProfileMigrator", buf);
3622 if (NS_SUCCEEDED(rv)) {
3623 if (buf[0] == '0' || buf[0] == 'f' || buf[0] == 'F') {
3624 gDoMigration = PR_FALSE;
3630 // Profile Migration
3631 if (gAppData->flags & NS_XRE_ENABLE_PROFILE_MIGRATOR && gDoMigration) {
3632 gDoMigration = PR_FALSE;
3633 nsCOMPtr<nsIProfileMigrator> pm
3634 (do_CreateInstance(NS_PROFILEMIGRATOR_CONTRACTID));
3635 if (pm)
3636 pm->Migrate(&dirProvider);
3639 NS_TIME_FUNCTION_MARK("Profile migration");
3641 dirProvider.DoStartup();
3643 NS_TIME_FUNCTION_MARK("dirProvider.DoStartup() (profile-after-change)");
3645 PRBool shuttingDown = PR_FALSE;
3646 appStartup->GetShuttingDown(&shuttingDown);
3648 nsCOMPtr<nsICommandLineRunner> cmdLine;
3650 nsCOMPtr<nsIFile> workingDir;
3651 rv = NS_GetSpecialDirectory(NS_OS_CURRENT_WORKING_DIR, getter_AddRefs(workingDir));
3652 NS_ENSURE_SUCCESS(rv, 1);
3654 if (!shuttingDown) {
3655 cmdLine = do_CreateInstance("@mozilla.org/toolkit/command-line;1");
3656 NS_ENSURE_TRUE(cmdLine, 1);
3658 rv = cmdLine->Init(gArgc, gArgv,
3659 workingDir, nsICommandLine::STATE_INITIAL_LAUNCH);
3660 NS_ENSURE_SUCCESS(rv, 1);
3662 /* Special-case services that need early access to the command
3663 line. */
3664 nsCOMPtr<nsIObserverService> obsService =
3665 mozilla::services::GetObserverService();
3666 if (obsService) {
3667 obsService->NotifyObservers(cmdLine, "command-line-startup", nsnull);
3670 NS_TIME_FUNCTION_MARK("Early command line init");
3672 NS_TIME_FUNCTION_MARK("Next: prepare for Run");
3675 SaveStateForAppInitiatedRestart();
3677 // clear out any environment variables which may have been set
3678 // during the relaunch process now that we know we won't be relaunching.
3679 SaveToEnv("XRE_PROFILE_PATH=");
3680 SaveToEnv("XRE_PROFILE_LOCAL_PATH=");
3681 SaveToEnv("XRE_PROFILE_NAME=");
3682 SaveToEnv("XRE_START_OFFLINE=");
3683 SaveToEnv("XRE_IMPORT_PROFILES=");
3684 SaveToEnv("NO_EM_RESTART=");
3685 SaveToEnv("XUL_APP_FILE=");
3686 SaveToEnv("XRE_BINARY_PATH=");
3688 NS_TIME_FUNCTION_MARK("env munging");
3690 if (!shuttingDown) {
3691 NS_TIME_FUNCTION_MARK("Next: CreateHiddenWindow");
3693 NS_TIMELINE_ENTER("appStartup->CreateHiddenWindow");
3694 rv = appStartup->CreateHiddenWindow();
3695 NS_TIMELINE_LEAVE("appStartup->CreateHiddenWindow");
3696 NS_ENSURE_SUCCESS(rv, 1);
3698 MOZ_SPLASHSCREEN_UPDATE(50);
3700 #if defined(HAVE_DESKTOP_STARTUP_ID) && defined(MOZ_WIDGET_GTK2)
3701 nsRefPtr<nsGTKToolkit> toolkit = GetGTKToolkit();
3702 if (toolkit && !desktopStartupID.IsEmpty()) {
3703 toolkit->SetDesktopStartupID(desktopStartupID);
3705 #endif
3707 #ifdef XP_MACOSX
3708 // Set up ability to respond to system (Apple) events. This must be
3709 // done before setting up the command line service.
3710 SetupMacApplicationDelegate();
3712 // we re-initialize the command-line service and do appleevents munging
3713 // after we are sure that we're not restarting
3714 cmdLine = do_CreateInstance("@mozilla.org/toolkit/command-line;1");
3715 NS_ENSURE_TRUE(cmdLine, 1);
3717 CommandLineServiceMac::SetupMacCommandLine(gArgc, gArgv, PR_FALSE);
3719 rv = cmdLine->Init(gArgc, gArgv,
3720 workingDir, nsICommandLine::STATE_INITIAL_LAUNCH);
3721 NS_ENSURE_SUCCESS(rv, 1);
3722 #endif
3724 MOZ_SPLASHSCREEN_UPDATE(70);
3726 nsCOMPtr<nsIObserverService> obsService =
3727 mozilla::services::GetObserverService();
3728 if (obsService)
3729 obsService->NotifyObservers(nsnull, "final-ui-startup", nsnull);
3731 NS_TIME_FUNCTION_MARK("final-ui-startup done");
3733 appStartup->GetShuttingDown(&shuttingDown);
3736 if (!shuttingDown) {
3737 rv = cmdLine->Run();
3738 NS_ENSURE_SUCCESS_LOG(rv, 1);
3740 appStartup->GetShuttingDown(&shuttingDown);
3743 #ifdef MOZ_ENABLE_XREMOTE
3744 nsCOMPtr<nsIRemoteService> remoteService;
3745 #endif /* MOZ_ENABLE_XREMOTE */
3746 if (!shuttingDown) {
3747 #ifdef MOZ_ENABLE_XREMOTE
3748 // if we have X remote support, start listening for requests on the
3749 // proxy window.
3750 remoteService = do_GetService("@mozilla.org/toolkit/remote-service;1");
3751 if (remoteService)
3752 remoteService->Startup(gAppData->name,
3753 PromiseFlatCString(profileName).get());
3754 #endif /* MOZ_ENABLE_XREMOTE */
3756 nativeApp->Enable();
3759 NS_TIME_FUNCTION_MARK("Next: Run");
3761 NS_TIME_FUNCTION_MARK("appStartup->Run");
3763 MOZ_SPLASHSCREEN_UPDATE(90);
3765 NS_TIMELINE_ENTER("appStartup->Run");
3766 rv = appStartup->Run();
3767 NS_TIMELINE_LEAVE("appStartup->Run");
3768 if (NS_FAILED(rv)) {
3769 NS_ERROR("failed to run appstartup");
3770 gLogConsoleErrors = PR_TRUE;
3774 NS_TIME_FUNCTION_MARK("Next: Finish");
3776 NS_TIME_FUNCTION_MARK("appStartup->Run done");
3778 // Check for an application initiated restart. This is one that
3779 // corresponds to nsIAppStartup.quit(eRestart)
3780 if (rv == NS_SUCCESS_RESTART_APP)
3781 appInitiatedRestart = PR_TRUE;
3783 if (!shuttingDown) {
3784 #ifdef MOZ_ENABLE_XREMOTE
3785 // shut down the x remote proxy window
3786 if (remoteService)
3787 remoteService->Shutdown();
3788 #endif /* MOZ_ENABLE_XREMOTE */
3791 #ifdef MOZ_TIMELINE
3792 // Make sure we print this out even if timeline is runtime disabled
3793 if (NS_FAILED(NS_TIMELINE_LEAVE("main1")))
3794 NS_TimelineForceMark("...main1");
3795 #endif
3799 // unlock the profile after ScopedXPCOMStartup object (xpcom)
3800 // has gone out of scope. see bug #386739 for more details
3801 profileLock->Unlock();
3803 // Restart the app after XPCOM has been shut down cleanly.
3804 if (appInitiatedRestart) {
3805 MOZ_SPLASHSCREEN_UPDATE(90);
3807 RestoreStateForAppInitiatedRestart();
3809 // Ensure that these environment variables are set:
3810 SaveFileToEnvIfUnset("XRE_PROFILE_PATH", profD);
3811 SaveFileToEnvIfUnset("XRE_PROFILE_LOCAL_PATH", profLD);
3812 SaveWordToEnvIfUnset("XRE_PROFILE_NAME", profileName);
3814 #ifdef XP_MACOSX
3815 if (gBinaryPath) {
3816 static char kEnvVar[MAXPATHLEN];
3817 sprintf(kEnvVar, "XRE_BINARY_PATH=%s", gBinaryPath);
3818 PR_SetEnv(kEnvVar);
3820 #endif
3822 #if defined(HAVE_DESKTOP_STARTUP_ID) && defined(MOZ_WIDGET_GTK2)
3823 if (!desktopStartupID.IsEmpty()) {
3824 nsCAutoString desktopStartupEnv;
3825 desktopStartupEnv.AssignLiteral("DESKTOP_STARTUP_ID=");
3826 desktopStartupEnv.Append(desktopStartupID);
3827 // Leak it with extreme prejudice!
3828 PR_SetEnv(ToNewCString(desktopStartupEnv));
3830 #endif
3832 #ifdef MOZ_WIDGET_GTK2
3833 MOZ_gdk_display_close(display);
3834 #endif
3836 rv = LaunchChild(nativeApp, PR_TRUE);
3838 #ifdef MOZ_CRASHREPORTER
3839 if (appData.flags & NS_XRE_ENABLE_CRASH_REPORTER)
3840 CrashReporter::UnsetExceptionHandler();
3841 #endif
3843 return rv == NS_ERROR_LAUNCHED_CHILD_PROCESS ? 0 : 1;
3846 #ifdef MOZ_WIDGET_GTK2
3847 // gdk_display_close also calls gdk_display_manager_set_default_display
3848 // appropriately when necessary.
3849 MOZ_gdk_display_close(display);
3850 #endif
3853 #ifdef MOZ_CRASHREPORTER
3854 if (appData.flags & NS_XRE_ENABLE_CRASH_REPORTER)
3855 CrashReporter::UnsetExceptionHandler();
3856 #endif
3858 XRE_DeinitCommandLine();
3860 return NS_FAILED(rv) ? 1 : 0;
3863 nsresult
3864 XRE_InitCommandLine(int aArgc, char* aArgv[])
3866 nsresult rv = NS_OK;
3868 #if defined(MOZ_IPC)
3870 #if defined(OS_WIN)
3871 CommandLine::Init(aArgc, aArgv);
3872 #else
3874 // these leak on error, but that's OK: we'll just exit()
3875 char** canonArgs = new char*[aArgc];
3877 // get the canonical version of the binary's path
3878 nsCOMPtr<nsILocalFile> binFile;
3879 rv = XRE_GetBinaryPath(aArgv[0], getter_AddRefs(binFile));
3880 if (NS_FAILED(rv))
3881 return NS_ERROR_FAILURE;
3883 nsCAutoString canonBinPath;
3884 rv = binFile->GetNativePath(canonBinPath);
3885 if (NS_FAILED(rv))
3886 return NS_ERROR_FAILURE;
3888 canonArgs[0] = strdup(canonBinPath.get());
3890 for (int i = 1; i < aArgc; ++i) {
3891 if (aArgv[i]) {
3892 canonArgs[i] = strdup(aArgv[i]);
3896 NS_ASSERTION(!CommandLine::IsInitialized(), "Bad news!");
3897 CommandLine::Init(aArgc, canonArgs);
3899 for (int i = 0; i < aArgc; ++i)
3900 free(canonArgs[i]);
3901 delete[] canonArgs;
3902 #endif
3903 #endif
3905 #ifdef MOZ_OMNIJAR
3906 const char *omnijarPath = nsnull;
3907 ArgResult ar = CheckArg("omnijar", PR_FALSE, &omnijarPath);
3908 if (ar == ARG_BAD) {
3909 PR_fprintf(PR_STDERR, "Error: argument -omnijar requires an omnijar path\n");
3910 return NS_ERROR_FAILURE;
3913 if (!omnijarPath)
3914 return rv;
3916 nsCOMPtr<nsILocalFile> omnijar;
3917 rv = NS_NewNativeLocalFile(nsDependentCString(omnijarPath), PR_TRUE,
3918 getter_AddRefs(omnijar));
3919 if (NS_SUCCEEDED(rv))
3920 mozilla::SetOmnijar(omnijar);
3921 #endif
3923 return rv;
3926 nsresult
3927 XRE_DeinitCommandLine()
3929 nsresult rv = NS_OK;
3931 #if defined(MOZ_IPC)
3932 CommandLine::Terminate();
3933 #endif
3935 return rv;
3938 GeckoProcessType
3939 XRE_GetProcessType()
3941 #ifdef MOZ_IPC
3942 return mozilla::startup::sChildProcessType;
3943 #else
3944 return GeckoProcessType_Default;
3945 #endif
3948 void
3949 SetupErrorHandling(const char* progname)
3951 #ifdef XP_WIN
3952 /* On Windows XPSP3 and Windows Vista if DEP is configured off-by-default
3953 we still want DEP protection: enable it explicitly and programmatically.
3955 This function is not available on WinXPSP2 so we dynamically load it.
3958 HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll");
3959 SetProcessDEPPolicyFunc _SetProcessDEPPolicy =
3960 (SetProcessDEPPolicyFunc) GetProcAddress(kernel32, "SetProcessDEPPolicy");
3961 if (_SetProcessDEPPolicy)
3962 _SetProcessDEPPolicy(PROCESS_DEP_ENABLE);
3963 #endif
3965 #if defined (XP_WIN32) && !defined (WINCE)
3966 // Suppress the "DLL Foo could not be found" dialog, such that if dependent
3967 // libraries (such as GDI+) are not preset, we gracefully fail to load those
3968 // XPCOM components, instead of being ungraceful.
3969 UINT realMode = SetErrorMode(0);
3970 realMode |= SEM_FAILCRITICALERRORS;
3971 // If XRE_NO_WINDOWS_CRASH_DIALOG is set, suppress displaying the "This
3972 // application has crashed" dialog box. This is mainly useful for
3973 // automated testing environments, e.g. tinderbox, where there's no need
3974 // for a dozen of the dialog boxes to litter the console
3975 if (getenv("XRE_NO_WINDOWS_CRASH_DIALOG"))
3976 realMode |= SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX;
3978 SetErrorMode(realMode);
3980 #endif
3982 #ifndef XP_OS2
3983 InstallSignalHandlers(progname);
3984 #endif
3986 #ifndef WINCE
3987 // Unbuffer stdout, needed for tinderbox tests.
3988 setbuf(stdout, 0);
3989 #endif
3991 #if defined(FREEBSD)
3992 // Disable all SIGFPE's on FreeBSD, as it has non-IEEE-conformant fp
3993 // trap behavior that trips up on floating-point tests performed by
3994 // the JS engine. See bugzilla bug 9967 details.
3995 fpsetmask(0);
3996 #endif