Bug 452317 - FeedConverter.js: QueryInterface should throw NS_ERROR_NO_INTERFACE...
[wine-gecko.git] / toolkit / xre / nsAppRunner.cpp
blob3a9413259e5e795bbd014df3acaa511267c90721
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 #include "nsAppRunner.h"
52 #include "nsUpdateDriver.h"
54 #if defined(MOZ_WIDGET_QT)
55 #include <qwidget.h>
56 #include <qapplication.h>
57 #endif
59 #ifdef XP_MACOSX
60 #include "MacLaunchHelper.h"
61 #include "MacApplicationDelegate.h"
62 #endif
64 #ifdef XP_OS2
65 #include "private/pprthred.h"
66 #endif
67 #include "prmem.h"
68 #include "prnetdb.h"
69 #include "prprf.h"
70 #include "prproces.h"
71 #include "prenv.h"
73 #include "nsIAppShellService.h"
74 #include "nsIAppStartup.h"
75 #include "nsIAppStartupNotifier.h"
76 #include "nsIMutableArray.h"
77 #include "nsICategoryManager.h"
78 #include "nsIChromeRegistry.h"
79 #include "nsICommandLineRunner.h"
80 #include "nsIComponentManager.h"
81 #include "nsIComponentRegistrar.h"
82 #include "nsIContentHandler.h"
83 #include "nsIDialogParamBlock.h"
84 #include "nsIDOMWindow.h"
85 #include "nsIExtensionManager.h"
86 #include "nsIFastLoadService.h" // for PLATFORM_FASL_SUFFIX
87 #include "nsIGenericFactory.h"
88 #include "nsIIOService2.h"
89 #include "nsIObserverService.h"
90 #include "nsINativeAppSupport.h"
91 #include "nsIProcess.h"
92 #include "nsIProfileUnlocker.h"
93 #include "nsIPromptService.h"
94 #include "nsIServiceManager.h"
95 #include "nsIStringBundle.h"
96 #include "nsISupportsPrimitives.h"
97 #include "nsITimelineService.h"
98 #include "nsIToolkitChromeRegistry.h"
99 #include "nsIToolkitProfile.h"
100 #include "nsIToolkitProfileService.h"
101 #include "nsIURI.h"
102 #include "nsIWindowCreator.h"
103 #include "nsIWindowMediator.h"
104 #include "nsIWindowWatcher.h"
105 #include "nsIXULAppInfo.h"
106 #include "nsIXULRuntime.h"
107 #include "nsPIDOMWindow.h"
108 #include "nsIBaseWindow.h"
109 #include "nsIWidget.h"
110 #include "nsIDocShell.h"
111 #include "nsAppShellCID.h"
113 #ifdef XP_WIN
114 #include "nsIWinAppHelper.h"
115 #endif
117 #include "nsCRT.h"
118 #include "nsCOMPtr.h"
119 #include "nsDirectoryServiceDefs.h"
120 #include "nsDirectoryServiceUtils.h"
121 #include "nsEmbedCID.h"
122 #include "nsNetUtil.h"
123 #include "nsReadableUtils.h"
124 #include "nsStaticComponents.h"
125 #include "nsXPCOM.h"
126 #include "nsXPIDLString.h"
127 #include "nsXPFEComponentsCID.h"
128 #include "nsVersionComparator.h"
130 #include "nsAppDirectoryServiceDefs.h"
131 #include "nsXULAppAPI.h"
132 #include "nsXREDirProvider.h"
133 #include "nsToolkitCompsCID.h"
135 #include "nsINIParser.h"
137 #include <stdlib.h>
139 #ifdef XP_UNIX
140 #include <sys/stat.h>
141 #include <unistd.h>
142 #endif
144 #ifdef XP_BEOS
145 // execv() behaves bit differently in R5 and Zeta, looks unreliable in such situation
146 //#include <unistd.h>
147 #include <AppKit.h>
148 #include <AppFileInfo.h>
149 #endif //XP_BEOS
151 #ifdef XP_WIN
152 #include <process.h>
153 #include <shlobj.h>
154 #include "nsThreadUtils.h"
155 #endif
157 #ifdef XP_MACOSX
158 #include "nsILocalFileMac.h"
159 #include "nsCommandLineServiceMac.h"
160 #endif
162 // for X remote support
163 #ifdef MOZ_ENABLE_XREMOTE
164 #ifdef MOZ_WIDGET_PHOTON
165 #include "PhRemoteClient.h"
166 #else
167 #include "XRemoteClient.h"
168 #endif
169 #include "nsIRemoteService.h"
170 #endif
172 #ifdef NS_TRACE_MALLOC
173 #include "nsTraceMalloc.h"
174 #endif
176 #if defined(DEBUG) && defined(XP_WIN32)
177 #include <malloc.h>
178 #endif
180 #if defined (XP_MACOSX)
181 #include <Processes.h>
182 #include <Events.h>
183 #endif
185 extern "C" void ShowOSAlert(const char* aMessage);
187 #ifdef DEBUG
188 #include "prlog.h"
189 #endif
191 #ifdef MOZ_JPROF
192 #include "jprof.h"
193 #endif
195 #ifdef MOZ_CRASHREPORTER
196 #include "nsExceptionHandler.h"
197 #include "nsICrashReporter.h"
198 #define NS_CRASHREPORTER_CONTRACTID "@mozilla.org/toolkit/crash-reporter;1"
199 #endif
201 // on x86 linux, the current builds of some popular plugins (notably
202 // flashplayer and real) expect a few builtin symbols from libgcc
203 // which were available in some older versions of gcc. However,
204 // they're _NOT_ available in newer versions of gcc (eg 3.1), so if
205 // we want those plugin to work with a gcc-3.1 built binary, we need
206 // to provide these symbols. MOZ_ENABLE_OLD_ABI_COMPAT_WRAPPERS defaults
207 // to true on x86 linux, and false everywhere else.
209 // The fact that the new and free operators are mismatched
210 // mirrors the way the original functions in egcs 1.1.2 worked.
212 #ifdef MOZ_ENABLE_OLD_ABI_COMPAT_WRAPPERS
214 extern "C" {
216 # ifndef HAVE___BUILTIN_VEC_NEW
217 void *__builtin_vec_new(size_t aSize, const std::nothrow_t &aNoThrow) throw()
219 return ::operator new(aSize, aNoThrow);
221 # endif
223 # ifndef HAVE___BUILTIN_VEC_DELETE
224 void __builtin_vec_delete(void *aPtr, const std::nothrow_t &) throw ()
226 if (aPtr) {
227 free(aPtr);
230 # endif
232 # ifndef HAVE___BUILTIN_NEW
233 void *__builtin_new(int aSize)
235 return malloc(aSize);
237 # endif
239 # ifndef HAVE___BUILTIN_DELETE
240 void __builtin_delete(void *aPtr)
242 free(aPtr);
244 # endif
246 # ifndef HAVE___PURE_VIRTUAL
247 void __pure_virtual(void) {
248 #ifdef WRAP_SYSTEM_INCLUDES
249 #pragma GCC visibility push(default)
250 #endif
251 extern void __cxa_pure_virtual(void);
252 #ifdef WRAP_SYSTEM_INCLUDES
253 #pragma GCC visibility pop
254 #endif
256 __cxa_pure_virtual();
258 # endif
260 #endif
262 #if defined(XP_UNIX) || defined(XP_BEOS)
263 extern void InstallUnixSignalHandlers(const char *ProgramName);
264 #endif
266 int gArgc;
267 char **gArgv;
269 static char gToolkitVersion[20];
270 static char gToolkitBuildID[40];
272 static int gRestartArgc;
273 static char **gRestartArgv;
275 #if defined(MOZ_WIDGET_GTK2)
276 #if defined(DEBUG) || defined(NS_BUILD_REFCNT_LOGGING) \
277 || defined(NS_TRACE_MALLOC)
278 #define CLEANUP_MEMORY 1
279 #define PANGO_ENABLE_BACKEND
280 #include <pango/pangofc-fontmap.h>
281 #endif
282 #include <gtk/gtk.h>
283 #ifdef MOZ_X11
284 #include <gdk/gdkx.h>
285 #endif /* MOZ_X11 */
286 #include "nsGTKToolkit.h"
287 #endif
289 // Save the given word to the specified environment variable.
290 static void
291 SaveWordToEnv(const char *name, const nsACString & word)
293 char *expr = PR_smprintf("%s=%s", name, PromiseFlatCString(word).get());
294 if (expr)
295 PR_SetEnv(expr);
296 // We intentionally leak |expr| here since it is required by PR_SetEnv.
299 // Save the path of the given file to the specified environment variable.
300 static void
301 SaveFileToEnv(const char *name, nsIFile *file)
303 #ifdef XP_WIN
304 nsAutoString path;
305 file->GetPath(path);
306 SetEnvironmentVariableW(NS_ConvertASCIItoUTF16(name).get(), path.get());
307 #else
308 nsCAutoString path;
309 file->GetNativePath(path);
310 SaveWordToEnv(name, path);
311 #endif
314 // Load the path of a file saved with SaveFileToEnv
315 static already_AddRefed<nsILocalFile>
316 GetFileFromEnv(const char *name)
318 nsresult rv;
319 nsILocalFile *file = nsnull;
321 #ifdef XP_WIN
322 WCHAR path[_MAX_PATH];
323 if (!GetEnvironmentVariableW(NS_ConvertASCIItoUTF16(name).get(),
324 path, _MAX_PATH))
325 return nsnull;
327 rv = NS_NewLocalFile(nsDependentString(path), PR_TRUE, &file);
328 if (NS_FAILED(rv))
329 return nsnull;
331 return file;
332 #else
333 const char *arg = PR_GetEnv(name);
334 if (!arg || !*arg)
335 return nsnull;
337 rv = NS_NewNativeLocalFile(nsDependentCString(arg), PR_TRUE, &file);
338 if (NS_FAILED(rv))
339 return nsnull;
341 return file;
342 #endif
345 // Save the path of the given word to the specified environment variable
346 // provided the environment variable does not have a value.
347 static void
348 SaveWordToEnvIfUnset(const char *name, const nsACString & word)
350 const char *val = PR_GetEnv(name);
351 if (!(val && *val))
352 SaveWordToEnv(name, word);
355 // Save the path of the given file to the specified environment variable
356 // provided the environment variable does not have a value.
357 static void
358 SaveFileToEnvIfUnset(const char *name, nsIFile *file)
360 const char *val = PR_GetEnv(name);
361 if (!(val && *val))
362 SaveFileToEnv(name, file);
365 static PRBool
366 strimatch(const char* lowerstr, const char* mixedstr)
368 while(*lowerstr) {
369 if (!*mixedstr) return PR_FALSE; // mixedstr is shorter
370 if (tolower(*mixedstr) != *lowerstr) return PR_FALSE; // no match
372 ++lowerstr;
373 ++mixedstr;
376 if (*mixedstr) return PR_FALSE; // lowerstr is shorter
378 return PR_TRUE;
382 * Output a string to the user. This method is really only meant to be used to
383 * output last-ditch error messages designed for developers NOT END USERS.
385 * @param isError
386 * Pass true to indicate severe errors.
387 * @param fmt
388 * printf-style format string followed by arguments.
390 static void Output(PRBool isError, const char *fmt, ... )
392 va_list ap;
393 va_start(ap, fmt);
395 #if defined(XP_WIN) && !MOZ_WINCONSOLE
396 char *msg = PR_vsmprintf(fmt, ap);
397 if (msg)
399 UINT flags = MB_OK;
400 if (isError)
401 flags |= MB_ICONERROR;
402 else
403 flags |= MB_ICONINFORMATION;
405 wchar_t wide_msg[1024];
406 MultiByteToWideChar(CP_ACP,
408 msg,
410 wide_msg,
411 sizeof(wide_msg) / sizeof(wchar_t));
413 MessageBoxW(NULL, wide_msg, L"XULRunner", flags);
414 PR_smprintf_free(msg);
416 #else
417 vfprintf(stderr, fmt, ap);
418 #endif
420 va_end(ap);
423 enum RemoteResult {
424 REMOTE_NOT_FOUND = 0,
425 REMOTE_FOUND = 1,
426 REMOTE_ARG_BAD = 2
429 enum ArgResult {
430 ARG_NONE = 0,
431 ARG_FOUND = 1,
432 ARG_BAD = 2 // you wanted a param, but there isn't one
435 static void RemoveArg(char **argv)
437 do {
438 *argv = *(argv + 1);
439 ++argv;
440 } while (*argv);
442 --gArgc;
446 * Check for a commandline flag. If the flag takes a parameter, the
447 * parameter is returned in aParam. Flags may be in the form -arg or
448 * --arg (or /arg on win32/OS2).
450 * @param aArg the parameter to check. Must be lowercase.
451 * @param aCheckOSInt if true returns ARG_BAD if the osint argument is present
452 * when aArg is also present.
453 * @param if non-null, the -arg <data> will be stored in this pointer. This is *not*
454 * allocated, but rather a pointer to the argv data.
456 static ArgResult
457 CheckArg(const char* aArg, PRBool aCheckOSInt = PR_FALSE, const char **aParam = nsnull)
459 char **curarg = gArgv + 1; // skip argv[0]
460 ArgResult ar = ARG_NONE;
462 while (*curarg) {
463 char *arg = curarg[0];
465 if (arg[0] == '-'
466 #if defined(XP_WIN) || defined(XP_OS2)
467 || *arg == '/'
468 #endif
470 ++arg;
471 if (*arg == '-')
472 ++arg;
474 if (strimatch(aArg, arg)) {
475 RemoveArg(curarg);
476 if (!aParam) {
477 ar = ARG_FOUND;
478 break;
481 if (*curarg) {
482 if (**curarg == '-'
483 #if defined(XP_WIN) || defined(XP_OS2)
484 || **curarg == '/'
485 #endif
487 return ARG_BAD;
489 *aParam = *curarg;
490 RemoveArg(curarg);
491 ar = ARG_FOUND;
492 break;
494 return ARG_BAD;
498 ++curarg;
501 if (aCheckOSInt && ar == ARG_FOUND) {
502 ArgResult arOSInt = CheckArg("osint");
503 if (arOSInt == ARG_FOUND) {
504 ar = ARG_BAD;
505 PR_fprintf(PR_STDERR, "Error: argument -osint is invalid\n");
509 return ar;
512 #if defined(XP_WIN)
514 * Check for a commandline flag from the windows shell and remove it from the
515 * argv used when restarting. Flags MUST be in the form -arg.
517 * @param aArg the parameter to check. Must be lowercase.
519 static ArgResult
520 CheckArgShell(const char* aArg)
522 char **curarg = gRestartArgv + 1; // skip argv[0]
524 while (*curarg) {
525 char *arg = curarg[0];
527 if (arg[0] == '-') {
528 ++arg;
530 if (strimatch(aArg, arg)) {
531 do {
532 *curarg = *(curarg + 1);
533 ++curarg;
534 } while (*curarg);
536 --gRestartArgc;
538 return ARG_FOUND;
542 ++curarg;
545 return ARG_NONE;
549 * Enabled Native App Support to process DDE messages when the app needs to
550 * restart and the app has been launched by the Windows shell to open an url.
551 * When aWait is false this will process the DDE events manually. This prevents
552 * Windows from displaying an error message due to the DDE message not being
553 * acknowledged.
555 static void
556 ProcessDDE(nsINativeAppSupport* aNative, PRBool aWait)
558 // When the app is launched by the windows shell the windows shell
559 // expects the app to be available for DDE messages and if it isn't
560 // windows displays an error dialog. To prevent the error the DDE server
561 // is enabled and pending events are processed when the app needs to
562 // restart after it was launched by the shell with the requestpending
563 // argument. The requestpending pending argument is removed to
564 // differentiate it from being launched when an app restart is not
565 // required.
566 ArgResult ar;
567 ar = CheckArgShell("requestpending");
568 if (ar == ARG_FOUND) {
569 aNative->Enable(); // enable win32 DDE responses
570 if (aWait) {
571 nsIThread *thread = NS_GetCurrentThread();
572 // This is just a guesstimate based on testing different values.
573 // If count is 8 or less windows will display an error dialog.
574 PRInt32 count = 20;
575 while(--count >= 0) {
576 NS_ProcessNextEvent(thread);
577 PR_Sleep(PR_MillisecondsToInterval(1));
582 #endif
584 PRBool gSafeMode = PR_FALSE;
587 * The nsXULAppInfo object implements nsIFactory so that it can be its own
588 * singleton.
590 class nsXULAppInfo : public nsIXULAppInfo,
591 #ifdef XP_WIN
592 public nsIWinAppHelper,
593 #endif
594 #ifdef MOZ_CRASHREPORTER
595 public nsICrashReporter,
596 #endif
597 public nsIXULRuntime
600 public:
601 NS_DECL_ISUPPORTS_INHERITED
602 NS_DECL_NSIXULAPPINFO
603 NS_DECL_NSIXULRUNTIME
604 #ifdef MOZ_CRASHREPORTER
605 NS_DECL_NSICRASHREPORTER
606 #endif
607 #ifdef XP_WIN
608 NS_DECL_NSIWINAPPHELPER
609 private:
610 nsresult LaunchAppHelperWithArgs(int aArgc, char **aArgv);
611 #endif
614 NS_INTERFACE_MAP_BEGIN(nsXULAppInfo)
615 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXULRuntime)
616 NS_INTERFACE_MAP_ENTRY(nsIXULRuntime)
617 #ifdef XP_WIN
618 NS_INTERFACE_MAP_ENTRY(nsIWinAppHelper)
619 #endif
620 #ifdef MOZ_CRASHREPORTER
621 NS_INTERFACE_MAP_ENTRY(nsICrashReporter)
622 #endif
623 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIXULAppInfo, gAppData)
624 NS_INTERFACE_MAP_END
626 NS_IMETHODIMP_(nsrefcnt)
627 nsXULAppInfo::AddRef()
629 return 1;
632 NS_IMETHODIMP_(nsrefcnt)
633 nsXULAppInfo::Release()
635 return 1;
638 NS_IMETHODIMP
639 nsXULAppInfo::GetVendor(nsACString& aResult)
641 aResult.Assign(gAppData->vendor);
643 return NS_OK;
646 NS_IMETHODIMP
647 nsXULAppInfo::GetName(nsACString& aResult)
649 aResult.Assign(gAppData->name);
651 return NS_OK;
654 NS_IMETHODIMP
655 nsXULAppInfo::GetID(nsACString& aResult)
657 aResult.Assign(gAppData->ID);
659 return NS_OK;
662 NS_IMETHODIMP
663 nsXULAppInfo::GetVersion(nsACString& aResult)
665 aResult.Assign(gAppData->version);
667 return NS_OK;
670 NS_IMETHODIMP
671 nsXULAppInfo::GetPlatformVersion(nsACString& aResult)
673 aResult.Assign(gToolkitVersion);
675 return NS_OK;
678 NS_IMETHODIMP
679 nsXULAppInfo::GetAppBuildID(nsACString& aResult)
681 aResult.Assign(gAppData->buildID);
683 return NS_OK;
686 NS_IMETHODIMP
687 nsXULAppInfo::GetPlatformBuildID(nsACString& aResult)
689 aResult.Assign(gToolkitBuildID);
691 return NS_OK;
694 NS_IMETHODIMP
695 nsXULAppInfo::GetLogConsoleErrors(PRBool *aResult)
697 *aResult = gLogConsoleErrors;
698 return NS_OK;
701 NS_IMETHODIMP
702 nsXULAppInfo::SetLogConsoleErrors(PRBool aValue)
704 gLogConsoleErrors = aValue;
705 return NS_OK;
708 NS_IMETHODIMP
709 nsXULAppInfo::GetInSafeMode(PRBool *aResult)
711 *aResult = gSafeMode;
712 return NS_OK;
715 NS_IMETHODIMP
716 nsXULAppInfo::GetOS(nsACString& aResult)
718 aResult.AssignLiteral(OS_TARGET);
719 return NS_OK;
722 NS_IMETHODIMP
723 nsXULAppInfo::GetXPCOMABI(nsACString& aResult)
725 #ifdef TARGET_XPCOM_ABI
726 aResult.AssignLiteral(TARGET_XPCOM_ABI);
727 return NS_OK;
728 #else
729 return NS_ERROR_NOT_AVAILABLE;
730 #endif
733 #ifdef XP_WIN
734 nsresult
735 nsXULAppInfo::LaunchAppHelperWithArgs(int aArgc, char **aArgv)
737 nsresult rv;
738 nsCOMPtr<nsIProperties> directoryService =
739 do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
740 NS_ENSURE_SUCCESS(rv, rv);
742 nsCOMPtr<nsILocalFile> appHelper;
743 rv = directoryService->Get(NS_XPCOM_CURRENT_PROCESS_DIR, NS_GET_IID(nsILocalFile), getter_AddRefs(appHelper));
744 NS_ENSURE_SUCCESS(rv, rv);
746 rv = appHelper->AppendNative(NS_LITERAL_CSTRING("uninstall"));
747 NS_ENSURE_SUCCESS(rv, rv);
749 rv = appHelper->AppendNative(NS_LITERAL_CSTRING("helper.exe"));
750 NS_ENSURE_SUCCESS(rv, rv);
752 nsAutoString appHelperPath;
753 rv = appHelper->GetPath(appHelperPath);
754 NS_ENSURE_SUCCESS(rv, rv);
756 if (!WinLaunchChild(appHelperPath.get(), aArgc, aArgv, 1))
757 return NS_ERROR_FAILURE;
758 else
759 return NS_OK;
762 NS_IMETHODIMP
763 nsXULAppInfo::PostUpdate(nsILocalFile *aLogFile)
765 nsresult rv;
766 int upgradeArgc = aLogFile ? 3 : 2;
767 char **upgradeArgv = (char**) malloc(sizeof(char*) * (upgradeArgc + 1));
769 if (!upgradeArgv)
770 return NS_ERROR_OUT_OF_MEMORY;
772 upgradeArgv[0] = "argv0ignoredbywinlaunchchild";
773 upgradeArgv[1] = "/postupdate";
775 char *pathArg = nsnull;
777 if (aLogFile) {
778 nsCAutoString logFilePath;
779 rv = aLogFile->GetNativePath(logFilePath);
780 NS_ENSURE_SUCCESS(rv, rv);
782 pathArg = PR_smprintf("/uninstalllog=%s", logFilePath.get());
783 if (!pathArg)
784 return NS_ERROR_OUT_OF_MEMORY;
786 upgradeArgv[2] = pathArg;
787 upgradeArgv[3] = nsnull;
789 else {
790 upgradeArgv[2] = nsnull;
793 rv = LaunchAppHelperWithArgs(upgradeArgc, upgradeArgv);
795 if (pathArg)
796 PR_smprintf_free(pathArg);
798 free(upgradeArgv);
799 return rv;
802 // Matches the enum in WinNT.h for the Vista SDK but renamed so that we can
803 // safely build with the Vista SDK and without it.
804 typedef enum
806 VistaTokenElevationTypeDefault = 1,
807 VistaTokenElevationTypeFull,
808 VistaTokenElevationTypeLimited
809 } VISTA_TOKEN_ELEVATION_TYPE;
811 // avoid collision with TokeElevationType enum in WinNT.h
812 // of the Vista SDK
813 #define VistaTokenElevationType static_cast< TOKEN_INFORMATION_CLASS >( 18 )
815 NS_IMETHODIMP
816 nsXULAppInfo::GetUserCanElevate(PRBool *aUserCanElevate)
818 #ifdef WINCE
819 *aUserCanElevate = PR_FALSE;
820 return NS_OK;
821 #else
822 HANDLE hToken;
824 VISTA_TOKEN_ELEVATION_TYPE elevationType;
825 DWORD dwSize;
827 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken) ||
828 !GetTokenInformation(hToken, VistaTokenElevationType, &elevationType,
829 sizeof(elevationType), &dwSize)) {
830 *aUserCanElevate = PR_FALSE;
832 else {
833 // The possible values returned for elevationType and their meanings are:
834 // TokenElevationTypeDefault: The token does not have a linked token
835 // (e.g. UAC disabled or a standard user, so they can't be elevated)
836 // TokenElevationTypeFull: The token is linked to an elevated token
837 // (e.g. UAC is enabled and the user is already elevated so they can't
838 // be elevated again)
839 // TokenElevationTypeLimited: The token is linked to a limited token
840 // (e.g. UAC is enabled and the user is not elevated, so they can be
841 // elevated)
842 *aUserCanElevate = (elevationType == VistaTokenElevationTypeLimited);
845 if (hToken)
846 CloseHandle(hToken);
848 return NS_OK;
849 #endif // WINCE
851 #endif
853 #ifdef MOZ_CRASHREPORTER
854 NS_IMETHODIMP
855 nsXULAppInfo::AnnotateCrashReport(const nsACString& key,
856 const nsACString& data)
858 return CrashReporter::AnnotateCrashReport(key, data);
861 NS_IMETHODIMP
862 nsXULAppInfo::AppendAppNotesToCrashReport(const nsACString& data)
864 return CrashReporter::AppendAppNotesToCrashReport(data);
867 NS_IMETHODIMP
868 nsXULAppInfo::WriteMinidumpForException(void* aExceptionInfo)
870 #ifdef XP_WIN32
871 return CrashReporter::WriteMinidumpForException(static_cast<EXCEPTION_POINTERS*>(aExceptionInfo));
872 #else
873 return NS_ERROR_NOT_IMPLEMENTED;
874 #endif
877 NS_IMETHODIMP
878 nsXULAppInfo::AppendObjCExceptionInfoToAppNotes(void* aException)
880 #ifdef XP_MACOSX
881 return CrashReporter::AppendObjCExceptionInfoToAppNotes(aException);
882 #else
883 return NS_ERROR_NOT_IMPLEMENTED;
884 #endif
886 #endif
888 static const nsXULAppInfo kAppInfo;
889 static NS_METHOD AppInfoConstructor(nsISupports* aOuter,
890 REFNSIID aIID, void **aResult)
892 NS_ENSURE_NO_AGGREGATION(aOuter);
894 return const_cast<nsXULAppInfo*>(&kAppInfo)->
895 QueryInterface(aIID, aResult);
898 PRBool gLogConsoleErrors
899 #ifdef DEBUG
900 = PR_TRUE;
901 #else
902 = PR_FALSE;
903 #endif
905 #define NS_ENSURE_TRUE_LOG(x, ret) \
906 PR_BEGIN_MACRO \
907 if (NS_UNLIKELY(!(x))) { \
908 NS_WARNING("NS_ENSURE_TRUE(" #x ") failed"); \
909 gLogConsoleErrors = PR_TRUE; \
910 return ret; \
912 PR_END_MACRO
914 #define NS_ENSURE_SUCCESS_LOG(res, ret) \
915 NS_ENSURE_TRUE_LOG(NS_SUCCEEDED(res), ret)
918 * Because we're starting/stopping XPCOM several times in different scenarios,
919 * this class is a stack-based critter that makes sure that XPCOM is shut down
920 * during early returns.
923 class ScopedXPCOMStartup
925 public:
926 ScopedXPCOMStartup() :
927 mServiceManager(nsnull) { }
928 ~ScopedXPCOMStartup();
930 nsresult Initialize();
931 nsresult DoAutoreg();
932 nsresult RegisterProfileService();
933 nsresult SetWindowCreator(nsINativeAppSupport* native);
935 private:
936 nsIServiceManager* mServiceManager;
939 ScopedXPCOMStartup::~ScopedXPCOMStartup()
941 if (mServiceManager) {
942 nsCOMPtr<nsIAppStartup> appStartup (do_GetService(NS_APPSTARTUP_CONTRACTID));
943 if (appStartup)
944 appStartup->DestroyHiddenWindow();
946 gDirServiceProvider->DoShutdown();
948 WriteConsoleLog();
950 NS_ShutdownXPCOM(mServiceManager);
951 mServiceManager = nsnull;
955 // {95d89e3e-a169-41a3-8e56-719978e15b12}
956 #define APPINFO_CID \
957 { 0x95d89e3e, 0xa169, 0x41a3, { 0x8e, 0x56, 0x71, 0x99, 0x78, 0xe1, 0x5b, 0x12 } }
959 static nsModuleComponentInfo kComponents[] =
962 "nsXULAppInfo",
963 APPINFO_CID,
964 XULAPPINFO_SERVICE_CONTRACTID,
965 AppInfoConstructor
967 #ifdef MOZ_CRASHREPORTER
970 "nsXULAppInfo",
971 APPINFO_CID,
972 NS_CRASHREPORTER_CONTRACTID,
973 AppInfoConstructor
975 #endif
978 NS_IMPL_NSGETMODULE(Apprunner, kComponents)
980 #if !defined(_BUILD_STATIC_BIN) && !defined(MOZ_ENABLE_LIBXUL)
981 static nsStaticModuleInfo const kXREStaticModules[] =
984 "Apprunner",
985 Apprunner_NSGetModule
989 nsStaticModuleInfo const *const kPStaticModules = kXREStaticModules;
990 PRUint32 const kStaticModuleCount = NS_ARRAY_LENGTH(kXREStaticModules);
991 #endif
993 nsresult
994 ScopedXPCOMStartup::Initialize()
996 NS_ASSERTION(gDirServiceProvider, "Should not get here!");
998 nsresult rv;
999 rv = NS_InitXPCOM3(&mServiceManager, gDirServiceProvider->GetAppDir(),
1000 gDirServiceProvider,
1001 kPStaticModules, kStaticModuleCount);
1002 if (NS_FAILED(rv)) {
1003 NS_ERROR("Couldn't start xpcom!");
1004 mServiceManager = nsnull;
1006 else {
1007 nsCOMPtr<nsIComponentRegistrar> reg =
1008 do_QueryInterface(mServiceManager);
1009 NS_ASSERTION(reg, "Service Manager doesn't QI to Registrar.");
1012 return rv;
1015 // {0C4A446C-EE82-41f2-8D04-D366D2C7A7D4}
1016 static const nsCID kNativeAppSupportCID =
1017 { 0xc4a446c, 0xee82, 0x41f2, { 0x8d, 0x4, 0xd3, 0x66, 0xd2, 0xc7, 0xa7, 0xd4 } };
1019 // {5F5E59CE-27BC-47eb-9D1F-B09CA9049836}
1020 static const nsCID kProfileServiceCID =
1021 { 0x5f5e59ce, 0x27bc, 0x47eb, { 0x9d, 0x1f, 0xb0, 0x9c, 0xa9, 0x4, 0x98, 0x36 } };
1023 nsresult
1024 ScopedXPCOMStartup::RegisterProfileService()
1026 NS_ASSERTION(mServiceManager, "Not initialized!");
1028 nsCOMPtr<nsIFactory> factory;
1029 NS_NewToolkitProfileFactory(getter_AddRefs(factory));
1030 if (!factory) return NS_ERROR_OUT_OF_MEMORY;
1032 nsCOMPtr<nsIComponentRegistrar> reg (do_QueryInterface(mServiceManager));
1033 if (!reg) return NS_ERROR_NO_INTERFACE;
1035 return reg->RegisterFactory(kProfileServiceCID,
1036 "Toolkit Profile Service",
1037 NS_PROFILESERVICE_CONTRACTID,
1038 factory);
1041 nsresult
1042 ScopedXPCOMStartup::DoAutoreg()
1044 #ifdef DEBUG
1045 // _Always_ autoreg if we're in a debug build, under the assumption
1046 // that people are busily modifying components and will be angry if
1047 // their changes aren't noticed.
1048 nsCOMPtr<nsIComponentRegistrar> registrar
1049 (do_QueryInterface(mServiceManager));
1050 NS_ASSERTION(registrar, "Where's the component registrar?");
1052 registrar->AutoRegister(nsnull);
1053 #endif
1055 return NS_OK;
1059 * This is a little factory class that serves as a singleton-service-factory
1060 * for the nativeappsupport object.
1062 class nsSingletonFactory : public nsIFactory
1064 public:
1065 NS_DECL_ISUPPORTS
1066 NS_DECL_NSIFACTORY
1068 nsSingletonFactory(nsISupports* aSingleton);
1069 ~nsSingletonFactory() { }
1071 private:
1072 nsCOMPtr<nsISupports> mSingleton;
1075 nsSingletonFactory::nsSingletonFactory(nsISupports* aSingleton)
1076 : mSingleton(aSingleton)
1078 NS_ASSERTION(mSingleton, "Singleton was null!");
1081 NS_IMPL_ISUPPORTS1(nsSingletonFactory, nsIFactory)
1083 NS_IMETHODIMP
1084 nsSingletonFactory::CreateInstance(nsISupports* aOuter,
1085 const nsIID& aIID,
1086 void* *aResult)
1088 NS_ENSURE_NO_AGGREGATION(aOuter);
1090 return mSingleton->QueryInterface(aIID, aResult);
1093 NS_IMETHODIMP
1094 nsSingletonFactory::LockFactory(PRBool)
1096 return NS_OK;
1100 * Set our windowcreator on the WindowWatcher service.
1102 nsresult
1103 ScopedXPCOMStartup::SetWindowCreator(nsINativeAppSupport* native)
1105 nsresult rv;
1107 nsCOMPtr<nsIComponentRegistrar> registrar
1108 (do_QueryInterface(mServiceManager));
1109 NS_ASSERTION(registrar, "Where's the component registrar?");
1111 nsCOMPtr<nsIFactory> nativeFactory = new nsSingletonFactory(native);
1112 NS_ENSURE_TRUE(nativeFactory, NS_ERROR_OUT_OF_MEMORY);
1114 rv = registrar->RegisterFactory(kNativeAppSupportCID,
1115 "Native App Support",
1116 NS_NATIVEAPPSUPPORT_CONTRACTID,
1117 nativeFactory);
1118 NS_ENSURE_SUCCESS(rv, rv);
1120 // Inform the chrome registry about OS accessibility
1121 nsCOMPtr<nsIToolkitChromeRegistry> cr (do_GetService(NS_CHROMEREGISTRY_CONTRACTID));
1122 if (cr)
1123 cr->CheckForOSAccessibility();
1125 nsCOMPtr<nsIWindowCreator> creator (do_GetService(NS_APPSTARTUP_CONTRACTID));
1126 if (!creator) return NS_ERROR_UNEXPECTED;
1128 nsCOMPtr<nsIWindowWatcher> wwatch
1129 (do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
1130 NS_ENSURE_SUCCESS(rv, rv);
1132 return wwatch->SetWindowCreator(creator);
1136 * A helper class which calls NS_LogInit/NS_LogTerm in its scope.
1138 class ScopedLogging
1140 public:
1141 ScopedLogging() { NS_LogInit(); }
1142 ~ScopedLogging() { NS_LogTerm(); }
1145 static void DumpArbitraryHelp()
1147 nsresult rv;
1149 ScopedLogging log;
1152 nsXREDirProvider dirProvider;
1153 dirProvider.Initialize(nsnull, gAppData->xreDirectory);
1155 ScopedXPCOMStartup xpcom;
1156 xpcom.Initialize();
1157 xpcom.DoAutoreg();
1159 nsCOMPtr<nsICommandLineRunner> cmdline
1160 (do_CreateInstance("@mozilla.org/toolkit/command-line;1"));
1161 if (!cmdline)
1162 return;
1164 nsCString text;
1165 rv = cmdline->GetHelpText(text);
1166 if (NS_SUCCEEDED(rv))
1167 printf("%s", text.get());
1171 // English text needs to go into a dtd file.
1172 // But when this is called we have no components etc. These strings must either be
1173 // here, or in a native resource file.
1174 static void
1175 DumpHelp()
1177 printf("Usage: %s [ options ... ] [URL]\n"
1178 " where options include:\n\n", gArgv[0]);
1180 #ifdef MOZ_X11
1181 printf("X11 options\n"
1182 "\t--display=DISPLAY\t\tX display to use\n"
1183 "\t--sync\t\tMake X calls synchronous\n"
1184 "\t--no-xshm\t\tDon't use X shared memory extension\n"
1185 "\t--xim-preedit=STYLE\n"
1186 "\t--xim-status=STYLE\n");
1187 #endif
1188 #ifdef XP_UNIX
1189 printf("\t--g-fatal-warnings\t\tMake all warnings fatal\n"
1190 "\n%s options\n", gAppData->name);
1191 #endif
1193 printf("\t-h or -help\t\tPrint this message.\n"
1194 "\t-v or -version\t\tPrint %s version.\n"
1195 "\t-P <profile>\t\tStart with <profile>.\n"
1196 "\t-migration\t\tStart with migration wizard.\n"
1197 "\t-ProfileManager\t\tStart with ProfileManager.\n"
1198 "\t-no-remote\t\tOpen new instance, not a new window in running instance.\n"
1199 "\t-UILocale <locale>\tStart with <locale> resources as UI Locale.\n"
1200 "\t-safe-mode\t\tDisables extensions and themes for this session.\n", gAppData->name);
1202 #if defined(XP_WIN) || defined(XP_OS2)
1203 printf("\t-console\t\tStart %s with a debugging console.\n", gAppData->name);
1204 #endif
1206 // this works, but only after the components have registered. so if you drop in a new command line handler, -help
1207 // won't not until the second run.
1208 // out of the bug, because we ship a component.reg file, it works correctly.
1209 DumpArbitraryHelp();
1212 #ifdef DEBUG_warren
1213 #ifdef XP_WIN
1214 #define _CRTDBG_MAP_ALLOC
1215 #include <crtdbg.h>
1216 #endif
1217 #endif
1219 #if defined(FREEBSD)
1220 // pick up fpsetmask prototype.
1221 #include <ieeefp.h>
1222 #endif
1224 static inline void
1225 DumpVersion()
1227 printf("%s %s %s",
1228 gAppData->vendor ? gAppData->vendor : "", gAppData->name, gAppData->version);
1229 if (gAppData->copyright)
1230 printf(", %s", gAppData->copyright);
1231 printf("\n");
1234 #ifdef MOZ_ENABLE_XREMOTE
1235 // use int here instead of a PR type since it will be returned
1236 // from main - just to keep types consistent
1237 static int
1238 HandleRemoteArgument(const char* remote, const char* aDesktopStartupID)
1240 nsresult rv;
1241 ArgResult ar;
1243 const char *profile = 0;
1244 nsCAutoString program(gAppData->name);
1245 ToLowerCase(program);
1246 const char *username = getenv("LOGNAME");
1248 ar = CheckArg("p", PR_FALSE, &profile);
1249 if (ar == ARG_BAD) {
1250 PR_fprintf(PR_STDERR, "Error: argument -p requires a profile name\n");
1251 return 1;
1254 const char *temp = nsnull;
1255 ar = CheckArg("a", PR_FALSE, &temp);
1256 if (ar == ARG_BAD) {
1257 PR_fprintf(PR_STDERR, "Error: argument -a requires an application name\n");
1258 return 1;
1259 } else if (ar == ARG_FOUND) {
1260 program.Assign(temp);
1263 ar = CheckArg("u", PR_FALSE, &username);
1264 if (ar == ARG_BAD) {
1265 PR_fprintf(PR_STDERR, "Error: argument -u requires a username\n");
1266 return 1;
1269 XRemoteClient client;
1270 rv = client.Init();
1271 if (NS_FAILED(rv)) {
1272 PR_fprintf(PR_STDERR, "Error: Failed to connect to X server.\n");
1273 return 1;
1276 nsXPIDLCString response;
1277 PRBool success = PR_FALSE;
1278 rv = client.SendCommand(program.get(), username, profile, remote,
1279 aDesktopStartupID, getter_Copies(response), &success);
1280 // did the command fail?
1281 if (NS_FAILED(rv)) {
1282 PR_fprintf(PR_STDERR, "Error: Failed to send command: %s\n",
1283 response ? response.get() : "No response included");
1284 return 1;
1287 if (!success) {
1288 PR_fprintf(PR_STDERR, "Error: No running window found\n");
1289 return 2;
1292 return 0;
1295 static RemoteResult
1296 RemoteCommandLine(const char* aDesktopStartupID)
1298 nsresult rv;
1299 ArgResult ar;
1301 nsCAutoString program(gAppData->name);
1302 ToLowerCase(program);
1303 const char *username = getenv("LOGNAME");
1305 const char *temp = nsnull;
1306 ar = CheckArg("a", PR_TRUE, &temp);
1307 if (ar == ARG_BAD) {
1308 PR_fprintf(PR_STDERR, "Error: argument -a requires an application name\n");
1309 return REMOTE_ARG_BAD;
1310 } else if (ar == ARG_FOUND) {
1311 program.Assign(temp);
1314 ar = CheckArg("u", PR_TRUE, &username);
1315 if (ar == ARG_BAD) {
1316 PR_fprintf(PR_STDERR, "Error: argument -u requires a username\n");
1317 return REMOTE_ARG_BAD;
1320 XRemoteClient client;
1321 rv = client.Init();
1322 if (NS_FAILED(rv))
1323 return REMOTE_NOT_FOUND;
1325 nsXPIDLCString response;
1326 PRBool success = PR_FALSE;
1327 rv = client.SendCommandLine(program.get(), username, nsnull,
1328 gArgc, gArgv, aDesktopStartupID,
1329 getter_Copies(response), &success);
1330 // did the command fail?
1331 if (NS_FAILED(rv) || !success)
1332 return REMOTE_NOT_FOUND;
1334 return REMOTE_FOUND;
1336 #endif // MOZ_ENABLE_XREMOTE
1338 #ifdef XP_MACOSX
1339 static char const *gBinaryPath;
1340 #endif
1342 nsresult
1343 XRE_GetBinaryPath(const char* argv0, nsILocalFile* *aResult)
1345 nsresult rv;
1346 nsCOMPtr<nsILocalFile> lf;
1348 // We need to use platform-specific hackery to find the
1349 // path of this executable. This is copied, with some modifications, from
1350 // nsGREDirServiceProvider.cpp
1352 #ifdef XP_WIN
1353 PRUnichar exePath[MAXPATHLEN];
1355 if (!::GetModuleFileNameW(0, exePath, MAXPATHLEN))
1356 return NS_ERROR_FAILURE;
1358 rv = NS_NewLocalFile(nsDependentString(exePath), PR_TRUE,
1359 getter_AddRefs(lf));
1360 if (NS_FAILED(rv))
1361 return rv;
1363 #elif defined(XP_MACOSX)
1364 if (gBinaryPath)
1365 return NS_NewNativeLocalFile(nsDependentCString(gBinaryPath), PR_FALSE,
1366 aResult);
1368 NS_NewNativeLocalFile(EmptyCString(), PR_TRUE, getter_AddRefs(lf));
1369 nsCOMPtr<nsILocalFileMac> lfm (do_QueryInterface(lf));
1370 if (!lfm)
1371 return NS_ERROR_FAILURE;
1373 // Works even if we're not bundled.
1374 CFBundleRef appBundle = CFBundleGetMainBundle();
1375 if (!appBundle)
1376 return NS_ERROR_FAILURE;
1378 CFURLRef bundleURL = CFBundleCopyExecutableURL(appBundle);
1379 if (!bundleURL)
1380 return NS_ERROR_FAILURE;
1382 FSRef fileRef;
1383 if (!CFURLGetFSRef(bundleURL, &fileRef)) {
1384 CFRelease(bundleURL);
1385 return NS_ERROR_FAILURE;
1388 rv = lfm->InitWithFSRef(&fileRef);
1389 CFRelease(bundleURL);
1391 if (NS_FAILED(rv))
1392 return rv;
1394 #elif defined(XP_UNIX)
1395 struct stat fileStat;
1396 char exePath[MAXPATHLEN];
1397 char tmpPath[MAXPATHLEN];
1399 rv = NS_ERROR_FAILURE;
1401 // on unix, there is no official way to get the path of the current binary.
1402 // instead of using the MOZILLA_FIVE_HOME hack, which doesn't scale to
1403 // multiple applications, we will try a series of techniques:
1405 // 1) look for /proc/<pid>/exe which is a symlink to the executable on newer
1406 // Linux kernels
1407 // 2) use realpath() on argv[0], which works unless we're loaded from the
1408 // PATH
1409 // 3) manually walk through the PATH and look for ourself
1410 // 4) give up
1412 // #ifdef __linux__
1413 #if 0
1414 int r = readlink("/proc/self/exe", exePath, MAXPATHLEN);
1416 // apparently, /proc/self/exe can sometimes return weird data... check it
1417 if (r > 0 && r < MAXPATHLEN && stat(exePath, &fileStat) == 0) {
1418 rv = NS_OK;
1421 #endif
1422 if (NS_FAILED(rv) &&
1423 realpath(argv0, exePath) && stat(exePath, &fileStat) == 0) {
1424 rv = NS_OK;
1427 if (NS_FAILED(rv)) {
1428 const char *path = getenv("PATH");
1429 if (!path)
1430 return NS_ERROR_FAILURE;
1432 char *pathdup = strdup(path);
1433 if (!pathdup)
1434 return NS_ERROR_OUT_OF_MEMORY;
1436 PRBool found = PR_FALSE;
1437 char *newStr = pathdup;
1438 char *token;
1439 while ( (token = nsCRT::strtok(newStr, ":", &newStr)) ) {
1440 sprintf(tmpPath, "%s/%s", token, argv0);
1441 if (realpath(tmpPath, exePath) && stat(exePath, &fileStat) == 0) {
1442 found = PR_TRUE;
1443 break;
1446 free(pathdup);
1447 if (!found)
1448 return NS_ERROR_FAILURE;
1451 rv = NS_NewNativeLocalFile(nsDependentCString(exePath), PR_TRUE,
1452 getter_AddRefs(lf));
1453 if (NS_FAILED(rv))
1454 return rv;
1456 #elif defined(XP_OS2)
1457 PPIB ppib;
1458 PTIB ptib;
1459 char exePath[MAXPATHLEN];
1461 DosGetInfoBlocks( &ptib, &ppib);
1462 DosQueryModuleName( ppib->pib_hmte, MAXPATHLEN, exePath);
1463 rv = NS_NewNativeLocalFile(nsDependentCString(exePath), PR_TRUE,
1464 getter_AddRefs(lf));
1465 if (NS_FAILED(rv))
1466 return rv;
1468 #elif defined(XP_BEOS)
1469 int32 cookie = 0;
1470 image_info info;
1472 if(get_next_image_info(0, &cookie, &info) != B_OK)
1473 return NS_ERROR_FAILURE;
1475 rv = NS_NewNativeLocalFile(nsDependentCString(info.name), PR_TRUE,
1476 getter_AddRefs(lf));
1477 if (NS_FAILED(rv))
1478 return rv;
1480 #elif
1481 #error Oops, you need platform-specific code here
1482 #endif
1484 NS_ADDREF(*aResult = lf);
1485 return NS_OK;
1488 #define NS_ERROR_LAUNCHED_CHILD_PROCESS NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_PROFILE, 200)
1490 #ifdef XP_WIN
1491 #include "nsWindowsRestart.cpp"
1492 #endif
1494 #if defined(XP_OS2) && (__GNUC__ == 3 && __GNUC_MINOR__ == 3) // broken OS/2 GCC
1495 // Copy the environment maintained by the C library into an ASCIIZ array
1496 // that can be used to pass it on to the OS/2 Dos* APIs (which otherwise
1497 // don't know anything about the stuff set by PR_SetEnv() or setenv()).
1498 char *createEnv()
1500 // just allocate the maximum amount (24 kB = 0x60000 bytes), to be able to
1501 // copy the existing environment
1502 char *env = (char *)calloc(0x6000, sizeof(char));
1503 if (!env) {
1504 return NULL;
1507 // walk along the environ string array of the C library and copy
1508 // everything (that fits) into the output environment array, leaving
1509 // null bytes between the entries
1510 char *penv = env; // movable pointer to result environment ASCIIZ array
1511 int i = 0, space = 0x6000;
1512 while (environ[i] && environ[i][0]) {
1513 int len = strlen(environ[i]);
1514 if (space - len <= 0) {
1515 break;
1517 strcpy(penv, environ[i]);
1518 i++; // next environment variable
1519 penv += len + 1; // jump to after next null byte
1520 space -= len - 1; // subtract consumed length from usable space
1523 return env;
1526 // OS2LaunchChild() is there to replace _execv() which is broken in the C
1527 // runtime library that comes with GCC 3.3.5 on OS/2. It uses createEnv()
1528 // to copy the process environment and add necessary variables
1530 // returns -1 on failure and 0 on success
1531 int OS2LaunchChild(const char *aExePath, int aArgc, char **aArgv)
1533 // find total length of aArgv
1534 int len = 0;
1535 for (int i = 0; i < aArgc; i++) {
1536 len += strlen(aArgv[i]) + 1; // plus space in between
1538 len++; // leave space for null byte at end
1539 // allocate enough space for all strings and nulls,
1540 // calloc helpfully initializes to null
1541 char *args = (char *)calloc(len, sizeof(char));
1542 if (!args) {
1543 return -1;
1545 char *pargs = args; // extra pointer to after the last argument
1546 // build argument list in the format the DosStartSession() wants,
1547 // adding spaces between the arguments
1548 for (int i = 0; i < aArgc; i++, *pargs++ = ' ') {
1549 strcpy(pargs, aArgv[i]);
1550 pargs += strlen(aArgv[i]);
1552 if (aArgc > 1) {
1553 *(pargs-1) = '\0'; // replace last space
1555 *pargs = '\0';
1556 // make sure that the program is separated by null byte
1557 pargs = strchr(args, ' ');
1558 if (pargs) {
1559 *pargs = '\0';
1562 char *env = createEnv();
1564 char error[CCHMAXPATH] = { 0 };
1565 RESULTCODES crc = { 0 };
1566 ULONG rc = DosExecPgm(error, sizeof(error), EXEC_ASYNC, args, env,
1567 &crc, (PSZ)aExePath);
1568 free(args); // done with the arguments
1569 if (env) {
1570 free(env);
1572 if (rc != NO_ERROR) {
1573 return -1;
1576 return 0;
1578 #endif
1580 // If aBlankCommandLine is true, then the application will be launched with a
1581 // blank command line instead of being launched with the same command line that
1582 // it was initially started with.
1583 static nsresult LaunchChild(nsINativeAppSupport* aNative,
1584 PRBool aBlankCommandLine = PR_FALSE)
1586 aNative->Quit(); // release DDE mutex, if we're holding it
1588 // Restart this process by exec'ing it into the current process
1589 // if supported by the platform. Otherwise, use NSPR.
1591 if (aBlankCommandLine) {
1592 gRestartArgc = 1;
1593 gRestartArgv[gRestartArgc] = nsnull;
1596 PR_SetEnv("MOZ_LAUNCHED_CHILD=1");
1598 #if defined(XP_MACOSX)
1599 LaunchChildMac(gRestartArgc, gRestartArgv);
1600 #else
1601 nsCOMPtr<nsILocalFile> lf;
1602 nsresult rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf));
1603 if (NS_FAILED(rv))
1604 return rv;
1606 #if defined(XP_WIN)
1607 nsAutoString exePath;
1608 rv = lf->GetPath(exePath);
1609 if (NS_FAILED(rv))
1610 return rv;
1612 if (!WinLaunchChild(exePath.get(), gRestartArgc, gRestartArgv, 0))
1613 return NS_ERROR_FAILURE;
1615 #else
1616 nsCAutoString exePath;
1617 rv = lf->GetNativePath(exePath);
1618 if (NS_FAILED(rv))
1619 return rv;
1621 #if defined(XP_OS2) && (__GNUC__ == 3 && __GNUC_MINOR__ == 3)
1622 // implementation of _execv() is broken with GCC 3.3.x on OS/2
1623 if (OS2LaunchChild(exePath.get(), gRestartArgc, gRestartArgv) == -1)
1624 return NS_ERROR_FAILURE;
1625 #elif defined(XP_OS2)
1626 if (_execv(exePath.get(), gRestartArgv) == -1)
1627 return NS_ERROR_FAILURE;
1628 #elif defined(XP_UNIX)
1629 if (execv(exePath.get(), gRestartArgv) == -1)
1630 return NS_ERROR_FAILURE;
1631 #elif defined(XP_BEOS)
1632 extern char **environ;
1633 status_t res;
1634 res = resume_thread(load_image(gRestartArgc,(const char **)gRestartArgv,(const char **)environ));
1635 if (res != B_OK)
1636 return NS_ERROR_FAILURE;
1637 #else
1638 PRProcess* process = PR_CreateProcess(exePath.get(), gRestartArgv,
1639 nsnull, nsnull);
1640 if (!process) return NS_ERROR_FAILURE;
1642 PRInt32 exitCode;
1643 PRStatus failed = PR_WaitProcess(process, &exitCode);
1644 if (failed || exitCode)
1645 return NS_ERROR_FAILURE;
1646 #endif // XP_OS2 series
1647 #endif // WP_WIN
1648 #endif // WP_MACOSX
1650 return NS_ERROR_LAUNCHED_CHILD_PROCESS;
1653 static const char kProfileProperties[] =
1654 "chrome://mozapps/locale/profile/profileSelection.properties";
1656 static nsresult
1657 ProfileLockedDialog(nsILocalFile* aProfileDir, nsILocalFile* aProfileLocalDir,
1658 nsIProfileUnlocker* aUnlocker,
1659 nsINativeAppSupport* aNative, nsIProfileLock* *aResult)
1661 nsresult rv;
1663 ScopedXPCOMStartup xpcom;
1664 rv = xpcom.Initialize();
1665 NS_ENSURE_SUCCESS(rv, rv);
1667 rv = xpcom.DoAutoreg();
1668 rv |= xpcom.SetWindowCreator(aNative);
1669 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
1671 { //extra scoping is needed so we release these components before xpcom shutdown
1672 nsCOMPtr<nsIStringBundleService> sbs
1673 (do_GetService(NS_STRINGBUNDLE_CONTRACTID));
1674 NS_ENSURE_TRUE(sbs, NS_ERROR_FAILURE);
1676 nsCOMPtr<nsIStringBundle> sb;
1677 sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb));
1678 NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE);
1680 NS_ConvertUTF8toUTF16 appName(gAppData->name);
1681 const PRUnichar* params[] = {appName.get(), appName.get()};
1683 nsXPIDLString killMessage;
1684 #ifndef XP_MACOSX
1685 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"
1686 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"
1687 #else
1688 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"
1689 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"
1690 #endif
1692 sb->FormatStringFromName(aUnlocker ? kRestartUnlocker : kRestartNoUnlocker,
1693 params, 2, getter_Copies(killMessage));
1695 nsXPIDLString killTitle;
1696 sb->FormatStringFromName(NS_LITERAL_STRING("restartTitle").get(),
1697 params, 1, getter_Copies(killTitle));
1699 if (!killMessage || !killTitle)
1700 return NS_ERROR_FAILURE;
1702 nsCOMPtr<nsIPromptService> ps
1703 (do_GetService(NS_PROMPTSERVICE_CONTRACTID));
1704 NS_ENSURE_TRUE(ps, NS_ERROR_FAILURE);
1706 PRUint32 flags = nsIPromptService::BUTTON_TITLE_OK * nsIPromptService::BUTTON_POS_0;
1708 if (aUnlocker) {
1709 flags =
1710 nsIPromptService::BUTTON_TITLE_CANCEL * nsIPromptService::BUTTON_POS_0 +
1711 nsIPromptService::BUTTON_TITLE_IS_STRING * nsIPromptService::BUTTON_POS_1 +
1712 nsIPromptService::BUTTON_POS_1_DEFAULT;
1715 PRInt32 button;
1716 rv = ps->ConfirmEx(nsnull, killTitle, killMessage, flags,
1717 killTitle, nsnull, nsnull, nsnull, nsnull, &button);
1718 NS_ENSURE_SUCCESS_LOG(rv, rv);
1720 if (button == 1 && aUnlocker) {
1721 rv = aUnlocker->Unlock(nsIProfileUnlocker::FORCE_QUIT);
1722 if (NS_FAILED(rv)) return rv;
1724 return NS_LockProfilePath(aProfileDir, aProfileLocalDir, nsnull, aResult);
1727 return NS_ERROR_ABORT;
1731 static const char kProfileManagerURL[] =
1732 "chrome://mozapps/content/profile/profileSelection.xul";
1734 static nsresult
1735 ShowProfileManager(nsIToolkitProfileService* aProfileSvc,
1736 nsINativeAppSupport* aNative)
1738 nsresult rv;
1740 nsCOMPtr<nsILocalFile> profD, profLD;
1741 PRUnichar* profileNamePtr;
1742 nsCAutoString profileName;
1745 ScopedXPCOMStartup xpcom;
1746 rv = xpcom.Initialize();
1747 NS_ENSURE_SUCCESS(rv, rv);
1749 rv = xpcom.DoAutoreg();
1750 rv |= xpcom.RegisterProfileService();
1751 rv |= xpcom.SetWindowCreator(aNative);
1752 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
1754 #ifdef XP_MACOSX
1755 SetupMacCommandLine(gRestartArgc, gRestartArgv);
1756 #endif
1758 #ifdef XP_WIN
1759 // we don't have to wait here because profile manager window will pump
1760 // and DDE message will be handled
1761 ProcessDDE(aNative, PR_FALSE);
1762 #endif
1764 { //extra scoping is needed so we release these components before xpcom shutdown
1765 nsCOMPtr<nsIWindowWatcher> windowWatcher
1766 (do_GetService(NS_WINDOWWATCHER_CONTRACTID));
1767 nsCOMPtr<nsIDialogParamBlock> ioParamBlock
1768 (do_CreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID));
1769 nsCOMPtr<nsIMutableArray> dlgArray (do_CreateInstance(NS_ARRAY_CONTRACTID));
1770 NS_ENSURE_TRUE(windowWatcher && ioParamBlock && dlgArray, NS_ERROR_FAILURE);
1772 ioParamBlock->SetObjects(dlgArray);
1774 nsCOMPtr<nsIAppStartup> appStartup
1775 (do_GetService(NS_APPSTARTUP_CONTRACTID));
1776 NS_ENSURE_TRUE(appStartup, NS_ERROR_FAILURE);
1778 nsCOMPtr<nsIDOMWindow> newWindow;
1779 rv = windowWatcher->OpenWindow(nsnull,
1780 kProfileManagerURL,
1781 "_blank",
1782 "centerscreen,chrome,modal,titlebar",
1783 ioParamBlock,
1784 getter_AddRefs(newWindow));
1786 NS_ENSURE_SUCCESS_LOG(rv, rv);
1788 aProfileSvc->Flush();
1790 PRInt32 dialogConfirmed;
1791 rv = ioParamBlock->GetInt(0, &dialogConfirmed);
1792 if (NS_FAILED(rv) || dialogConfirmed == 0) return NS_ERROR_ABORT;
1794 nsCOMPtr<nsIProfileLock> lock;
1795 rv = dlgArray->QueryElementAt(0, NS_GET_IID(nsIProfileLock),
1796 getter_AddRefs(lock));
1797 NS_ENSURE_SUCCESS_LOG(rv, rv);
1799 rv = lock->GetDirectory(getter_AddRefs(profD));
1800 NS_ENSURE_SUCCESS(rv, rv);
1802 rv = lock->GetLocalDirectory(getter_AddRefs(profLD));
1803 NS_ENSURE_SUCCESS(rv, rv);
1805 rv = ioParamBlock->GetString(0, &profileNamePtr);
1806 NS_ENSURE_SUCCESS(rv, rv);
1808 CopyUTF16toUTF8(profileNamePtr, profileName);
1809 NS_Free(profileNamePtr);
1811 lock->Unlock();
1815 SaveFileToEnv("XRE_PROFILE_PATH", profD);
1816 SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", profLD);
1817 SaveWordToEnv("XRE_PROFILE_NAME", profileName);
1819 PRBool offline = PR_FALSE;
1820 aProfileSvc->GetStartOffline(&offline);
1821 if (offline) {
1822 PR_SetEnv("XRE_START_OFFLINE=1");
1825 return LaunchChild(aNative);
1828 static nsresult
1829 ImportProfiles(nsIToolkitProfileService* aPService,
1830 nsINativeAppSupport* aNative)
1832 nsresult rv;
1834 PR_SetEnv("XRE_IMPORT_PROFILES=1");
1836 // try to import old-style profiles
1837 { // scope XPCOM
1838 ScopedXPCOMStartup xpcom;
1839 rv = xpcom.Initialize();
1840 if (NS_SUCCEEDED(rv)) {
1841 xpcom.DoAutoreg();
1842 xpcom.RegisterProfileService();
1844 #ifdef XP_MACOSX
1845 SetupMacCommandLine(gRestartArgc, gRestartArgv);
1846 #endif
1848 nsCOMPtr<nsIProfileMigrator> migrator
1849 (do_GetService(NS_PROFILEMIGRATOR_CONTRACTID));
1850 if (migrator) {
1851 migrator->Import();
1856 aPService->Flush();
1857 return LaunchChild(aNative);
1860 // Pick a profile. We need to end up with a profile lock.
1862 // 1) check for -profile <path>
1863 // 2) check for -P <name>
1864 // 3) check for -ProfileManager
1865 // 4) use the default profile, if there is one
1866 // 5) if there are *no* profiles, set up profile-migration
1867 // 6) display the profile-manager UI
1869 static PRBool gDoMigration = PR_FALSE;
1871 static nsresult
1872 SelectProfile(nsIProfileLock* *aResult, nsINativeAppSupport* aNative,
1873 PRBool* aStartOffline, nsACString* aProfileName)
1875 nsresult rv;
1876 ArgResult ar;
1877 const char* arg;
1878 *aResult = nsnull;
1879 *aStartOffline = PR_FALSE;
1881 ar = CheckArg("offline", PR_TRUE);
1882 if (ar == ARG_BAD) {
1883 PR_fprintf(PR_STDERR, "Error: argument -offline is invalid when argument -osint is specified\n");
1884 return NS_ERROR_FAILURE;
1887 arg = PR_GetEnv("XRE_START_OFFLINE");
1888 if ((arg && *arg) || ar)
1889 *aStartOffline = PR_TRUE;
1892 nsCOMPtr<nsILocalFile> lf = GetFileFromEnv("XRE_PROFILE_PATH");
1893 if (lf) {
1894 nsCOMPtr<nsILocalFile> localDir =
1895 GetFileFromEnv("XRE_PROFILE_LOCAL_PATH");
1896 if (!localDir) {
1897 localDir = lf;
1900 arg = PR_GetEnv("XRE_PROFILE_NAME");
1901 if (arg && *arg && aProfileName)
1902 aProfileName->Assign(nsDependentCString(arg));
1904 // Clear out flags that we handled (or should have handled!) last startup.
1905 const char *dummy;
1906 CheckArg("p", PR_FALSE, &dummy);
1907 CheckArg("profile", PR_FALSE, &dummy);
1908 CheckArg("profilemanager");
1910 return NS_LockProfilePath(lf, localDir, nsnull, aResult);
1913 ar = CheckArg("migration", PR_TRUE);
1914 if (ar == ARG_BAD) {
1915 PR_fprintf(PR_STDERR, "Error: argument -migration is invalid when argument -osint is specified\n");
1916 return NS_ERROR_FAILURE;
1917 } else if (ar == ARG_FOUND) {
1918 gDoMigration = PR_TRUE;
1921 ar = CheckArg("profile", PR_TRUE, &arg);
1922 if (ar == ARG_BAD) {
1923 PR_fprintf(PR_STDERR, "Error: argument -profile requires a path\n");
1924 return NS_ERROR_FAILURE;
1926 if (ar) {
1927 nsCOMPtr<nsILocalFile> lf;
1928 rv = XRE_GetFileFromPath(arg, getter_AddRefs(lf));
1929 NS_ENSURE_SUCCESS(rv, rv);
1931 nsCOMPtr<nsIProfileUnlocker> unlocker;
1933 // If a profile path is specified directory on the command line, then
1934 // assume that the temp directory is the same as the given directory.
1935 rv = NS_LockProfilePath(lf, lf, getter_AddRefs(unlocker), aResult);
1936 if (NS_SUCCEEDED(rv))
1937 return rv;
1939 return ProfileLockedDialog(lf, lf, unlocker, aNative, aResult);
1942 nsCOMPtr<nsIToolkitProfileService> profileSvc;
1943 rv = NS_NewToolkitProfileService(getter_AddRefs(profileSvc));
1944 NS_ENSURE_SUCCESS(rv, rv);
1946 ar = CheckArg("createprofile", PR_TRUE, &arg);
1947 if (ar == ARG_BAD) {
1948 PR_fprintf(PR_STDERR, "Error: argument -createprofile requires a profile name\n");
1949 return NS_ERROR_FAILURE;
1951 if (ar) {
1952 nsCOMPtr<nsIToolkitProfile> profile;
1954 const char* delim = strchr(arg, ' ');
1955 if (delim) {
1956 nsCOMPtr<nsILocalFile> lf;
1957 rv = NS_NewNativeLocalFile(nsDependentCString(delim + 1),
1958 PR_TRUE, getter_AddRefs(lf));
1959 if (NS_FAILED(rv)) {
1960 PR_fprintf(PR_STDERR, "Error: profile path not valid.\n");
1961 return rv;
1964 // As with -profile, assume that the given path will be used for both the
1965 // main profile directory and the temp profile directory.
1966 rv = profileSvc->CreateProfile(lf, lf, nsDependentCSubstring(arg, delim),
1967 getter_AddRefs(profile));
1968 } else {
1969 rv = profileSvc->CreateProfile(nsnull, nsnull, nsDependentCString(arg),
1970 getter_AddRefs(profile));
1972 // Some pathological arguments can make it this far
1973 if (NS_FAILED(rv)) {
1974 PR_fprintf(PR_STDERR, "Error creating profile.\n");
1975 return rv;
1977 rv = NS_ERROR_ABORT;
1978 profileSvc->Flush();
1980 // XXXben need to ensure prefs.js exists here so the tinderboxes will
1981 // not go orange.
1982 nsCOMPtr<nsILocalFile> prefsJSFile;
1983 profile->GetRootDir(getter_AddRefs(prefsJSFile));
1984 prefsJSFile->AppendNative(NS_LITERAL_CSTRING("prefs.js"));
1985 nsCAutoString pathStr;
1986 prefsJSFile->GetNativePath(pathStr);
1987 PR_fprintf(PR_STDERR, "Success: created profile '%s' at '%s'\n", arg, pathStr.get());
1988 PRBool exists;
1989 prefsJSFile->Exists(&exists);
1990 if (!exists)
1991 prefsJSFile->Create(nsIFile::NORMAL_FILE_TYPE, 0644);
1992 // XXXdarin perhaps 0600 would be better?
1994 return rv;
1997 PRUint32 count;
1998 rv = profileSvc->GetProfileCount(&count);
1999 NS_ENSURE_SUCCESS(rv, rv);
2001 if (gAppData->flags & NS_XRE_ENABLE_PROFILE_MIGRATOR) {
2002 arg = PR_GetEnv("XRE_IMPORT_PROFILES");
2003 if (!count && (!arg || !*arg)) {
2004 return ImportProfiles(profileSvc, aNative);
2008 ar = CheckArg("p", PR_FALSE, &arg);
2009 if (ar == ARG_BAD) {
2010 ar = CheckArg("osint");
2011 if (ar == ARG_FOUND) {
2012 PR_fprintf(PR_STDERR, "Error: argument -p is invalid when argument -osint is specified\n");
2013 return NS_ERROR_FAILURE;
2015 return ShowProfileManager(profileSvc, aNative);
2017 if (ar) {
2018 ar = CheckArg("osint");
2019 if (ar == ARG_FOUND) {
2020 PR_fprintf(PR_STDERR, "Error: argument -p is invalid when argument -osint is specified\n");
2021 return NS_ERROR_FAILURE;
2023 nsCOMPtr<nsIToolkitProfile> profile;
2024 rv = profileSvc->GetProfileByName(nsDependentCString(arg),
2025 getter_AddRefs(profile));
2026 if (NS_SUCCEEDED(rv)) {
2027 nsCOMPtr<nsIProfileUnlocker> unlocker;
2028 rv = profile->Lock(nsnull, aResult);
2029 if (NS_SUCCEEDED(rv)) {
2030 if (aProfileName)
2031 aProfileName->Assign(nsDependentCString(arg));
2032 return NS_OK;
2035 nsCOMPtr<nsILocalFile> profileDir;
2036 rv = profile->GetRootDir(getter_AddRefs(profileDir));
2037 NS_ENSURE_SUCCESS(rv, rv);
2039 nsCOMPtr<nsILocalFile> profileLocalDir;
2040 rv = profile->GetLocalDir(getter_AddRefs(profileLocalDir));
2041 NS_ENSURE_SUCCESS(rv, rv);
2043 return ProfileLockedDialog(profileDir, profileLocalDir, unlocker,
2044 aNative, aResult);
2047 return ShowProfileManager(profileSvc, aNative);
2050 ar = CheckArg("profilemanager", PR_TRUE);
2051 if (ar == ARG_BAD) {
2052 PR_fprintf(PR_STDERR, "Error: argument -profilemanager is invalid when argument -osint is specified\n");
2053 return NS_ERROR_FAILURE;
2054 } else if (ar == ARG_FOUND) {
2055 return ShowProfileManager(profileSvc, aNative);
2058 if (!count) {
2059 gDoMigration = PR_TRUE;
2061 // create a default profile
2062 nsCOMPtr<nsIToolkitProfile> profile;
2063 nsresult rv = profileSvc->CreateProfile(nsnull, // choose a default dir for us
2064 nsnull, // choose a default dir for us
2065 NS_LITERAL_CSTRING("default"),
2066 getter_AddRefs(profile));
2067 if (NS_SUCCEEDED(rv)) {
2068 profileSvc->Flush();
2069 rv = profile->Lock(nsnull, aResult);
2070 if (NS_SUCCEEDED(rv)) {
2071 if (aProfileName)
2072 aProfileName->Assign(NS_LITERAL_CSTRING("default"));
2073 return NS_OK;
2078 PRBool useDefault = PR_TRUE;
2079 if (count > 1)
2080 profileSvc->GetStartWithLastProfile(&useDefault);
2082 if (useDefault) {
2083 nsCOMPtr<nsIToolkitProfile> profile;
2084 // GetSelectedProfile will auto-select the only profile if there's just one
2085 profileSvc->GetSelectedProfile(getter_AddRefs(profile));
2086 if (profile) {
2087 nsCOMPtr<nsIProfileUnlocker> unlocker;
2088 rv = profile->Lock(getter_AddRefs(unlocker), aResult);
2089 if (NS_SUCCEEDED(rv)) {
2090 // Try to grab the profile name.
2091 if (aProfileName) {
2092 rv = profile->GetName(*aProfileName);
2093 if (NS_FAILED(rv))
2094 aProfileName->Truncate(0);
2096 return NS_OK;
2099 nsCOMPtr<nsILocalFile> profileDir;
2100 rv = profile->GetRootDir(getter_AddRefs(profileDir));
2101 NS_ENSURE_SUCCESS(rv, rv);
2103 nsCOMPtr<nsILocalFile> profileLocalDir;
2104 rv = profile->GetRootDir(getter_AddRefs(profileLocalDir));
2105 NS_ENSURE_SUCCESS(rv, rv);
2107 return ProfileLockedDialog(profileDir, profileLocalDir, unlocker,
2108 aNative, aResult);
2112 return ShowProfileManager(profileSvc, aNative);
2115 #define FILE_COMPATIBILITY_INFO NS_LITERAL_CSTRING("compatibility.ini")
2117 static PRBool
2118 CheckCompatibility(nsIFile* aProfileDir, const nsCString& aVersion,
2119 const nsCString& aOSABI, nsIFile* aXULRunnerDir,
2120 nsIFile* aAppDir)
2122 nsCOMPtr<nsIFile> file;
2123 aProfileDir->Clone(getter_AddRefs(file));
2124 if (!file)
2125 return PR_FALSE;
2126 file->AppendNative(FILE_COMPATIBILITY_INFO);
2128 nsINIParser parser;
2129 nsCOMPtr<nsILocalFile> localFile(do_QueryInterface(file));
2130 nsresult rv = parser.Init(localFile);
2131 if (NS_FAILED(rv))
2132 return PR_FALSE;
2134 nsCAutoString buf;
2135 rv = parser.GetString("Compatibility", "LastVersion", buf);
2136 if (NS_FAILED(rv) || !aVersion.Equals(buf))
2137 return PR_FALSE;
2139 rv = parser.GetString("Compatibility", "LastOSABI", buf);
2140 if (NS_FAILED(rv) || !aOSABI.Equals(buf))
2141 return PR_FALSE;
2143 rv = parser.GetString("Compatibility", "LastPlatformDir", buf);
2144 if (NS_FAILED(rv))
2145 return PR_FALSE;
2147 nsCOMPtr<nsILocalFile> lf;
2148 rv = NS_NewNativeLocalFile(buf, PR_FALSE,
2149 getter_AddRefs(lf));
2150 if (NS_FAILED(rv))
2151 return PR_FALSE;
2153 PRBool eq;
2154 rv = lf->Equals(aXULRunnerDir, &eq);
2155 if (NS_FAILED(rv) || !eq)
2156 return PR_FALSE;
2158 if (aAppDir) {
2159 rv = parser.GetString("Compatibility", "LastAppDir", buf);
2160 if (NS_FAILED(rv))
2161 return PR_FALSE;
2163 rv = NS_NewNativeLocalFile(buf, PR_FALSE,
2164 getter_AddRefs(lf));
2165 if (NS_FAILED(rv))
2166 return PR_FALSE;
2168 rv = lf->Equals(aAppDir, &eq);
2169 if (NS_FAILED(rv) || !eq)
2170 return PR_FALSE;
2173 return PR_TRUE;
2176 static void BuildVersion(nsCString &aBuf)
2178 aBuf.Assign(gAppData->version);
2179 aBuf.Append('_');
2180 aBuf.Append(gAppData->buildID);
2181 aBuf.Append('/');
2182 aBuf.Append(gToolkitBuildID);
2185 static void
2186 WriteVersion(nsIFile* aProfileDir, const nsCString& aVersion,
2187 const nsCString& aOSABI, nsIFile* aXULRunnerDir,
2188 nsIFile* aAppDir)
2190 nsCOMPtr<nsIFile> file;
2191 aProfileDir->Clone(getter_AddRefs(file));
2192 if (!file)
2193 return;
2194 file->AppendNative(FILE_COMPATIBILITY_INFO);
2196 nsCOMPtr<nsILocalFile> lf = do_QueryInterface(file);
2198 nsCAutoString platformDir;
2199 aXULRunnerDir->GetNativePath(platformDir);
2201 nsCAutoString appDir;
2202 if (aAppDir)
2203 aAppDir->GetNativePath(appDir);
2205 PRFileDesc *fd = nsnull;
2206 lf->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0600, &fd);
2207 if (!fd) {
2208 NS_ERROR("could not create output stream");
2209 return;
2212 static const char kHeader[] = "[Compatibility]" NS_LINEBREAK
2213 "LastVersion=";
2215 PR_Write(fd, kHeader, sizeof(kHeader) - 1);
2216 PR_Write(fd, aVersion.get(), aVersion.Length());
2218 static const char kOSABIHeader[] = NS_LINEBREAK "LastOSABI=";
2219 PR_Write(fd, kOSABIHeader, sizeof(kOSABIHeader) - 1);
2220 PR_Write(fd, aOSABI.get(), aOSABI.Length());
2222 static const char kPlatformDirHeader[] = NS_LINEBREAK "LastPlatformDir=";
2224 PR_Write(fd, kPlatformDirHeader, sizeof(kPlatformDirHeader) - 1);
2225 PR_Write(fd, platformDir.get(), platformDir.Length());
2227 static const char kAppDirHeader[] = NS_LINEBREAK "LastAppDir=";
2228 if (aAppDir) {
2229 PR_Write(fd, kAppDirHeader, sizeof(kAppDirHeader) - 1);
2230 PR_Write(fd, appDir.get(), appDir.Length());
2233 static const char kNL[] = NS_LINEBREAK;
2234 PR_Write(fd, kNL, sizeof(kNL) - 1);
2236 PR_Close(fd);
2239 static PRBool ComponentsListChanged(nsIFile* aProfileDir)
2241 nsCOMPtr<nsIFile> file;
2242 aProfileDir->Clone(getter_AddRefs(file));
2243 if (!file)
2244 return PR_TRUE;
2245 file->AppendNative(NS_LITERAL_CSTRING(".autoreg"));
2247 PRBool exists = PR_FALSE;
2248 file->Exists(&exists);
2249 return exists;
2252 static void RemoveComponentRegistries(nsIFile* aProfileDir, nsIFile* aLocalProfileDir,
2253 PRBool aRemoveEMFiles)
2255 nsCOMPtr<nsIFile> file;
2256 aProfileDir->Clone(getter_AddRefs(file));
2257 if (!file)
2258 return;
2260 file->AppendNative(NS_LITERAL_CSTRING("compreg.dat"));
2261 file->Remove(PR_FALSE);
2263 file->SetNativeLeafName(NS_LITERAL_CSTRING("xpti.dat"));
2264 file->Remove(PR_FALSE);
2266 file->SetNativeLeafName(NS_LITERAL_CSTRING(".autoreg"));
2267 file->Remove(PR_FALSE);
2269 if (aRemoveEMFiles) {
2270 file->SetNativeLeafName(NS_LITERAL_CSTRING("extensions.ini"));
2271 file->Remove(PR_FALSE);
2274 aLocalProfileDir->Clone(getter_AddRefs(file));
2275 if (!file)
2276 return;
2278 file->AppendNative(NS_LITERAL_CSTRING("XUL" PLATFORM_FASL_SUFFIX));
2279 file->Remove(PR_FALSE);
2282 // To support application initiated restart via nsIAppStartup.quit, we
2283 // need to save various environment variables, and then restore them
2284 // before re-launching the application.
2286 static struct {
2287 const char *name;
2288 char *value;
2289 } gSavedVars[] = {
2290 {"XUL_APP_FILE", nsnull}
2293 static void SaveStateForAppInitiatedRestart()
2295 for (size_t i = 0; i < NS_ARRAY_LENGTH(gSavedVars); ++i) {
2296 const char *s = PR_GetEnv(gSavedVars[i].name);
2297 if (s)
2298 gSavedVars[i].value = PR_smprintf("%s=%s", gSavedVars[i].name, s);
2302 static void RestoreStateForAppInitiatedRestart()
2304 for (size_t i = 0; i < NS_ARRAY_LENGTH(gSavedVars); ++i) {
2305 if (gSavedVars[i].value)
2306 PR_SetEnv(gSavedVars[i].value);
2310 #ifdef MOZ_CRASHREPORTER
2311 // When we first initialize the crash reporter we don't have a profile,
2312 // so we set the minidump path to $TEMP. Once we have a profile,
2313 // we set it to $PROFILE/minidumps, creating the directory
2314 // if needed.
2315 static void MakeOrSetMinidumpPath(nsIFile* profD)
2317 nsCOMPtr<nsIFile> dumpD;
2318 nsresult rv = profD->Clone(getter_AddRefs(dumpD));
2320 if(dumpD) {
2321 PRBool fileExists;
2322 //XXX: do some more error checking here
2323 dumpD->Append(NS_LITERAL_STRING("minidumps"));
2324 rv = dumpD->Exists(&fileExists);
2325 if(!fileExists) {
2326 dumpD->Create(nsIFile::DIRECTORY_TYPE, 0700);
2329 nsAutoString pathStr;
2330 if(NS_SUCCEEDED(dumpD->GetPath(pathStr)))
2331 CrashReporter::SetMinidumpPath(pathStr);
2334 #endif
2336 const nsXREAppData* gAppData = nsnull;
2338 #if defined(XP_OS2)
2339 // because we use early returns, we use a stack-based helper to un-set the OS2 FP handler
2340 class ScopedFPHandler {
2341 private:
2342 EXCEPTIONREGISTRATIONRECORD excpreg;
2344 public:
2345 ScopedFPHandler() { PR_OS2_SetFloatExcpHandler(&excpreg); }
2346 ~ScopedFPHandler() { PR_OS2_UnsetFloatExcpHandler(&excpreg); }
2348 #endif
2350 #ifdef MOZ_WIDGET_GTK2
2351 #include "prlink.h"
2352 typedef void (*_g_set_application_name_fn)(const gchar *application_name);
2353 typedef void (*_gtk_window_set_auto_startup_notification_fn)(gboolean setting);
2355 static PRFuncPtr FindFunction(const char* aName)
2357 PRLibrary *lib = nsnull;
2358 PRFuncPtr result = PR_FindFunctionSymbolAndLibrary(aName, &lib);
2359 // Since the library was already loaded, we can safely unload it here.
2360 if (lib) {
2361 PR_UnloadLibrary(lib);
2363 return result;
2366 static nsIWidget* GetMainWidget(nsIDOMWindow* aWindow)
2368 // get the native window for this instance
2369 nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(aWindow));
2370 NS_ENSURE_TRUE(window, nsnull);
2372 nsCOMPtr<nsIBaseWindow> baseWindow
2373 (do_QueryInterface(window->GetDocShell()));
2374 NS_ENSURE_TRUE(baseWindow, nsnull);
2376 nsCOMPtr<nsIWidget> mainWidget;
2377 baseWindow->GetMainWidget(getter_AddRefs(mainWidget));
2378 return mainWidget;
2381 static nsGTKToolkit* GetGTKToolkit()
2383 nsCOMPtr<nsIAppShellService> svc = do_GetService(NS_APPSHELLSERVICE_CONTRACTID);
2384 if (!svc)
2385 return nsnull;
2386 nsCOMPtr<nsIDOMWindowInternal> window;
2387 svc->GetHiddenDOMWindow(getter_AddRefs(window));
2388 if (!window)
2389 return nsnull;
2390 nsIWidget* widget = GetMainWidget(window);
2391 if (!widget)
2392 return nsnull;
2393 nsIToolkit* toolkit = widget->GetToolkit();
2394 if (!toolkit)
2395 return nsnull;
2396 return static_cast<nsGTKToolkit*>(toolkit);
2399 static void MOZ_gdk_display_close(GdkDisplay *display)
2401 // XXX wallpaper for bug 417163: don't close the Display if we're using the
2402 // Qt theme because we crash (in Qt code) when using jemalloc.
2403 PRBool theme_is_qt = PR_FALSE;
2404 GtkSettings* settings =
2405 gtk_settings_get_for_screen(gdk_display_get_default_screen(display));
2406 gchar *theme_name;
2407 g_object_get(settings, "gtk-theme-name", &theme_name, NULL);
2408 if (theme_name) {
2409 theme_is_qt = strcmp(theme_name, "Qt") == 0;
2410 if (theme_is_qt)
2411 NS_WARNING("wallpaper bug 417163 for Qt theme");
2412 g_free(theme_name);
2415 // gdk_display_close was broken prior to gtk+-2.10.0.
2416 // (http://bugzilla.gnome.org/show_bug.cgi?id=85715)
2417 // gdk_display_manager_set_default_display (gdk_display_manager_get(), NULL)
2418 // was also broken.
2419 if (gtk_check_version(2,10,0) != NULL) {
2420 #ifdef MOZ_X11
2421 // Version check failed - broken gdk_display_close.
2423 // Let the gdk structures leak but at least close the Display,
2424 // assuming that gdk will not use it again.
2425 Display* dpy = GDK_DISPLAY_XDISPLAY(display);
2426 if (!theme_is_qt)
2427 XCloseDisplay(dpy);
2428 #else
2429 gdk_display_close(display);
2430 #endif /* MOZ_X11 */
2432 else {
2433 #if CLEANUP_MEMORY
2434 // Get a (new) Pango context that holds a reference to the fontmap that
2435 // GTK has been using. gdk_pango_context_get() must be called while GTK
2436 // has a default display.
2437 PangoContext *pangoContext = gdk_pango_context_get();
2438 #endif
2440 if (!theme_is_qt)
2441 gdk_display_close(display);
2443 #if CLEANUP_MEMORY
2444 // This doesn't take a reference.
2445 PangoFontMap *fontmap = pango_context_get_font_map(pangoContext);
2446 // Do some shutdown of the fontmap, which releases the fonts, clearing a
2447 // bunch of circular references from the fontmap through the fonts back to
2448 // itself. The shutdown that this does is much less than what's done by
2449 // the fontmap's finalize, though.
2450 if (PANGO_IS_FC_FONT_MAP(fontmap))
2451 pango_fc_font_map_shutdown(PANGO_FC_FONT_MAP(fontmap));
2452 g_object_unref(pangoContext);
2453 // PangoCairo still holds a reference to the fontmap.
2454 // Now that we have finished with GTK and Pango, we could unref fontmap,
2455 // which would allow us to call FcFini, but removing what is really
2456 // Pango's ref feels a bit evil. Pango-1.22 will have support for
2457 // pango_cairo_font_map_set_default(NULL), which would release the
2458 // reference on the old fontmap.
2460 #if GTK_CHECK_VERSION(2,8,0)
2461 // cairo_debug_reset_static_data() is prototyped through cairo.h included
2462 // by gtk.h.
2463 #ifdef cairo_debug_reset_static_data
2464 #error "Looks like we're including Mozilla's cairo instead of system cairo"
2465 #endif
2466 cairo_debug_reset_static_data();
2467 #endif // 2.8.0
2468 #endif // CLEANUP_MEMORY
2471 #endif // MOZ_WIDGET_GTK2
2473 /**
2474 * NSPR will search for the "nspr_use_zone_allocator" symbol throughout
2475 * the process and use it to determine whether the application defines its own
2476 * memory allocator or not.
2478 * Since most applications (e.g. Firefox and Thunderbird) don't use any special
2479 * allocators and therefore don't define this symbol, NSPR must search the
2480 * entire process, which reduces startup performance.
2482 * By defining the symbol here, we can avoid the wasted lookup and hopefully
2483 * improve startup performance.
2485 PRBool nspr_use_zone_allocator = PR_FALSE;
2488 XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
2490 nsresult rv;
2491 ArgResult ar;
2492 NS_TIMELINE_MARK("enter main");
2494 #ifdef DEBUG
2495 if (PR_GetEnv("XRE_MAIN_BREAK"))
2496 NS_BREAK();
2497 #endif
2499 #if defined (XP_WIN32) && !defined (WINCE)
2500 // Suppress the "DLL Foo could not be found" dialog, such that if dependent
2501 // libraries (such as GDI+) are not preset, we gracefully fail to load those
2502 // XPCOM components, instead of being ungraceful.
2503 UINT realMode = SetErrorMode(0);
2504 realMode |= SEM_FAILCRITICALERRORS;
2505 // If XRE_NO_WINDOWS_CRASH_DIALOG is set, suppress displaying the "This
2506 // application has crashed" dialog box. This is mainly useful for
2507 // automated testing environments, e.g. tinderbox, where there's no need
2508 // for a dozen of the dialog boxes to litter the console
2509 if (getenv("XRE_NO_WINDOWS_CRASH_DIALOG"))
2510 realMode |= SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX;
2512 SetErrorMode(realMode);
2514 #ifdef DEBUG
2515 // Disable small heap allocator to get heapwalk() giving us
2516 // accurate heap numbers. Win2k non-debug does not use small heap allocator.
2517 // Win2k debug seems to be still using it.
2518 // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt__set_sbh_threshold.asp
2519 _set_sbh_threshold(0);
2520 #endif
2521 #endif
2523 #if defined(XP_UNIX) || defined(XP_BEOS)
2524 InstallUnixSignalHandlers(argv[0]);
2525 #endif
2527 #ifdef MOZ_ACCESSIBILITY_ATK
2528 // Reset GTK_MODULES, strip atk-bridge if exists
2529 // Mozilla will load libatk-bridge.so later if necessary
2530 const char* gtkModules = PR_GetEnv("GTK_MODULES");
2531 if (gtkModules && *gtkModules) {
2532 nsCString gtkModulesStr(gtkModules);
2533 gtkModulesStr.ReplaceSubstring("atk-bridge", "");
2534 char* expr = PR_smprintf("GTK_MODULES=%s", gtkModulesStr.get());
2535 if (expr)
2536 PR_SetEnv(expr);
2537 // We intentionally leak |expr| here since it is required by PR_SetEnv.
2539 #endif
2541 // Unbuffer stdout, needed for tinderbox tests.
2542 setbuf(stdout, 0);
2544 #if defined(FREEBSD)
2545 // Disable all SIGFPE's on FreeBSD, as it has non-IEEE-conformant fp
2546 // trap behavior that trips up on floating-point tests performed by
2547 // the JS engine. See bugzilla bug 9967 details.
2548 fpsetmask(0);
2549 #endif
2551 gArgc = argc;
2552 gArgv = argv;
2554 NS_ENSURE_TRUE(aAppData, 2);
2556 #ifdef XP_MACOSX
2557 // The xulrunner stub executable tricks CFBundleGetMainBundle on
2558 // purpose into lying about the main bundle path. It will set
2559 // XRE_BINARY_PATH to inform us of our real location.
2560 gBinaryPath = getenv("XRE_BINARY_PATH");
2562 if (gBinaryPath && !*gBinaryPath)
2563 gBinaryPath = nsnull;
2564 #endif
2566 // Check for application.ini overrides
2567 const char* override = nsnull;
2568 ar = CheckArg("override", PR_TRUE, &override);
2569 if (ar == ARG_BAD) {
2570 Output(PR_TRUE, "Incorrect number of arguments passed to -override");
2571 return 1;
2573 else if (ar == ARG_FOUND) {
2574 nsCOMPtr<nsILocalFile> overrideLF;
2575 rv = XRE_GetFileFromPath(override, getter_AddRefs(overrideLF));
2576 if (NS_FAILED(rv)) {
2577 Output(PR_TRUE, "Error: unrecognized override.ini path.\n");
2578 return 1;
2581 nsXREAppData* overrideAppData = const_cast<nsXREAppData*>(aAppData);
2582 rv = XRE_ParseAppData(overrideLF, overrideAppData);
2583 if (NS_FAILED(rv)) {
2584 Output(PR_TRUE, "Couldn't read override.ini");
2585 return 1;
2589 ScopedAppData appData(aAppData);
2590 gAppData = &appData;
2592 // Check sanity and correctness of app data.
2594 if (!appData.name) {
2595 Output(PR_TRUE, "Error: App:Name not specified in application.ini\n");
2596 return 1;
2598 if (!appData.buildID) {
2599 Output(PR_TRUE, "Error: App:BuildID not specified in application.ini\n");
2600 return 1;
2603 ScopedLogging log;
2605 if (!appData.xreDirectory) {
2606 nsCOMPtr<nsILocalFile> lf;
2607 rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf));
2608 if (NS_FAILED(rv))
2609 return 2;
2611 nsCOMPtr<nsIFile> greDir;
2612 rv = lf->GetParent(getter_AddRefs(greDir));
2613 if (NS_FAILED(rv))
2614 return 2;
2616 rv = CallQueryInterface(greDir, &appData.xreDirectory);
2617 if (NS_FAILED(rv))
2618 return 2;
2621 nsCOMPtr<nsIFile> iniFile;
2622 rv = appData.xreDirectory->Clone(getter_AddRefs(iniFile));
2623 if (NS_FAILED(rv))
2624 return 2;
2626 iniFile->AppendNative(NS_LITERAL_CSTRING("platform.ini"));
2628 nsCOMPtr<nsILocalFile> localIniFile = do_QueryInterface(iniFile);
2629 if (!localIniFile)
2630 return 2;
2632 nsINIParser parser;
2633 rv = parser.Init(localIniFile);
2634 if (NS_SUCCEEDED(rv)) {
2635 rv = parser.GetString("Build", "Milestone",
2636 gToolkitVersion, sizeof(gToolkitVersion));
2637 NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to get toolkit version");
2639 rv = parser.GetString("Build", "BuildID",
2640 gToolkitBuildID, sizeof(gToolkitBuildID));
2641 NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to get toolkit buildid");
2643 else {
2644 NS_ERROR("Couldn't parse platform.ini!");
2647 if (appData.size > offsetof(nsXREAppData, minVersion)) {
2648 if (!appData.minVersion) {
2649 Output(PR_TRUE, "Error: Gecko:MinVersion not specified in application.ini\n");
2650 return 1;
2653 if (!appData.maxVersion) {
2654 // If no maxVersion is specified, we assume the app is only compatible
2655 // with the initial preview release. Do not increment this number ever!
2656 SetAllocatedString(appData.maxVersion, "1.*");
2659 if (NS_CompareVersions(appData.minVersion, gToolkitVersion) > 0 ||
2660 NS_CompareVersions(appData.maxVersion, gToolkitVersion) < 0) {
2661 Output(PR_TRUE, "Error: Platform version '%s' is not compatible with\n"
2662 "minVersion >= %s\nmaxVersion <= %s\n",
2663 gToolkitVersion,
2664 appData.minVersion, appData.maxVersion);
2665 return 1;
2669 #ifdef MOZ_CRASHREPORTER
2670 const char* crashreporterEnv = PR_GetEnv("MOZ_CRASHREPORTER");
2671 if (crashreporterEnv && *crashreporterEnv) {
2672 appData.flags |= NS_XRE_ENABLE_CRASH_REPORTER;
2675 if ((appData.flags & NS_XRE_ENABLE_CRASH_REPORTER) &&
2676 NS_SUCCEEDED(
2677 CrashReporter::SetExceptionHandler(appData.xreDirectory,
2678 appData.crashReporterURL))) {
2679 // pass some basic info from the app data
2680 if (appData.vendor)
2681 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Vendor"),
2682 nsDependentCString(appData.vendor));
2683 if (appData.name)
2684 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProductName"),
2685 nsDependentCString(appData.name));
2686 if (appData.version)
2687 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Version"),
2688 nsDependentCString(appData.version));
2689 if (appData.buildID)
2690 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("BuildID"),
2691 nsDependentCString(appData.buildID));
2692 CrashReporter::SetRestartArgs(argc, argv);
2694 // annotate other data (user id etc)
2695 nsXREDirProvider dirProvider;
2696 nsCOMPtr<nsILocalFile> userAppDataDir;
2697 rv = dirProvider.Initialize(gAppData->directory, gAppData->xreDirectory);
2698 if (NS_SUCCEEDED(rv) &&
2699 NS_SUCCEEDED(dirProvider.GetUserAppDataDirectory(
2700 getter_AddRefs(userAppDataDir)))) {
2701 CrashReporter::SetupExtraData(userAppDataDir,
2702 nsDependentCString(appData.buildID));
2704 // see if we have a crashreporter-override.ini in the application directory
2705 nsCOMPtr<nsIFile> overrideini;
2706 PRBool exists;
2707 static char overrideEnv[MAXPATHLEN];
2708 if (NS_SUCCEEDED(dirProvider.GetAppDir()->Clone(getter_AddRefs(overrideini))) &&
2709 NS_SUCCEEDED(overrideini->AppendNative(NS_LITERAL_CSTRING("crashreporter-override.ini"))) &&
2710 NS_SUCCEEDED(overrideini->Exists(&exists)) &&
2711 exists) {
2712 #ifdef XP_WIN
2713 nsAutoString overridePathW;
2714 overrideini->GetPath(overridePathW);
2715 NS_ConvertUTF16toUTF8 overridePath(overridePathW);
2716 #else
2717 nsCAutoString overridePath;
2718 overrideini->GetNativePath(overridePath);
2719 #endif
2721 sprintf(overrideEnv, "MOZ_CRASHREPORTER_STRINGS_OVERRIDE=%s",
2722 overridePath.get());
2723 PR_SetEnv(overrideEnv);
2727 #endif
2729 #ifdef XP_MACOSX
2730 if (PR_GetEnv("MOZ_LAUNCHED_CHILD")) {
2731 // This is needed, on relaunch, to force the OS to use the "Cocoa Dock
2732 // API". Otherwise the call to ReceiveNextEvent() below will make it
2733 // use the "Carbon Dock API". For more info see bmo bug 377166.
2734 EnsureUseCocoaDockAPI();
2736 // When the app relaunches, the original process exits. This causes
2737 // the dock tile to stop bouncing, lose the "running" triangle, and
2738 // if the tile does not permanently reside in the Dock, even disappear.
2739 // This can be confusing to the user, who is expecting the app to launch.
2740 // Calling ReceiveNextEvent without requesting any event is enough to
2741 // cause a dock tile for the child process to appear.
2742 const EventTypeSpec kFakeEventList[] = { { INT_MAX, INT_MAX } };
2743 EventRef event;
2744 ::ReceiveNextEvent(GetEventTypeCount(kFakeEventList), kFakeEventList,
2745 kEventDurationNoWait, PR_FALSE, &event);
2748 if (CheckArg("foreground")) {
2749 // The original process communicates that it was in the foreground by
2750 // adding this argument. This new process, which is taking over for
2751 // the old one, should make itself the active application.
2752 ProcessSerialNumber psn;
2753 if (::GetCurrentProcess(&psn) == noErr)
2754 ::SetFrontProcess(&psn);
2756 #endif
2758 PR_SetEnv("MOZ_LAUNCHED_CHILD=");
2760 gRestartArgc = gArgc;
2761 gRestartArgv = (char**) malloc(sizeof(char*) * (gArgc + 1 + (override ? 2 : 0)));
2762 if (!gRestartArgv) return 1;
2764 int i;
2765 for (i = 0; i < gArgc; ++i) {
2766 gRestartArgv[i] = gArgv[i];
2769 // Add the -override argument back (it is removed automatically be CheckArg) if there is one
2770 if (override) {
2771 gRestartArgv[gRestartArgc++] = const_cast<char*>("-override");
2772 gRestartArgv[gRestartArgc++] = const_cast<char*>(override);
2775 gRestartArgv[gRestartArgc] = nsnull;
2778 #if defined(XP_OS2)
2779 PRBool StartOS2App(int aArgc, char **aArgv);
2780 if (!StartOS2App(gArgc, gArgv))
2781 return 1;
2782 ScopedFPHandler handler;
2783 #endif /* XP_OS2 */
2785 ar = CheckArg("safe-mode", PR_TRUE);
2786 if (ar == ARG_BAD) {
2787 PR_fprintf(PR_STDERR, "Error: argument -safe-mode is invalid when argument -osint is specified\n");
2788 return 1;
2789 } else if (ar == ARG_FOUND) {
2790 gSafeMode = PR_TRUE;
2793 #ifdef XP_MACOSX
2794 if (GetCurrentEventKeyModifiers() & optionKey)
2795 gSafeMode = PR_TRUE;
2796 #endif
2798 // Handle -no-remote command line argument. Setup the environment to
2799 // better accommodate other components and various restart scenarios.
2800 ar = CheckArg("no-remote", PR_TRUE);
2801 if (ar == ARG_BAD) {
2802 PR_fprintf(PR_STDERR, "Error: argument -a requires an application name\n");
2803 return 1;
2804 } else if (ar == ARG_FOUND) {
2805 PR_SetEnv("MOZ_NO_REMOTE=1");
2808 // Handle -help and -version command line arguments.
2809 // They should return quickly, so we deal with them here.
2810 if (CheckArg("h") || CheckArg("help") || CheckArg("?")) {
2811 DumpHelp();
2812 return 0;
2815 if (CheckArg("v") || CheckArg("version")) {
2816 DumpVersion();
2817 return 0;
2820 #ifdef NS_TRACE_MALLOC
2821 gArgc = argc = NS_TraceMallocStartupArgs(gArgc, gArgv);
2822 #endif
2825 nsXREDirProvider dirProvider;
2826 rv = dirProvider.Initialize(gAppData->directory, gAppData->xreDirectory);
2827 if (NS_FAILED(rv))
2828 return 1;
2830 // Check for -register, which registers chrome and then exits immediately.
2831 ar = CheckArg("register", PR_TRUE);
2832 if (ar == ARG_BAD) {
2833 PR_fprintf(PR_STDERR, "Error: argument -register is invalid when argument -osint is specified\n");
2834 return 1;
2835 } else if (ar == ARG_FOUND) {
2836 ScopedXPCOMStartup xpcom;
2837 rv = xpcom.Initialize();
2838 NS_ENSURE_SUCCESS(rv, 1);
2841 nsCOMPtr<nsIChromeRegistry> chromeReg
2842 (do_GetService("@mozilla.org/chrome/chrome-registry;1"));
2843 NS_ENSURE_TRUE(chromeReg, 1);
2845 chromeReg->CheckForNewChrome();
2847 return 0;
2850 #if defined(MOZ_WIDGET_GTK2) || defined(MOZ_ENABLE_XREMOTE)
2851 // Stash DESKTOP_STARTUP_ID in malloc'ed memory because gtk_init will clear it.
2852 #define HAVE_DESKTOP_STARTUP_ID
2853 const char* desktopStartupIDEnv = PR_GetEnv("DESKTOP_STARTUP_ID");
2854 nsCAutoString desktopStartupID;
2855 if (desktopStartupIDEnv) {
2856 desktopStartupID.Assign(desktopStartupIDEnv);
2858 #endif
2860 #if defined(MOZ_WIDGET_QT)
2861 QApplication app(gArgc, gArgv);
2862 #endif
2863 #if defined(MOZ_WIDGET_GTK2)
2864 #ifdef MOZ_MEMORY
2865 // Disable the slice allocator, since jemalloc already uses similar layout
2866 // algorithms, and using a sub-allocator tends to increase fragmentation.
2867 // This must be done before g_thread_init() is called.
2868 g_slice_set_config(G_SLICE_CONFIG_ALWAYS_MALLOC, 1);
2869 #endif
2870 g_thread_init(NULL);
2871 // setup for private colormap. Ideally we'd like to do this
2872 // in nsAppShell::Create, but we need to get in before gtk
2873 // has been initialized to make sure everything is running
2874 // consistently.
2875 if (CheckArg("install"))
2876 gdk_rgb_set_install(TRUE);
2878 // Initialize GTK here for splash.
2880 // Open the display ourselves instead of using gtk_init, so that we can
2881 // close it without fear that one day gtk might clean up the display it
2882 // opens.
2883 if (!gtk_parse_args(&gArgc, &gArgv))
2884 return 1;
2886 // display_name is owned by gdk.
2887 const char *display_name = gdk_get_display_arg_name();
2888 if (display_name) {
2889 SaveWordToEnv("DISPLAY", nsDependentCString(display_name));
2890 } else {
2891 display_name = PR_GetEnv("DISPLAY");
2892 if (!display_name) {
2893 PR_fprintf(PR_STDERR, "Error: no display specified\n");
2894 return 1;
2897 #endif /* MOZ_WIDGET_GTK2 */
2899 #ifdef MOZ_ENABLE_XREMOTE
2900 // handle -remote now that xpcom is fired up
2902 const char* xremotearg;
2903 ar = CheckArg("remote", PR_TRUE, &xremotearg);
2904 if (ar == ARG_BAD) {
2905 PR_fprintf(PR_STDERR, "Error: -remote requires an argument\n");
2906 return 1;
2908 const char* desktopStartupIDPtr =
2909 desktopStartupID.IsEmpty() ? nsnull : desktopStartupID.get();
2910 if (ar) {
2911 return HandleRemoteArgument(xremotearg, desktopStartupIDPtr);
2914 if (!PR_GetEnv("MOZ_NO_REMOTE")) {
2915 // Try to remote the entire command line. If this fails, start up normally.
2916 RemoteResult rr = RemoteCommandLine(desktopStartupIDPtr);
2917 if (rr == REMOTE_FOUND)
2918 return 0;
2919 else if (rr == REMOTE_ARG_BAD)
2920 return 1;
2922 #endif
2924 #if defined(MOZ_WIDGET_GTK2)
2925 GdkDisplay* display = nsnull;
2926 display = gdk_display_open(display_name);
2927 if (!display) {
2928 PR_fprintf(PR_STDERR, "Error: cannot open display: %s\n", display_name);
2929 return 1;
2931 gdk_display_manager_set_default_display (gdk_display_manager_get(),
2932 display);
2934 // g_set_application_name () is only defined in glib2.2 and higher.
2935 _g_set_application_name_fn _g_set_application_name =
2936 (_g_set_application_name_fn)FindFunction("g_set_application_name");
2937 if (_g_set_application_name) {
2938 _g_set_application_name(gAppData->name);
2940 _gtk_window_set_auto_startup_notification_fn _gtk_window_set_auto_startup_notification =
2941 (_gtk_window_set_auto_startup_notification_fn)FindFunction("gtk_window_set_auto_startup_notification");
2942 if (_gtk_window_set_auto_startup_notification) {
2943 _gtk_window_set_auto_startup_notification(PR_FALSE);
2946 gtk_widget_set_default_visual(gdk_rgb_get_visual());
2947 gtk_widget_set_default_colormap(gdk_rgb_get_cmap());
2948 #endif /* MOZ_WIDGET_GTK2 */
2950 // Call the code to install our handler
2951 #ifdef MOZ_JPROF
2952 setupProfilingStuff();
2953 #endif
2955 // Try to allocate "native app support."
2956 nsCOMPtr<nsINativeAppSupport> nativeApp;
2957 rv = NS_CreateNativeAppSupport(getter_AddRefs(nativeApp));
2958 if (NS_FAILED(rv))
2959 return 1;
2961 PRBool canRun = PR_FALSE;
2962 rv = nativeApp->Start(&canRun);
2963 if (NS_FAILED(rv) || !canRun) {
2964 return 1;
2967 #if defined(MOZ_UPDATER)
2968 // Check for and process any available updates
2969 nsCOMPtr<nsIFile> updRoot;
2970 PRBool persistent;
2971 rv = dirProvider.GetFile(XRE_UPDATE_ROOT_DIR, &persistent,
2972 getter_AddRefs(updRoot));
2973 // XRE_UPDATE_ROOT_DIR may fail. Fallback to appDir if failed
2974 if (NS_FAILED(rv))
2975 updRoot = dirProvider.GetAppDir();
2977 ProcessUpdates(dirProvider.GetGREDir(),
2978 dirProvider.GetAppDir(),
2979 updRoot,
2980 gRestartArgc,
2981 gRestartArgv);
2982 #endif
2984 nsCOMPtr<nsIProfileLock> profileLock;
2985 PRBool startOffline = PR_FALSE;
2986 nsCAutoString profileName;
2988 rv = SelectProfile(getter_AddRefs(profileLock), nativeApp, &startOffline,
2989 &profileName);
2990 if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS ||
2991 rv == NS_ERROR_ABORT) return 0;
2992 if (NS_FAILED(rv)) return 1;
2994 nsCOMPtr<nsILocalFile> profD;
2995 rv = profileLock->GetDirectory(getter_AddRefs(profD));
2996 NS_ENSURE_SUCCESS(rv, 1);
2998 nsCOMPtr<nsILocalFile> profLD;
2999 rv = profileLock->GetLocalDirectory(getter_AddRefs(profLD));
3000 NS_ENSURE_SUCCESS(rv, 1);
3002 rv = dirProvider.SetProfile(profD, profLD);
3003 NS_ENSURE_SUCCESS(rv, 1);
3005 //////////////////////// NOW WE HAVE A PROFILE ////////////////////////
3007 #ifdef MOZ_CRASHREPORTER
3008 if (appData.flags & NS_XRE_ENABLE_CRASH_REPORTER)
3009 MakeOrSetMinidumpPath(profD);
3010 #endif
3012 PRBool upgraded = PR_FALSE;
3014 nsCAutoString version;
3015 BuildVersion(version);
3017 #ifdef TARGET_OS_ABI
3018 NS_NAMED_LITERAL_CSTRING(osABI, TARGET_OS_ABI);
3019 #else
3020 // No TARGET_XPCOM_ABI, but at least the OS is known
3021 NS_NAMED_LITERAL_CSTRING(osABI, OS_TARGET "_UNKNOWN");
3022 #endif
3024 // Check for version compatibility with the last version of the app this
3025 // profile was started with. The format of the version stamp is defined
3026 // by the BuildVersion function.
3027 PRBool versionOK = CheckCompatibility(profD, version, osABI,
3028 dirProvider.GetGREDir(),
3029 gAppData->directory);
3031 // Every time a profile is loaded by a build with a different version,
3032 // it updates the compatibility.ini file saying what version last wrote
3033 // the compreg.dat. On subsequent launches if the version matches,
3034 // there is no need for re-registration. If the user loads the same
3035 // profile in different builds the component registry must be
3036 // re-generated to prevent mysterious component loading failures.
3038 if (gSafeMode) {
3039 RemoveComponentRegistries(profD, profLD, PR_FALSE);
3040 WriteVersion(profD, NS_LITERAL_CSTRING("Safe Mode"), osABI,
3041 dirProvider.GetGREDir(), gAppData->directory);
3043 else if (versionOK) {
3044 if (ComponentsListChanged(profD)) {
3045 // Remove compreg.dat and xpti.dat, forcing component re-registration.
3046 // The new list of additional components directories is derived from
3047 // information in "extensions.ini".
3048 RemoveComponentRegistries(profD, profLD, PR_FALSE);
3050 // Nothing need be done for the normal startup case.
3052 else {
3053 // Remove compreg.dat and xpti.dat, forcing component re-registration
3054 // with the default set of components (this disables any potentially
3055 // troublesome incompatible XPCOM components).
3056 RemoveComponentRegistries(profD, profLD, PR_TRUE);
3058 // Tell the Extension Manager it should check for incompatible
3059 // Extensions and re-write the "extensions.ini" file with a list of
3060 // directories for compatible extensions
3061 upgraded = PR_TRUE;
3063 // Write out version
3064 WriteVersion(profD, version, osABI,
3065 dirProvider.GetGREDir(), gAppData->directory);
3068 PRBool needsRestart = PR_FALSE;
3069 PRBool appInitiatedRestart = PR_FALSE;
3071 // Allows the user to forcefully bypass the restart process at their
3072 // own risk. Useful for debugging or for tinderboxes where child
3073 // processes can be problematic.
3075 // Start the real application
3076 ScopedXPCOMStartup xpcom;
3077 rv = xpcom.Initialize();
3078 NS_ENSURE_SUCCESS(rv, 1);
3079 rv = xpcom.DoAutoreg();
3080 rv |= xpcom.RegisterProfileService();
3081 rv |= xpcom.SetWindowCreator(nativeApp);
3082 NS_ENSURE_SUCCESS(rv, 1);
3085 if (startOffline) {
3086 nsCOMPtr<nsIIOService2> io (do_GetService("@mozilla.org/network/io-service;1"));
3087 NS_ENSURE_TRUE(io, 1);
3088 io->SetManageOfflineStatus(PR_FALSE);
3089 io->SetOffline(PR_TRUE);
3093 NS_TIMELINE_ENTER("startupNotifier");
3094 nsCOMPtr<nsIObserver> startupNotifier
3095 (do_CreateInstance(NS_APPSTARTUPNOTIFIER_CONTRACTID, &rv));
3096 NS_ENSURE_SUCCESS(rv, 1);
3098 startupNotifier->Observe(nsnull, APPSTARTUP_TOPIC, nsnull);
3099 NS_TIMELINE_LEAVE("startupNotifier");
3102 nsCOMPtr<nsIAppStartup> appStartup
3103 (do_GetService(NS_APPSTARTUP_CONTRACTID));
3104 NS_ENSURE_TRUE(appStartup, 1);
3106 if (gDoMigration) {
3107 nsCOMPtr<nsIFile> file;
3108 dirProvider.GetAppDir()->Clone(getter_AddRefs(file));
3109 file->AppendNative(NS_LITERAL_CSTRING("override.ini"));
3110 nsINIParser parser;
3111 nsCOMPtr<nsILocalFile> localFile(do_QueryInterface(file));
3112 nsresult rv = parser.Init(localFile);
3113 if (NS_SUCCEEDED(rv)) {
3114 nsCAutoString buf;
3115 rv = parser.GetString("XRE", "EnableProfileMigrator", buf);
3116 if (NS_SUCCEEDED(rv)) {
3117 if (buf[0] == '0' || buf[0] == 'f' || buf[0] == 'F') {
3118 gDoMigration = PR_FALSE;
3124 // Profile Migration
3125 if (gAppData->flags & NS_XRE_ENABLE_PROFILE_MIGRATOR && gDoMigration) {
3126 gDoMigration = PR_FALSE;
3127 nsCOMPtr<nsIProfileMigrator> pm
3128 (do_CreateInstance(NS_PROFILEMIGRATOR_CONTRACTID));
3129 if (pm)
3130 pm->Migrate(&dirProvider);
3132 dirProvider.DoStartup();
3134 nsCOMPtr<nsICommandLineRunner> cmdLine
3135 (do_CreateInstance("@mozilla.org/toolkit/command-line;1"));
3136 NS_ENSURE_TRUE(cmdLine, 1);
3138 nsCOMPtr<nsIFile> workingDir;
3139 rv = NS_GetSpecialDirectory(NS_OS_CURRENT_WORKING_DIR, getter_AddRefs(workingDir));
3140 NS_ENSURE_SUCCESS(rv, 1);
3142 rv = cmdLine->Init(gArgc, gArgv,
3143 workingDir, nsICommandLine::STATE_INITIAL_LAUNCH);
3144 NS_ENSURE_SUCCESS(rv, 1);
3146 /* Special-case services that need early access to the command
3147 line. */
3148 nsCOMPtr<nsIObserver> chromeObserver
3149 (do_GetService("@mozilla.org/chrome/chrome-registry;1"));
3150 if (chromeObserver) {
3151 chromeObserver->Observe(cmdLine, "command-line-startup", nsnull);
3154 NS_TIMELINE_ENTER("appStartup->CreateHiddenWindow");
3155 rv = appStartup->CreateHiddenWindow();
3156 NS_TIMELINE_LEAVE("appStartup->CreateHiddenWindow");
3157 NS_ENSURE_SUCCESS(rv, 1);
3159 #if defined(HAVE_DESKTOP_STARTUP_ID) && defined(MOZ_WIDGET_GTK2)
3160 nsRefPtr<nsGTKToolkit> toolkit = GetGTKToolkit();
3161 if (toolkit && !desktopStartupID.IsEmpty()) {
3162 toolkit->SetDesktopStartupID(desktopStartupID);
3164 #endif
3166 // Extension Compatibility Checking and Startup
3167 if (gAppData->flags & NS_XRE_ENABLE_EXTENSION_MANAGER) {
3168 nsCOMPtr<nsIExtensionManager> em(do_GetService("@mozilla.org/extensions/manager;1"));
3169 NS_ENSURE_TRUE(em, 1);
3171 ar = CheckArg("install-global-extension", PR_TRUE);
3172 if (ar == ARG_BAD) {
3173 PR_fprintf(PR_STDERR, "Error: argument -install-global-extension is invalid when argument -osint is specified\n");
3174 return 1;
3175 } else if (ar == ARG_FOUND) {
3176 // Do the required processing and then shut down.
3177 em->HandleCommandLineArgs(cmdLine);
3178 return 0;
3181 ar = CheckArg("install-global-theme", PR_TRUE);
3182 if (ar == ARG_BAD) {
3183 PR_fprintf(PR_STDERR, "Error: argument -install-global-theme is invalid when argument -osint is specified\n");
3184 return 1;
3185 } else if (ar == ARG_FOUND) {
3186 // Do the required processing and then shut down.
3187 em->HandleCommandLineArgs(cmdLine);
3188 return 0;
3191 if (upgraded) {
3192 rv = em->CheckForMismatches(&needsRestart);
3193 if (NS_FAILED(rv)) {
3194 needsRestart = PR_FALSE;
3195 upgraded = PR_FALSE;
3199 if (!upgraded || !needsRestart)
3200 em->Start(cmdLine, &needsRestart);
3203 // We want to restart no more than 2 times. The first restart,
3204 // NO_EM_RESTART == "0" , and the second time, "1".
3205 char* noEMRestart = PR_GetEnv("NO_EM_RESTART");
3206 if (noEMRestart && *noEMRestart && *noEMRestart == '1') {
3207 if (upgraded || needsRestart) {
3208 NS_WARNING("EM tried to force us to restart twice! Forcefully preventing that.");
3210 needsRestart = upgraded = PR_FALSE;
3213 if (!upgraded && !needsRestart) {
3214 SaveStateForAppInitiatedRestart();
3216 // clear out any environment variables which may have been set
3217 // during the relaunch process now that we know we won't be relaunching.
3218 PR_SetEnv("XRE_PROFILE_PATH=");
3219 PR_SetEnv("XRE_PROFILE_LOCAL_PATH=");
3220 PR_SetEnv("XRE_PROFILE_NAME=");
3221 PR_SetEnv("XRE_START_OFFLINE=");
3222 PR_SetEnv("XRE_IMPORT_PROFILES=");
3223 PR_SetEnv("NO_EM_RESTART=");
3224 PR_SetEnv("XUL_APP_FILE=");
3225 PR_SetEnv("XRE_BINARY_PATH=");
3227 #ifdef XP_MACOSX
3228 // we re-initialize the command-line service and do appleevents munging
3229 // after we are sure that we're not restarting
3230 cmdLine = do_CreateInstance("@mozilla.org/toolkit/command-line;1");
3231 NS_ENSURE_TRUE(cmdLine, 1);
3233 SetupMacCommandLine(gArgc, gArgv);
3235 rv = cmdLine->Init(gArgc, gArgv,
3236 workingDir, nsICommandLine::STATE_INITIAL_LAUNCH);
3237 NS_ENSURE_SUCCESS(rv, 1);
3238 #endif
3239 #ifdef MOZ_WIDGET_COCOA
3240 // Prepare Cocoa's form of Apple Event handling.
3241 SetupMacApplicationDelegate();
3242 #endif
3243 nsCOMPtr<nsIObserverService> obsService
3244 (do_GetService("@mozilla.org/observer-service;1"));
3245 if (obsService)
3246 obsService->NotifyObservers(nsnull, "final-ui-startup", nsnull);
3248 rv = cmdLine->Run();
3249 NS_ENSURE_SUCCESS_LOG(rv, 1);
3251 #ifdef MOZ_ENABLE_XREMOTE
3252 // if we have X remote support, start listening for requests on the
3253 // proxy window.
3254 nsCOMPtr<nsIRemoteService> remoteService;
3255 remoteService = do_GetService("@mozilla.org/toolkit/remote-service;1");
3256 if (remoteService)
3257 remoteService->Startup(gAppData->name,
3258 PromiseFlatCString(profileName).get());
3259 #endif /* MOZ_ENABLE_XREMOTE */
3261 // enable win32 DDE responses and Mac appleevents responses
3262 nativeApp->Enable();
3264 NS_TIMELINE_ENTER("appStartup->Run");
3265 rv = appStartup->Run();
3266 NS_TIMELINE_LEAVE("appStartup->Run");
3267 if (NS_FAILED(rv)) {
3268 NS_ERROR("failed to run appstartup");
3269 gLogConsoleErrors = PR_TRUE;
3272 // Check for an application initiated restart. This is one that
3273 // corresponds to nsIAppStartup.quit(eRestart)
3274 if (rv == NS_SUCCESS_RESTART_APP) {
3275 needsRestart = PR_TRUE;
3276 appInitiatedRestart = PR_TRUE;
3279 #ifdef MOZ_ENABLE_XREMOTE
3280 // shut down the x remote proxy window
3281 if (remoteService)
3282 remoteService->Shutdown();
3283 #endif /* MOZ_ENABLE_XREMOTE */
3285 #ifdef MOZ_TIMELINE
3286 // Make sure we print this out even if timeline is runtime disabled
3287 if (NS_FAILED(NS_TIMELINE_LEAVE("main1")))
3288 NS_TimelineForceMark("...main1");
3289 #endif
3291 else {
3292 // Upgrade condition (build id changes), but the restart hint was
3293 // not set by the Extension Manager. This is because the compatibility
3294 // resolution for Extensions is different than for the component
3295 // registry - major milestone vs. build id.
3296 needsRestart = PR_TRUE;
3298 #ifdef XP_WIN
3299 ProcessDDE(nativeApp, PR_TRUE);
3300 #endif
3302 #ifdef XP_MACOSX
3303 SetupMacCommandLine(gRestartArgc, gRestartArgv);
3304 #endif
3309 // unlock the profile after ScopedXPCOMStartup object (xpcom)
3310 // has gone out of scope. see bug #386739 for more details
3311 profileLock->Unlock();
3313 // Restart the app after XPCOM has been shut down cleanly.
3314 if (needsRestart) {
3315 if (appInitiatedRestart) {
3316 RestoreStateForAppInitiatedRestart();
3318 else {
3319 char* noEMRestart = PR_GetEnv("NO_EM_RESTART");
3320 if (noEMRestart && *noEMRestart) {
3321 PR_SetEnv("NO_EM_RESTART=1");
3323 else {
3324 PR_SetEnv("NO_EM_RESTART=0");
3328 // Ensure that these environment variables are set:
3329 SaveFileToEnvIfUnset("XRE_PROFILE_PATH", profD);
3330 SaveFileToEnvIfUnset("XRE_PROFILE_LOCAL_PATH", profLD);
3331 SaveWordToEnvIfUnset("XRE_PROFILE_NAME", profileName);
3333 #ifdef XP_MACOSX
3334 if (gBinaryPath) {
3335 static char kEnvVar[MAXPATHLEN];
3336 sprintf(kEnvVar, "XRE_BINARY_PATH=%s", gBinaryPath);
3337 PR_SetEnv(kEnvVar);
3339 #endif
3341 // XXXkt s/MOZ_TOOLKIT_GTK2/MOZ_WIDGET_GTK2/?
3342 // but the hidden window has been destroyed so toolkit is NULL anyway.
3343 #if defined(HAVE_DESKTOP_STARTUP_ID) && defined(MOZ_TOOLKIT_GTK2)
3344 nsGTKToolkit* toolkit = GetGTKToolkit();
3345 if (toolkit) {
3346 nsCAutoString currentDesktopStartupID;
3347 toolkit->GetDesktopStartupID(&currentDesktopStartupID);
3348 if (!currentDesktopStartupID.IsEmpty()) {
3349 nsCAutoString desktopStartupEnv;
3350 desktopStartupEnv.AssignLiteral("DESKTOP_STARTUP_ID=");
3351 desktopStartupEnv.Append(currentDesktopStartupID);
3352 // Leak it with extreme prejudice!
3353 PR_SetEnv(ToNewCString(desktopStartupEnv));
3356 #endif
3358 #ifdef MOZ_WIDGET_GTK2
3359 MOZ_gdk_display_close(display);
3360 #endif
3362 rv = LaunchChild(nativeApp, appInitiatedRestart);
3364 #ifdef MOZ_CRASHREPORTER
3365 if (appData.flags & NS_XRE_ENABLE_CRASH_REPORTER)
3366 CrashReporter::UnsetExceptionHandler();
3367 #endif
3369 return rv == NS_ERROR_LAUNCHED_CHILD_PROCESS ? 0 : 1;
3372 #ifdef MOZ_WIDGET_GTK2
3373 // gdk_display_close also calls gdk_display_manager_set_default_display
3374 // appropriately when necessary.
3375 MOZ_gdk_display_close(display);
3376 #endif
3379 #ifdef MOZ_CRASHREPORTER
3380 if (appData.flags & NS_XRE_ENABLE_CRASH_REPORTER)
3381 CrashReporter::UnsetExceptionHandler();
3382 #endif
3384 return NS_FAILED(rv) ? 1 : 0;