Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / toolkit / xre / nsAppRunner.cpp
blobc4736a44c6b635194e5429a99666edf2e39329a1
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 #ifndef WINCE
153 #include <process.h>
154 #include <shlobj.h>
155 #endif
156 #include "nsThreadUtils.h"
157 #endif
159 #ifdef XP_MACOSX
160 #include "nsILocalFileMac.h"
161 #include "nsCommandLineServiceMac.h"
162 #endif
164 // for X remote support
165 #ifdef MOZ_ENABLE_XREMOTE
166 #ifdef MOZ_WIDGET_PHOTON
167 #include "PhRemoteClient.h"
168 #else
169 #include "XRemoteClient.h"
170 #endif
171 #include "nsIRemoteService.h"
172 #endif
174 #ifdef NS_TRACE_MALLOC
175 #include "nsTraceMalloc.h"
176 #endif
178 #if defined(DEBUG) && defined(XP_WIN32)
179 #include <malloc.h>
180 #endif
182 #if defined (XP_MACOSX)
183 #include <Processes.h>
184 #include <Events.h>
185 #endif
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) && (__KLIBC__ == 0 && __KLIBC_MINOR__ >= 6) // broken kLibc
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 SetupMacCommandLine(gRestartArgc, gRestartArgv);
1600 LaunchChildMac(gRestartArgc, gRestartArgv);
1601 #else
1602 nsCOMPtr<nsILocalFile> lf;
1603 nsresult rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf));
1604 if (NS_FAILED(rv))
1605 return rv;
1607 #if defined(XP_WIN)
1608 nsAutoString exePath;
1609 rv = lf->GetPath(exePath);
1610 if (NS_FAILED(rv))
1611 return rv;
1613 if (!WinLaunchChild(exePath.get(), gRestartArgc, gRestartArgv, 0))
1614 return NS_ERROR_FAILURE;
1616 #else
1617 nsCAutoString exePath;
1618 rv = lf->GetNativePath(exePath);
1619 if (NS_FAILED(rv))
1620 return rv;
1622 #if defined(XP_OS2) && (__KLIBC__ == 0 && __KLIBC_MINOR__ >= 6)
1623 // implementation of _execv() is broken with kLibc 0.6.x and later
1624 if (OS2LaunchChild(exePath.get(), gRestartArgc, gRestartArgv) == -1)
1625 return NS_ERROR_FAILURE;
1626 #elif defined(XP_OS2)
1627 if (_execv(exePath.get(), gRestartArgv) == -1)
1628 return NS_ERROR_FAILURE;
1629 #elif defined(XP_UNIX)
1630 if (execv(exePath.get(), gRestartArgv) == -1)
1631 return NS_ERROR_FAILURE;
1632 #elif defined(XP_BEOS)
1633 extern char **environ;
1634 status_t res;
1635 res = resume_thread(load_image(gRestartArgc,(const char **)gRestartArgv,(const char **)environ));
1636 if (res != B_OK)
1637 return NS_ERROR_FAILURE;
1638 #else
1639 PRProcess* process = PR_CreateProcess(exePath.get(), gRestartArgv,
1640 nsnull, nsnull);
1641 if (!process) return NS_ERROR_FAILURE;
1643 PRInt32 exitCode;
1644 PRStatus failed = PR_WaitProcess(process, &exitCode);
1645 if (failed || exitCode)
1646 return NS_ERROR_FAILURE;
1647 #endif // XP_OS2 series
1648 #endif // WP_WIN
1649 #endif // WP_MACOSX
1651 return NS_ERROR_LAUNCHED_CHILD_PROCESS;
1654 static const char kProfileProperties[] =
1655 "chrome://mozapps/locale/profile/profileSelection.properties";
1657 static nsresult
1658 ProfileLockedDialog(nsILocalFile* aProfileDir, nsILocalFile* aProfileLocalDir,
1659 nsIProfileUnlocker* aUnlocker,
1660 nsINativeAppSupport* aNative, nsIProfileLock* *aResult)
1662 nsresult rv;
1664 ScopedXPCOMStartup xpcom;
1665 rv = xpcom.Initialize();
1666 NS_ENSURE_SUCCESS(rv, rv);
1668 rv = xpcom.DoAutoreg();
1669 rv |= xpcom.SetWindowCreator(aNative);
1670 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
1672 { //extra scoping is needed so we release these components before xpcom shutdown
1673 nsCOMPtr<nsIStringBundleService> sbs
1674 (do_GetService(NS_STRINGBUNDLE_CONTRACTID));
1675 NS_ENSURE_TRUE(sbs, NS_ERROR_FAILURE);
1677 nsCOMPtr<nsIStringBundle> sb;
1678 sbs->CreateBundle(kProfileProperties, getter_AddRefs(sb));
1679 NS_ENSURE_TRUE_LOG(sbs, NS_ERROR_FAILURE);
1681 NS_ConvertUTF8toUTF16 appName(gAppData->name);
1682 const PRUnichar* params[] = {appName.get(), appName.get()};
1684 nsXPIDLString killMessage;
1685 #ifndef XP_MACOSX
1686 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"
1687 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"
1688 #else
1689 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"
1690 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"
1691 #endif
1693 sb->FormatStringFromName(aUnlocker ? kRestartUnlocker : kRestartNoUnlocker,
1694 params, 2, getter_Copies(killMessage));
1696 nsXPIDLString killTitle;
1697 sb->FormatStringFromName(NS_LITERAL_STRING("restartTitle").get(),
1698 params, 1, getter_Copies(killTitle));
1700 if (!killMessage || !killTitle)
1701 return NS_ERROR_FAILURE;
1703 nsCOMPtr<nsIPromptService> ps
1704 (do_GetService(NS_PROMPTSERVICE_CONTRACTID));
1705 NS_ENSURE_TRUE(ps, NS_ERROR_FAILURE);
1707 PRUint32 flags = nsIPromptService::BUTTON_TITLE_OK * nsIPromptService::BUTTON_POS_0;
1709 if (aUnlocker) {
1710 flags =
1711 nsIPromptService::BUTTON_TITLE_CANCEL * nsIPromptService::BUTTON_POS_0 +
1712 nsIPromptService::BUTTON_TITLE_IS_STRING * nsIPromptService::BUTTON_POS_1 +
1713 nsIPromptService::BUTTON_POS_1_DEFAULT;
1716 PRInt32 button;
1717 rv = ps->ConfirmEx(nsnull, killTitle, killMessage, flags,
1718 killTitle, nsnull, nsnull, nsnull, nsnull, &button);
1719 NS_ENSURE_SUCCESS_LOG(rv, rv);
1721 if (button == 1 && aUnlocker) {
1722 rv = aUnlocker->Unlock(nsIProfileUnlocker::FORCE_QUIT);
1723 if (NS_FAILED(rv)) return rv;
1725 return NS_LockProfilePath(aProfileDir, aProfileLocalDir, nsnull, aResult);
1728 return NS_ERROR_ABORT;
1732 static const char kProfileManagerURL[] =
1733 "chrome://mozapps/content/profile/profileSelection.xul";
1735 static nsresult
1736 ShowProfileManager(nsIToolkitProfileService* aProfileSvc,
1737 nsINativeAppSupport* aNative)
1739 nsresult rv;
1741 nsCOMPtr<nsILocalFile> profD, profLD;
1742 PRUnichar* profileNamePtr;
1743 nsCAutoString profileName;
1746 ScopedXPCOMStartup xpcom;
1747 rv = xpcom.Initialize();
1748 NS_ENSURE_SUCCESS(rv, rv);
1750 rv = xpcom.DoAutoreg();
1751 rv |= xpcom.RegisterProfileService();
1752 rv |= xpcom.SetWindowCreator(aNative);
1753 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
1755 #ifdef XP_MACOSX
1756 SetupMacCommandLine(gRestartArgc, gRestartArgv);
1757 #endif
1759 #ifdef XP_WIN
1760 // we don't have to wait here because profile manager window will pump
1761 // and DDE message will be handled
1762 ProcessDDE(aNative, PR_FALSE);
1763 #endif
1765 { //extra scoping is needed so we release these components before xpcom shutdown
1766 nsCOMPtr<nsIWindowWatcher> windowWatcher
1767 (do_GetService(NS_WINDOWWATCHER_CONTRACTID));
1768 nsCOMPtr<nsIDialogParamBlock> ioParamBlock
1769 (do_CreateInstance(NS_DIALOGPARAMBLOCK_CONTRACTID));
1770 nsCOMPtr<nsIMutableArray> dlgArray (do_CreateInstance(NS_ARRAY_CONTRACTID));
1771 NS_ENSURE_TRUE(windowWatcher && ioParamBlock && dlgArray, NS_ERROR_FAILURE);
1773 ioParamBlock->SetObjects(dlgArray);
1775 nsCOMPtr<nsIAppStartup> appStartup
1776 (do_GetService(NS_APPSTARTUP_CONTRACTID));
1777 NS_ENSURE_TRUE(appStartup, NS_ERROR_FAILURE);
1779 nsCOMPtr<nsIDOMWindow> newWindow;
1780 rv = windowWatcher->OpenWindow(nsnull,
1781 kProfileManagerURL,
1782 "_blank",
1783 "centerscreen,chrome,modal,titlebar",
1784 ioParamBlock,
1785 getter_AddRefs(newWindow));
1787 NS_ENSURE_SUCCESS_LOG(rv, rv);
1789 aProfileSvc->Flush();
1791 PRInt32 dialogConfirmed;
1792 rv = ioParamBlock->GetInt(0, &dialogConfirmed);
1793 if (NS_FAILED(rv) || dialogConfirmed == 0) return NS_ERROR_ABORT;
1795 nsCOMPtr<nsIProfileLock> lock;
1796 rv = dlgArray->QueryElementAt(0, NS_GET_IID(nsIProfileLock),
1797 getter_AddRefs(lock));
1798 NS_ENSURE_SUCCESS_LOG(rv, rv);
1800 rv = lock->GetDirectory(getter_AddRefs(profD));
1801 NS_ENSURE_SUCCESS(rv, rv);
1803 rv = lock->GetLocalDirectory(getter_AddRefs(profLD));
1804 NS_ENSURE_SUCCESS(rv, rv);
1806 rv = ioParamBlock->GetString(0, &profileNamePtr);
1807 NS_ENSURE_SUCCESS(rv, rv);
1809 CopyUTF16toUTF8(profileNamePtr, profileName);
1810 NS_Free(profileNamePtr);
1812 lock->Unlock();
1816 SaveFileToEnv("XRE_PROFILE_PATH", profD);
1817 SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", profLD);
1818 SaveWordToEnv("XRE_PROFILE_NAME", profileName);
1820 PRBool offline = PR_FALSE;
1821 aProfileSvc->GetStartOffline(&offline);
1822 if (offline) {
1823 PR_SetEnv("XRE_START_OFFLINE=1");
1826 return LaunchChild(aNative);
1829 static nsresult
1830 ImportProfiles(nsIToolkitProfileService* aPService,
1831 nsINativeAppSupport* aNative)
1833 nsresult rv;
1835 PR_SetEnv("XRE_IMPORT_PROFILES=1");
1837 // try to import old-style profiles
1838 { // scope XPCOM
1839 ScopedXPCOMStartup xpcom;
1840 rv = xpcom.Initialize();
1841 if (NS_SUCCEEDED(rv)) {
1842 xpcom.DoAutoreg();
1843 xpcom.RegisterProfileService();
1845 #ifdef XP_MACOSX
1846 SetupMacCommandLine(gRestartArgc, gRestartArgv);
1847 #endif
1849 nsCOMPtr<nsIProfileMigrator> migrator
1850 (do_GetService(NS_PROFILEMIGRATOR_CONTRACTID));
1851 if (migrator) {
1852 migrator->Import();
1857 aPService->Flush();
1858 return LaunchChild(aNative);
1861 // Pick a profile. We need to end up with a profile lock.
1863 // 1) check for -profile <path>
1864 // 2) check for -P <name>
1865 // 3) check for -ProfileManager
1866 // 4) use the default profile, if there is one
1867 // 5) if there are *no* profiles, set up profile-migration
1868 // 6) display the profile-manager UI
1870 static PRBool gDoMigration = PR_FALSE;
1872 static nsresult
1873 SelectProfile(nsIProfileLock* *aResult, nsINativeAppSupport* aNative,
1874 PRBool* aStartOffline, nsACString* aProfileName)
1876 nsresult rv;
1877 ArgResult ar;
1878 const char* arg;
1879 *aResult = nsnull;
1880 *aStartOffline = PR_FALSE;
1882 ar = CheckArg("offline", PR_TRUE);
1883 if (ar == ARG_BAD) {
1884 PR_fprintf(PR_STDERR, "Error: argument -offline is invalid when argument -osint is specified\n");
1885 return NS_ERROR_FAILURE;
1888 arg = PR_GetEnv("XRE_START_OFFLINE");
1889 if ((arg && *arg) || ar)
1890 *aStartOffline = PR_TRUE;
1893 nsCOMPtr<nsILocalFile> lf = GetFileFromEnv("XRE_PROFILE_PATH");
1894 if (lf) {
1895 nsCOMPtr<nsILocalFile> localDir =
1896 GetFileFromEnv("XRE_PROFILE_LOCAL_PATH");
1897 if (!localDir) {
1898 localDir = lf;
1901 arg = PR_GetEnv("XRE_PROFILE_NAME");
1902 if (arg && *arg && aProfileName)
1903 aProfileName->Assign(nsDependentCString(arg));
1905 // Clear out flags that we handled (or should have handled!) last startup.
1906 const char *dummy;
1907 CheckArg("p", PR_FALSE, &dummy);
1908 CheckArg("profile", PR_FALSE, &dummy);
1909 CheckArg("profilemanager");
1911 return NS_LockProfilePath(lf, localDir, nsnull, aResult);
1914 ar = CheckArg("migration", PR_TRUE);
1915 if (ar == ARG_BAD) {
1916 PR_fprintf(PR_STDERR, "Error: argument -migration is invalid when argument -osint is specified\n");
1917 return NS_ERROR_FAILURE;
1918 } else if (ar == ARG_FOUND) {
1919 gDoMigration = PR_TRUE;
1922 ar = CheckArg("profile", PR_TRUE, &arg);
1923 if (ar == ARG_BAD) {
1924 PR_fprintf(PR_STDERR, "Error: argument -profile requires a path\n");
1925 return NS_ERROR_FAILURE;
1927 if (ar) {
1928 nsCOMPtr<nsILocalFile> lf;
1929 rv = XRE_GetFileFromPath(arg, getter_AddRefs(lf));
1930 NS_ENSURE_SUCCESS(rv, rv);
1932 nsCOMPtr<nsIProfileUnlocker> unlocker;
1934 // If a profile path is specified directory on the command line, then
1935 // assume that the temp directory is the same as the given directory.
1936 rv = NS_LockProfilePath(lf, lf, getter_AddRefs(unlocker), aResult);
1937 if (NS_SUCCEEDED(rv))
1938 return rv;
1940 return ProfileLockedDialog(lf, lf, unlocker, aNative, aResult);
1943 nsCOMPtr<nsIToolkitProfileService> profileSvc;
1944 rv = NS_NewToolkitProfileService(getter_AddRefs(profileSvc));
1945 NS_ENSURE_SUCCESS(rv, rv);
1947 ar = CheckArg("createprofile", PR_TRUE, &arg);
1948 if (ar == ARG_BAD) {
1949 PR_fprintf(PR_STDERR, "Error: argument -createprofile requires a profile name\n");
1950 return NS_ERROR_FAILURE;
1952 if (ar) {
1953 nsCOMPtr<nsIToolkitProfile> profile;
1955 const char* delim = strchr(arg, ' ');
1956 if (delim) {
1957 nsCOMPtr<nsILocalFile> lf;
1958 rv = NS_NewNativeLocalFile(nsDependentCString(delim + 1),
1959 PR_TRUE, getter_AddRefs(lf));
1960 if (NS_FAILED(rv)) {
1961 PR_fprintf(PR_STDERR, "Error: profile path not valid.\n");
1962 return rv;
1965 // As with -profile, assume that the given path will be used for both the
1966 // main profile directory and the temp profile directory.
1967 rv = profileSvc->CreateProfile(lf, lf, nsDependentCSubstring(arg, delim),
1968 getter_AddRefs(profile));
1969 } else {
1970 rv = profileSvc->CreateProfile(nsnull, nsnull, nsDependentCString(arg),
1971 getter_AddRefs(profile));
1973 // Some pathological arguments can make it this far
1974 if (NS_FAILED(rv)) {
1975 PR_fprintf(PR_STDERR, "Error creating profile.\n");
1976 return rv;
1978 rv = NS_ERROR_ABORT;
1979 profileSvc->Flush();
1981 // XXXben need to ensure prefs.js exists here so the tinderboxes will
1982 // not go orange.
1983 nsCOMPtr<nsILocalFile> prefsJSFile;
1984 profile->GetRootDir(getter_AddRefs(prefsJSFile));
1985 prefsJSFile->AppendNative(NS_LITERAL_CSTRING("prefs.js"));
1986 nsCAutoString pathStr;
1987 prefsJSFile->GetNativePath(pathStr);
1988 PR_fprintf(PR_STDERR, "Success: created profile '%s' at '%s'\n", arg, pathStr.get());
1989 PRBool exists;
1990 prefsJSFile->Exists(&exists);
1991 if (!exists)
1992 prefsJSFile->Create(nsIFile::NORMAL_FILE_TYPE, 0644);
1993 // XXXdarin perhaps 0600 would be better?
1995 return rv;
1998 PRUint32 count;
1999 rv = profileSvc->GetProfileCount(&count);
2000 NS_ENSURE_SUCCESS(rv, rv);
2002 if (gAppData->flags & NS_XRE_ENABLE_PROFILE_MIGRATOR) {
2003 arg = PR_GetEnv("XRE_IMPORT_PROFILES");
2004 if (!count && (!arg || !*arg)) {
2005 return ImportProfiles(profileSvc, aNative);
2009 ar = CheckArg("p", PR_FALSE, &arg);
2010 if (ar == ARG_BAD) {
2011 ar = CheckArg("osint");
2012 if (ar == ARG_FOUND) {
2013 PR_fprintf(PR_STDERR, "Error: argument -p is invalid when argument -osint is specified\n");
2014 return NS_ERROR_FAILURE;
2016 return ShowProfileManager(profileSvc, aNative);
2018 if (ar) {
2019 ar = CheckArg("osint");
2020 if (ar == ARG_FOUND) {
2021 PR_fprintf(PR_STDERR, "Error: argument -p is invalid when argument -osint is specified\n");
2022 return NS_ERROR_FAILURE;
2024 nsCOMPtr<nsIToolkitProfile> profile;
2025 rv = profileSvc->GetProfileByName(nsDependentCString(arg),
2026 getter_AddRefs(profile));
2027 if (NS_SUCCEEDED(rv)) {
2028 nsCOMPtr<nsIProfileUnlocker> unlocker;
2029 rv = profile->Lock(nsnull, aResult);
2030 if (NS_SUCCEEDED(rv)) {
2031 if (aProfileName)
2032 aProfileName->Assign(nsDependentCString(arg));
2033 return NS_OK;
2036 nsCOMPtr<nsILocalFile> profileDir;
2037 rv = profile->GetRootDir(getter_AddRefs(profileDir));
2038 NS_ENSURE_SUCCESS(rv, rv);
2040 nsCOMPtr<nsILocalFile> profileLocalDir;
2041 rv = profile->GetLocalDir(getter_AddRefs(profileLocalDir));
2042 NS_ENSURE_SUCCESS(rv, rv);
2044 return ProfileLockedDialog(profileDir, profileLocalDir, unlocker,
2045 aNative, aResult);
2048 return ShowProfileManager(profileSvc, aNative);
2051 ar = CheckArg("profilemanager", PR_TRUE);
2052 if (ar == ARG_BAD) {
2053 PR_fprintf(PR_STDERR, "Error: argument -profilemanager is invalid when argument -osint is specified\n");
2054 return NS_ERROR_FAILURE;
2055 } else if (ar == ARG_FOUND) {
2056 return ShowProfileManager(profileSvc, aNative);
2059 if (!count) {
2060 gDoMigration = PR_TRUE;
2062 // create a default profile
2063 nsCOMPtr<nsIToolkitProfile> profile;
2064 nsresult rv = profileSvc->CreateProfile(nsnull, // choose a default dir for us
2065 nsnull, // choose a default dir for us
2066 NS_LITERAL_CSTRING("default"),
2067 getter_AddRefs(profile));
2068 if (NS_SUCCEEDED(rv)) {
2069 profileSvc->Flush();
2070 rv = profile->Lock(nsnull, aResult);
2071 if (NS_SUCCEEDED(rv)) {
2072 if (aProfileName)
2073 aProfileName->Assign(NS_LITERAL_CSTRING("default"));
2074 return NS_OK;
2079 PRBool useDefault = PR_TRUE;
2080 if (count > 1)
2081 profileSvc->GetStartWithLastProfile(&useDefault);
2083 if (useDefault) {
2084 nsCOMPtr<nsIToolkitProfile> profile;
2085 // GetSelectedProfile will auto-select the only profile if there's just one
2086 profileSvc->GetSelectedProfile(getter_AddRefs(profile));
2087 if (profile) {
2088 nsCOMPtr<nsIProfileUnlocker> unlocker;
2089 rv = profile->Lock(getter_AddRefs(unlocker), aResult);
2090 if (NS_SUCCEEDED(rv)) {
2091 // Try to grab the profile name.
2092 if (aProfileName) {
2093 rv = profile->GetName(*aProfileName);
2094 if (NS_FAILED(rv))
2095 aProfileName->Truncate(0);
2097 return NS_OK;
2100 nsCOMPtr<nsILocalFile> profileDir;
2101 rv = profile->GetRootDir(getter_AddRefs(profileDir));
2102 NS_ENSURE_SUCCESS(rv, rv);
2104 nsCOMPtr<nsILocalFile> profileLocalDir;
2105 rv = profile->GetRootDir(getter_AddRefs(profileLocalDir));
2106 NS_ENSURE_SUCCESS(rv, rv);
2108 return ProfileLockedDialog(profileDir, profileLocalDir, unlocker,
2109 aNative, aResult);
2113 return ShowProfileManager(profileSvc, aNative);
2116 #define FILE_COMPATIBILITY_INFO NS_LITERAL_CSTRING("compatibility.ini")
2118 static PRBool
2119 CheckCompatibility(nsIFile* aProfileDir, const nsCString& aVersion,
2120 const nsCString& aOSABI, nsIFile* aXULRunnerDir,
2121 nsIFile* aAppDir)
2123 nsCOMPtr<nsIFile> file;
2124 aProfileDir->Clone(getter_AddRefs(file));
2125 if (!file)
2126 return PR_FALSE;
2127 file->AppendNative(FILE_COMPATIBILITY_INFO);
2129 nsINIParser parser;
2130 nsCOMPtr<nsILocalFile> localFile(do_QueryInterface(file));
2131 nsresult rv = parser.Init(localFile);
2132 if (NS_FAILED(rv))
2133 return PR_FALSE;
2135 nsCAutoString buf;
2136 rv = parser.GetString("Compatibility", "LastVersion", buf);
2137 if (NS_FAILED(rv) || !aVersion.Equals(buf))
2138 return PR_FALSE;
2140 rv = parser.GetString("Compatibility", "LastOSABI", buf);
2141 if (NS_FAILED(rv) || !aOSABI.Equals(buf))
2142 return PR_FALSE;
2144 rv = parser.GetString("Compatibility", "LastPlatformDir", buf);
2145 if (NS_FAILED(rv))
2146 return PR_FALSE;
2148 nsCOMPtr<nsILocalFile> lf;
2149 rv = NS_NewNativeLocalFile(buf, PR_FALSE,
2150 getter_AddRefs(lf));
2151 if (NS_FAILED(rv))
2152 return PR_FALSE;
2154 PRBool eq;
2155 rv = lf->Equals(aXULRunnerDir, &eq);
2156 if (NS_FAILED(rv) || !eq)
2157 return PR_FALSE;
2159 if (aAppDir) {
2160 rv = parser.GetString("Compatibility", "LastAppDir", buf);
2161 if (NS_FAILED(rv))
2162 return PR_FALSE;
2164 rv = NS_NewNativeLocalFile(buf, PR_FALSE,
2165 getter_AddRefs(lf));
2166 if (NS_FAILED(rv))
2167 return PR_FALSE;
2169 rv = lf->Equals(aAppDir, &eq);
2170 if (NS_FAILED(rv) || !eq)
2171 return PR_FALSE;
2174 return PR_TRUE;
2177 static void BuildVersion(nsCString &aBuf)
2179 aBuf.Assign(gAppData->version);
2180 aBuf.Append('_');
2181 aBuf.Append(gAppData->buildID);
2182 aBuf.Append('/');
2183 aBuf.Append(gToolkitBuildID);
2186 static void
2187 WriteVersion(nsIFile* aProfileDir, const nsCString& aVersion,
2188 const nsCString& aOSABI, nsIFile* aXULRunnerDir,
2189 nsIFile* aAppDir)
2191 nsCOMPtr<nsIFile> file;
2192 aProfileDir->Clone(getter_AddRefs(file));
2193 if (!file)
2194 return;
2195 file->AppendNative(FILE_COMPATIBILITY_INFO);
2197 nsCOMPtr<nsILocalFile> lf = do_QueryInterface(file);
2199 nsCAutoString platformDir;
2200 aXULRunnerDir->GetNativePath(platformDir);
2202 nsCAutoString appDir;
2203 if (aAppDir)
2204 aAppDir->GetNativePath(appDir);
2206 PRFileDesc *fd = nsnull;
2207 lf->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0600, &fd);
2208 if (!fd) {
2209 NS_ERROR("could not create output stream");
2210 return;
2213 static const char kHeader[] = "[Compatibility]" NS_LINEBREAK
2214 "LastVersion=";
2216 PR_Write(fd, kHeader, sizeof(kHeader) - 1);
2217 PR_Write(fd, aVersion.get(), aVersion.Length());
2219 static const char kOSABIHeader[] = NS_LINEBREAK "LastOSABI=";
2220 PR_Write(fd, kOSABIHeader, sizeof(kOSABIHeader) - 1);
2221 PR_Write(fd, aOSABI.get(), aOSABI.Length());
2223 static const char kPlatformDirHeader[] = NS_LINEBREAK "LastPlatformDir=";
2225 PR_Write(fd, kPlatformDirHeader, sizeof(kPlatformDirHeader) - 1);
2226 PR_Write(fd, platformDir.get(), platformDir.Length());
2228 static const char kAppDirHeader[] = NS_LINEBREAK "LastAppDir=";
2229 if (aAppDir) {
2230 PR_Write(fd, kAppDirHeader, sizeof(kAppDirHeader) - 1);
2231 PR_Write(fd, appDir.get(), appDir.Length());
2234 static const char kNL[] = NS_LINEBREAK;
2235 PR_Write(fd, kNL, sizeof(kNL) - 1);
2237 PR_Close(fd);
2240 static PRBool ComponentsListChanged(nsIFile* aProfileDir)
2242 nsCOMPtr<nsIFile> file;
2243 aProfileDir->Clone(getter_AddRefs(file));
2244 if (!file)
2245 return PR_TRUE;
2246 file->AppendNative(NS_LITERAL_CSTRING(".autoreg"));
2248 PRBool exists = PR_FALSE;
2249 file->Exists(&exists);
2250 return exists;
2253 static void RemoveComponentRegistries(nsIFile* aProfileDir, nsIFile* aLocalProfileDir,
2254 PRBool aRemoveEMFiles)
2256 nsCOMPtr<nsIFile> file;
2257 aProfileDir->Clone(getter_AddRefs(file));
2258 if (!file)
2259 return;
2261 file->AppendNative(NS_LITERAL_CSTRING("compreg.dat"));
2262 file->Remove(PR_FALSE);
2264 file->SetNativeLeafName(NS_LITERAL_CSTRING("xpti.dat"));
2265 file->Remove(PR_FALSE);
2267 file->SetNativeLeafName(NS_LITERAL_CSTRING(".autoreg"));
2268 file->Remove(PR_FALSE);
2270 if (aRemoveEMFiles) {
2271 file->SetNativeLeafName(NS_LITERAL_CSTRING("extensions.ini"));
2272 file->Remove(PR_FALSE);
2275 aLocalProfileDir->Clone(getter_AddRefs(file));
2276 if (!file)
2277 return;
2279 file->AppendNative(NS_LITERAL_CSTRING("XUL" PLATFORM_FASL_SUFFIX));
2280 file->Remove(PR_FALSE);
2283 // To support application initiated restart via nsIAppStartup.quit, we
2284 // need to save various environment variables, and then restore them
2285 // before re-launching the application.
2287 static struct {
2288 const char *name;
2289 char *value;
2290 } gSavedVars[] = {
2291 {"XUL_APP_FILE", nsnull}
2294 static void SaveStateForAppInitiatedRestart()
2296 for (size_t i = 0; i < NS_ARRAY_LENGTH(gSavedVars); ++i) {
2297 const char *s = PR_GetEnv(gSavedVars[i].name);
2298 if (s)
2299 gSavedVars[i].value = PR_smprintf("%s=%s", gSavedVars[i].name, s);
2303 static void RestoreStateForAppInitiatedRestart()
2305 for (size_t i = 0; i < NS_ARRAY_LENGTH(gSavedVars); ++i) {
2306 if (gSavedVars[i].value)
2307 PR_SetEnv(gSavedVars[i].value);
2311 #ifdef MOZ_CRASHREPORTER
2312 // When we first initialize the crash reporter we don't have a profile,
2313 // so we set the minidump path to $TEMP. Once we have a profile,
2314 // we set it to $PROFILE/minidumps, creating the directory
2315 // if needed.
2316 static void MakeOrSetMinidumpPath(nsIFile* profD)
2318 nsCOMPtr<nsIFile> dumpD;
2319 nsresult rv = profD->Clone(getter_AddRefs(dumpD));
2321 if(dumpD) {
2322 PRBool fileExists;
2323 //XXX: do some more error checking here
2324 dumpD->Append(NS_LITERAL_STRING("minidumps"));
2325 rv = dumpD->Exists(&fileExists);
2326 if(!fileExists) {
2327 dumpD->Create(nsIFile::DIRECTORY_TYPE, 0700);
2330 nsAutoString pathStr;
2331 if(NS_SUCCEEDED(dumpD->GetPath(pathStr)))
2332 CrashReporter::SetMinidumpPath(pathStr);
2335 #endif
2337 const nsXREAppData* gAppData = nsnull;
2339 #if defined(XP_OS2)
2340 // because we use early returns, we use a stack-based helper to un-set the OS2 FP handler
2341 class ScopedFPHandler {
2342 private:
2343 EXCEPTIONREGISTRATIONRECORD excpreg;
2345 public:
2346 ScopedFPHandler() { PR_OS2_SetFloatExcpHandler(&excpreg); }
2347 ~ScopedFPHandler() { PR_OS2_UnsetFloatExcpHandler(&excpreg); }
2349 #endif
2351 #ifdef MOZ_WIDGET_GTK2
2352 #include "prlink.h"
2353 typedef void (*_g_set_application_name_fn)(const gchar *application_name);
2354 typedef void (*_gtk_window_set_auto_startup_notification_fn)(gboolean setting);
2356 static PRFuncPtr FindFunction(const char* aName)
2358 PRLibrary *lib = nsnull;
2359 PRFuncPtr result = PR_FindFunctionSymbolAndLibrary(aName, &lib);
2360 // Since the library was already loaded, we can safely unload it here.
2361 if (lib) {
2362 PR_UnloadLibrary(lib);
2364 return result;
2367 static nsIWidget* GetMainWidget(nsIDOMWindow* aWindow)
2369 // get the native window for this instance
2370 nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(aWindow));
2371 NS_ENSURE_TRUE(window, nsnull);
2373 nsCOMPtr<nsIBaseWindow> baseWindow
2374 (do_QueryInterface(window->GetDocShell()));
2375 NS_ENSURE_TRUE(baseWindow, nsnull);
2377 nsCOMPtr<nsIWidget> mainWidget;
2378 baseWindow->GetMainWidget(getter_AddRefs(mainWidget));
2379 return mainWidget;
2382 static nsGTKToolkit* GetGTKToolkit()
2384 nsCOMPtr<nsIAppShellService> svc = do_GetService(NS_APPSHELLSERVICE_CONTRACTID);
2385 if (!svc)
2386 return nsnull;
2387 nsCOMPtr<nsIDOMWindowInternal> window;
2388 svc->GetHiddenDOMWindow(getter_AddRefs(window));
2389 if (!window)
2390 return nsnull;
2391 nsIWidget* widget = GetMainWidget(window);
2392 if (!widget)
2393 return nsnull;
2394 nsIToolkit* toolkit = widget->GetToolkit();
2395 if (!toolkit)
2396 return nsnull;
2397 return static_cast<nsGTKToolkit*>(toolkit);
2400 static void MOZ_gdk_display_close(GdkDisplay *display)
2402 // XXX wallpaper for bug 417163: don't close the Display if we're using the
2403 // Qt theme because we crash (in Qt code) when using jemalloc.
2404 PRBool theme_is_qt = PR_FALSE;
2405 GtkSettings* settings =
2406 gtk_settings_get_for_screen(gdk_display_get_default_screen(display));
2407 gchar *theme_name;
2408 g_object_get(settings, "gtk-theme-name", &theme_name, NULL);
2409 if (theme_name) {
2410 theme_is_qt = strcmp(theme_name, "Qt") == 0;
2411 if (theme_is_qt)
2412 NS_WARNING("wallpaper bug 417163 for Qt theme");
2413 g_free(theme_name);
2416 // gdk_display_close was broken prior to gtk+-2.10.0.
2417 // (http://bugzilla.gnome.org/show_bug.cgi?id=85715)
2418 // gdk_display_manager_set_default_display (gdk_display_manager_get(), NULL)
2419 // was also broken.
2420 if (gtk_check_version(2,10,0) != NULL) {
2421 #ifdef MOZ_X11
2422 // Version check failed - broken gdk_display_close.
2424 // Let the gdk structures leak but at least close the Display,
2425 // assuming that gdk will not use it again.
2426 Display* dpy = GDK_DISPLAY_XDISPLAY(display);
2427 if (!theme_is_qt)
2428 XCloseDisplay(dpy);
2429 #else
2430 gdk_display_close(display);
2431 #endif /* MOZ_X11 */
2433 else {
2434 #if CLEANUP_MEMORY
2435 // Get a (new) Pango context that holds a reference to the fontmap that
2436 // GTK has been using. gdk_pango_context_get() must be called while GTK
2437 // has a default display.
2438 PangoContext *pangoContext = gdk_pango_context_get();
2439 #endif
2441 if (!theme_is_qt)
2442 gdk_display_close(display);
2444 #if CLEANUP_MEMORY
2445 // This doesn't take a reference.
2446 PangoFontMap *fontmap = pango_context_get_font_map(pangoContext);
2447 // Do some shutdown of the fontmap, which releases the fonts, clearing a
2448 // bunch of circular references from the fontmap through the fonts back to
2449 // itself. The shutdown that this does is much less than what's done by
2450 // the fontmap's finalize, though.
2451 if (PANGO_IS_FC_FONT_MAP(fontmap))
2452 pango_fc_font_map_shutdown(PANGO_FC_FONT_MAP(fontmap));
2453 g_object_unref(pangoContext);
2454 // PangoCairo still holds a reference to the fontmap.
2455 // Now that we have finished with GTK and Pango, we could unref fontmap,
2456 // which would allow us to call FcFini, but removing what is really
2457 // Pango's ref feels a bit evil. Pango-1.22 will have support for
2458 // pango_cairo_font_map_set_default(NULL), which would release the
2459 // reference on the old fontmap.
2461 #if GTK_CHECK_VERSION(2,8,0)
2462 // cairo_debug_reset_static_data() is prototyped through cairo.h included
2463 // by gtk.h.
2464 #ifdef cairo_debug_reset_static_data
2465 #error "Looks like we're including Mozilla's cairo instead of system cairo"
2466 #endif
2467 cairo_debug_reset_static_data();
2468 #endif // 2.8.0
2469 #endif // CLEANUP_MEMORY
2472 #endif // MOZ_WIDGET_GTK2
2474 /**
2475 * NSPR will search for the "nspr_use_zone_allocator" symbol throughout
2476 * the process and use it to determine whether the application defines its own
2477 * memory allocator or not.
2479 * Since most applications (e.g. Firefox and Thunderbird) don't use any special
2480 * allocators and therefore don't define this symbol, NSPR must search the
2481 * entire process, which reduces startup performance.
2483 * By defining the symbol here, we can avoid the wasted lookup and hopefully
2484 * improve startup performance.
2486 PRBool nspr_use_zone_allocator = PR_FALSE;
2489 XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
2491 nsresult rv;
2492 ArgResult ar;
2493 NS_TIMELINE_MARK("enter main");
2495 #ifdef DEBUG
2496 if (PR_GetEnv("XRE_MAIN_BREAK"))
2497 NS_BREAK();
2498 #endif
2500 #if defined (XP_WIN32) && !defined (WINCE)
2501 // Suppress the "DLL Foo could not be found" dialog, such that if dependent
2502 // libraries (such as GDI+) are not preset, we gracefully fail to load those
2503 // XPCOM components, instead of being ungraceful.
2504 UINT realMode = SetErrorMode(0);
2505 realMode |= SEM_FAILCRITICALERRORS;
2506 // If XRE_NO_WINDOWS_CRASH_DIALOG is set, suppress displaying the "This
2507 // application has crashed" dialog box. This is mainly useful for
2508 // automated testing environments, e.g. tinderbox, where there's no need
2509 // for a dozen of the dialog boxes to litter the console
2510 if (getenv("XRE_NO_WINDOWS_CRASH_DIALOG"))
2511 realMode |= SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX;
2513 SetErrorMode(realMode);
2515 #ifdef DEBUG
2516 // Disable small heap allocator to get heapwalk() giving us
2517 // accurate heap numbers. Win2k non-debug does not use small heap allocator.
2518 // Win2k debug seems to be still using it.
2519 // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt__set_sbh_threshold.asp
2520 _set_sbh_threshold(0);
2521 #endif
2522 #endif
2524 #if defined(XP_UNIX) || defined(XP_BEOS)
2525 InstallUnixSignalHandlers(argv[0]);
2526 #endif
2528 #ifdef MOZ_ACCESSIBILITY_ATK
2529 // Reset GTK_MODULES, strip atk-bridge if exists
2530 // Mozilla will load libatk-bridge.so later if necessary
2531 const char* gtkModules = PR_GetEnv("GTK_MODULES");
2532 if (gtkModules && *gtkModules) {
2533 nsCString gtkModulesStr(gtkModules);
2534 gtkModulesStr.ReplaceSubstring("atk-bridge", "");
2535 char* expr = PR_smprintf("GTK_MODULES=%s", gtkModulesStr.get());
2536 if (expr)
2537 PR_SetEnv(expr);
2538 // We intentionally leak |expr| here since it is required by PR_SetEnv.
2541 // Suppress atk-bridge init at startup, it works after GNOME 2.24.2
2542 PR_SetEnv("NO_AT_BRIDGE=1");
2543 #endif
2545 #ifndef WINCE
2546 // Unbuffer stdout, needed for tinderbox tests.
2547 setbuf(stdout, 0);
2548 #endif
2550 #if defined(FREEBSD)
2551 // Disable all SIGFPE's on FreeBSD, as it has non-IEEE-conformant fp
2552 // trap behavior that trips up on floating-point tests performed by
2553 // the JS engine. See bugzilla bug 9967 details.
2554 fpsetmask(0);
2555 #endif
2557 gArgc = argc;
2558 gArgv = argv;
2560 NS_ENSURE_TRUE(aAppData, 2);
2562 #ifdef XP_MACOSX
2563 // The xulrunner stub executable tricks CFBundleGetMainBundle on
2564 // purpose into lying about the main bundle path. It will set
2565 // XRE_BINARY_PATH to inform us of our real location.
2566 gBinaryPath = getenv("XRE_BINARY_PATH");
2568 if (gBinaryPath && !*gBinaryPath)
2569 gBinaryPath = nsnull;
2570 #endif
2572 // Check for application.ini overrides
2573 const char* override = nsnull;
2574 ar = CheckArg("override", PR_TRUE, &override);
2575 if (ar == ARG_BAD) {
2576 Output(PR_TRUE, "Incorrect number of arguments passed to -override");
2577 return 1;
2579 else if (ar == ARG_FOUND) {
2580 nsCOMPtr<nsILocalFile> overrideLF;
2581 rv = XRE_GetFileFromPath(override, getter_AddRefs(overrideLF));
2582 if (NS_FAILED(rv)) {
2583 Output(PR_TRUE, "Error: unrecognized override.ini path.\n");
2584 return 1;
2587 nsXREAppData* overrideAppData = const_cast<nsXREAppData*>(aAppData);
2588 rv = XRE_ParseAppData(overrideLF, overrideAppData);
2589 if (NS_FAILED(rv)) {
2590 Output(PR_TRUE, "Couldn't read override.ini");
2591 return 1;
2595 ScopedAppData appData(aAppData);
2596 gAppData = &appData;
2598 // Check sanity and correctness of app data.
2600 if (!appData.name) {
2601 Output(PR_TRUE, "Error: App:Name not specified in application.ini\n");
2602 return 1;
2604 if (!appData.buildID) {
2605 Output(PR_TRUE, "Error: App:BuildID not specified in application.ini\n");
2606 return 1;
2609 ScopedLogging log;
2611 if (!appData.xreDirectory) {
2612 nsCOMPtr<nsILocalFile> lf;
2613 rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf));
2614 if (NS_FAILED(rv))
2615 return 2;
2617 nsCOMPtr<nsIFile> greDir;
2618 rv = lf->GetParent(getter_AddRefs(greDir));
2619 if (NS_FAILED(rv))
2620 return 2;
2622 rv = CallQueryInterface(greDir, &appData.xreDirectory);
2623 if (NS_FAILED(rv))
2624 return 2;
2627 nsCOMPtr<nsIFile> iniFile;
2628 rv = appData.xreDirectory->Clone(getter_AddRefs(iniFile));
2629 if (NS_FAILED(rv))
2630 return 2;
2632 iniFile->AppendNative(NS_LITERAL_CSTRING("platform.ini"));
2634 nsCOMPtr<nsILocalFile> localIniFile = do_QueryInterface(iniFile);
2635 if (!localIniFile)
2636 return 2;
2638 nsINIParser parser;
2639 rv = parser.Init(localIniFile);
2640 if (NS_SUCCEEDED(rv)) {
2641 rv = parser.GetString("Build", "Milestone",
2642 gToolkitVersion, sizeof(gToolkitVersion));
2643 NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to get toolkit version");
2645 rv = parser.GetString("Build", "BuildID",
2646 gToolkitBuildID, sizeof(gToolkitBuildID));
2647 NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to get toolkit buildid");
2649 else {
2650 NS_ERROR("Couldn't parse platform.ini!");
2653 if (appData.size > offsetof(nsXREAppData, minVersion)) {
2654 if (!appData.minVersion) {
2655 Output(PR_TRUE, "Error: Gecko:MinVersion not specified in application.ini\n");
2656 return 1;
2659 if (!appData.maxVersion) {
2660 // If no maxVersion is specified, we assume the app is only compatible
2661 // with the initial preview release. Do not increment this number ever!
2662 SetAllocatedString(appData.maxVersion, "1.*");
2665 if (NS_CompareVersions(appData.minVersion, gToolkitVersion) > 0 ||
2666 NS_CompareVersions(appData.maxVersion, gToolkitVersion) < 0) {
2667 Output(PR_TRUE, "Error: Platform version '%s' is not compatible with\n"
2668 "minVersion >= %s\nmaxVersion <= %s\n",
2669 gToolkitVersion,
2670 appData.minVersion, appData.maxVersion);
2671 return 1;
2675 #ifdef MOZ_CRASHREPORTER
2676 const char* crashreporterEnv = PR_GetEnv("MOZ_CRASHREPORTER");
2677 if (crashreporterEnv && *crashreporterEnv) {
2678 appData.flags |= NS_XRE_ENABLE_CRASH_REPORTER;
2681 if ((appData.flags & NS_XRE_ENABLE_CRASH_REPORTER) &&
2682 NS_SUCCEEDED(
2683 CrashReporter::SetExceptionHandler(appData.xreDirectory,
2684 appData.crashReporterURL))) {
2685 // pass some basic info from the app data
2686 if (appData.vendor)
2687 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Vendor"),
2688 nsDependentCString(appData.vendor));
2689 if (appData.name)
2690 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProductName"),
2691 nsDependentCString(appData.name));
2692 if (appData.version)
2693 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Version"),
2694 nsDependentCString(appData.version));
2695 if (appData.buildID)
2696 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("BuildID"),
2697 nsDependentCString(appData.buildID));
2698 CrashReporter::SetRestartArgs(argc, argv);
2700 // annotate other data (user id etc)
2701 nsXREDirProvider dirProvider;
2702 nsCOMPtr<nsILocalFile> userAppDataDir;
2703 rv = dirProvider.Initialize(gAppData->directory, gAppData->xreDirectory);
2704 if (NS_SUCCEEDED(rv) &&
2705 NS_SUCCEEDED(dirProvider.GetUserAppDataDirectory(
2706 getter_AddRefs(userAppDataDir)))) {
2707 CrashReporter::SetupExtraData(userAppDataDir,
2708 nsDependentCString(appData.buildID));
2710 // see if we have a crashreporter-override.ini in the application directory
2711 nsCOMPtr<nsIFile> overrideini;
2712 PRBool exists;
2713 static char overrideEnv[MAXPATHLEN];
2714 if (NS_SUCCEEDED(dirProvider.GetAppDir()->Clone(getter_AddRefs(overrideini))) &&
2715 NS_SUCCEEDED(overrideini->AppendNative(NS_LITERAL_CSTRING("crashreporter-override.ini"))) &&
2716 NS_SUCCEEDED(overrideini->Exists(&exists)) &&
2717 exists) {
2718 #ifdef XP_WIN
2719 nsAutoString overridePathW;
2720 overrideini->GetPath(overridePathW);
2721 NS_ConvertUTF16toUTF8 overridePath(overridePathW);
2722 #else
2723 nsCAutoString overridePath;
2724 overrideini->GetNativePath(overridePath);
2725 #endif
2727 sprintf(overrideEnv, "MOZ_CRASHREPORTER_STRINGS_OVERRIDE=%s",
2728 overridePath.get());
2729 PR_SetEnv(overrideEnv);
2733 #endif
2735 #ifdef XP_MACOSX
2736 if (PR_GetEnv("MOZ_LAUNCHED_CHILD")) {
2737 // This is needed, on relaunch, to force the OS to use the "Cocoa Dock
2738 // API". Otherwise the call to ReceiveNextEvent() below will make it
2739 // use the "Carbon Dock API". For more info see bmo bug 377166.
2740 EnsureUseCocoaDockAPI();
2742 // When the app relaunches, the original process exits. This causes
2743 // the dock tile to stop bouncing, lose the "running" triangle, and
2744 // if the tile does not permanently reside in the Dock, even disappear.
2745 // This can be confusing to the user, who is expecting the app to launch.
2746 // Calling ReceiveNextEvent without requesting any event is enough to
2747 // cause a dock tile for the child process to appear.
2748 const EventTypeSpec kFakeEventList[] = { { INT_MAX, INT_MAX } };
2749 EventRef event;
2750 ::ReceiveNextEvent(GetEventTypeCount(kFakeEventList), kFakeEventList,
2751 kEventDurationNoWait, PR_FALSE, &event);
2754 if (CheckArg("foreground")) {
2755 // The original process communicates that it was in the foreground by
2756 // adding this argument. This new process, which is taking over for
2757 // the old one, should make itself the active application.
2758 ProcessSerialNumber psn;
2759 if (::GetCurrentProcess(&psn) == noErr)
2760 ::SetFrontProcess(&psn);
2762 #endif
2764 PR_SetEnv("MOZ_LAUNCHED_CHILD=");
2766 gRestartArgc = gArgc;
2767 gRestartArgv = (char**) malloc(sizeof(char*) * (gArgc + 1 + (override ? 2 : 0)));
2768 if (!gRestartArgv) return 1;
2770 int i;
2771 for (i = 0; i < gArgc; ++i) {
2772 gRestartArgv[i] = gArgv[i];
2775 // Add the -override argument back (it is removed automatically be CheckArg) if there is one
2776 if (override) {
2777 gRestartArgv[gRestartArgc++] = const_cast<char*>("-override");
2778 gRestartArgv[gRestartArgc++] = const_cast<char*>(override);
2781 gRestartArgv[gRestartArgc] = nsnull;
2784 #if defined(XP_OS2)
2785 PRBool StartOS2App(int aArgc, char **aArgv);
2786 if (!StartOS2App(gArgc, gArgv))
2787 return 1;
2788 ScopedFPHandler handler;
2789 #endif /* XP_OS2 */
2791 ar = CheckArg("safe-mode", PR_TRUE);
2792 if (ar == ARG_BAD) {
2793 PR_fprintf(PR_STDERR, "Error: argument -safe-mode is invalid when argument -osint is specified\n");
2794 return 1;
2795 } else if (ar == ARG_FOUND) {
2796 gSafeMode = PR_TRUE;
2799 #ifdef XP_MACOSX
2800 if (GetCurrentEventKeyModifiers() & optionKey)
2801 gSafeMode = PR_TRUE;
2802 #endif
2804 // Handle -no-remote command line argument. Setup the environment to
2805 // better accommodate other components and various restart scenarios.
2806 ar = CheckArg("no-remote", PR_TRUE);
2807 if (ar == ARG_BAD) {
2808 PR_fprintf(PR_STDERR, "Error: argument -a requires an application name\n");
2809 return 1;
2810 } else if (ar == ARG_FOUND) {
2811 PR_SetEnv("MOZ_NO_REMOTE=1");
2814 // Handle -help and -version command line arguments.
2815 // They should return quickly, so we deal with them here.
2816 if (CheckArg("h") || CheckArg("help") || CheckArg("?")) {
2817 DumpHelp();
2818 return 0;
2821 if (CheckArg("v") || CheckArg("version")) {
2822 DumpVersion();
2823 return 0;
2826 #ifdef NS_TRACE_MALLOC
2827 gArgc = argc = NS_TraceMallocStartupArgs(gArgc, gArgv);
2828 #endif
2831 nsXREDirProvider dirProvider;
2832 rv = dirProvider.Initialize(gAppData->directory, gAppData->xreDirectory);
2833 if (NS_FAILED(rv))
2834 return 1;
2836 // Check for -register, which registers chrome and then exits immediately.
2837 ar = CheckArg("register", PR_TRUE);
2838 if (ar == ARG_BAD) {
2839 PR_fprintf(PR_STDERR, "Error: argument -register is invalid when argument -osint is specified\n");
2840 return 1;
2841 } else if (ar == ARG_FOUND) {
2842 ScopedXPCOMStartup xpcom;
2843 rv = xpcom.Initialize();
2844 NS_ENSURE_SUCCESS(rv, 1);
2847 nsCOMPtr<nsIChromeRegistry> chromeReg
2848 (do_GetService("@mozilla.org/chrome/chrome-registry;1"));
2849 NS_ENSURE_TRUE(chromeReg, 1);
2851 chromeReg->CheckForNewChrome();
2853 return 0;
2856 #if defined(MOZ_WIDGET_GTK2) || defined(MOZ_ENABLE_XREMOTE)
2857 // Stash DESKTOP_STARTUP_ID in malloc'ed memory because gtk_init will clear it.
2858 #define HAVE_DESKTOP_STARTUP_ID
2859 const char* desktopStartupIDEnv = PR_GetEnv("DESKTOP_STARTUP_ID");
2860 nsCAutoString desktopStartupID;
2861 if (desktopStartupIDEnv) {
2862 desktopStartupID.Assign(desktopStartupIDEnv);
2864 #endif
2866 #if defined(MOZ_WIDGET_QT)
2867 QApplication app(gArgc, gArgv);
2868 #endif
2869 #if defined(MOZ_WIDGET_GTK2)
2870 #ifdef MOZ_MEMORY
2871 // Disable the slice allocator, since jemalloc already uses similar layout
2872 // algorithms, and using a sub-allocator tends to increase fragmentation.
2873 // This must be done before g_thread_init() is called.
2874 g_slice_set_config(G_SLICE_CONFIG_ALWAYS_MALLOC, 1);
2875 #endif
2876 g_thread_init(NULL);
2877 // setup for private colormap. Ideally we'd like to do this
2878 // in nsAppShell::Create, but we need to get in before gtk
2879 // has been initialized to make sure everything is running
2880 // consistently.
2881 if (CheckArg("install"))
2882 gdk_rgb_set_install(TRUE);
2884 // Initialize GTK here for splash.
2886 // Open the display ourselves instead of using gtk_init, so that we can
2887 // close it without fear that one day gtk might clean up the display it
2888 // opens.
2889 if (!gtk_parse_args(&gArgc, &gArgv))
2890 return 1;
2892 // display_name is owned by gdk.
2893 const char *display_name = gdk_get_display_arg_name();
2894 if (display_name) {
2895 SaveWordToEnv("DISPLAY", nsDependentCString(display_name));
2896 } else {
2897 display_name = PR_GetEnv("DISPLAY");
2898 if (!display_name) {
2899 PR_fprintf(PR_STDERR, "Error: no display specified\n");
2900 return 1;
2903 #endif /* MOZ_WIDGET_GTK2 */
2905 #ifdef MOZ_ENABLE_XREMOTE
2906 // handle -remote now that xpcom is fired up
2908 const char* xremotearg;
2909 ar = CheckArg("remote", PR_TRUE, &xremotearg);
2910 if (ar == ARG_BAD) {
2911 PR_fprintf(PR_STDERR, "Error: -remote requires an argument\n");
2912 return 1;
2914 const char* desktopStartupIDPtr =
2915 desktopStartupID.IsEmpty() ? nsnull : desktopStartupID.get();
2916 if (ar) {
2917 return HandleRemoteArgument(xremotearg, desktopStartupIDPtr);
2920 if (!PR_GetEnv("MOZ_NO_REMOTE")) {
2921 // Try to remote the entire command line. If this fails, start up normally.
2922 RemoteResult rr = RemoteCommandLine(desktopStartupIDPtr);
2923 if (rr == REMOTE_FOUND)
2924 return 0;
2925 else if (rr == REMOTE_ARG_BAD)
2926 return 1;
2928 #endif
2930 #if defined(MOZ_WIDGET_GTK2)
2931 GdkDisplay* display = nsnull;
2932 display = gdk_display_open(display_name);
2933 if (!display) {
2934 PR_fprintf(PR_STDERR, "Error: cannot open display: %s\n", display_name);
2935 return 1;
2937 gdk_display_manager_set_default_display (gdk_display_manager_get(),
2938 display);
2940 // g_set_application_name () is only defined in glib2.2 and higher.
2941 _g_set_application_name_fn _g_set_application_name =
2942 (_g_set_application_name_fn)FindFunction("g_set_application_name");
2943 if (_g_set_application_name) {
2944 _g_set_application_name(gAppData->name);
2946 _gtk_window_set_auto_startup_notification_fn _gtk_window_set_auto_startup_notification =
2947 (_gtk_window_set_auto_startup_notification_fn)FindFunction("gtk_window_set_auto_startup_notification");
2948 if (_gtk_window_set_auto_startup_notification) {
2949 _gtk_window_set_auto_startup_notification(PR_FALSE);
2952 gtk_widget_set_default_visual(gdk_rgb_get_visual());
2953 gtk_widget_set_default_colormap(gdk_rgb_get_cmap());
2954 #endif /* MOZ_WIDGET_GTK2 */
2956 // Call the code to install our handler
2957 #ifdef MOZ_JPROF
2958 setupProfilingStuff();
2959 #endif
2961 // Try to allocate "native app support."
2962 nsCOMPtr<nsINativeAppSupport> nativeApp;
2963 rv = NS_CreateNativeAppSupport(getter_AddRefs(nativeApp));
2964 if (NS_FAILED(rv))
2965 return 1;
2967 PRBool canRun = PR_FALSE;
2968 rv = nativeApp->Start(&canRun);
2969 if (NS_FAILED(rv) || !canRun) {
2970 return 1;
2973 #if defined(MOZ_UPDATER)
2974 // Check for and process any available updates
2975 nsCOMPtr<nsIFile> updRoot;
2976 PRBool persistent;
2977 rv = dirProvider.GetFile(XRE_UPDATE_ROOT_DIR, &persistent,
2978 getter_AddRefs(updRoot));
2979 // XRE_UPDATE_ROOT_DIR may fail. Fallback to appDir if failed
2980 if (NS_FAILED(rv))
2981 updRoot = dirProvider.GetAppDir();
2983 ProcessUpdates(dirProvider.GetGREDir(),
2984 dirProvider.GetAppDir(),
2985 updRoot,
2986 gRestartArgc,
2987 gRestartArgv,
2988 appData.version);
2989 #endif
2991 nsCOMPtr<nsIProfileLock> profileLock;
2992 PRBool startOffline = PR_FALSE;
2993 nsCAutoString profileName;
2995 rv = SelectProfile(getter_AddRefs(profileLock), nativeApp, &startOffline,
2996 &profileName);
2997 if (rv == NS_ERROR_LAUNCHED_CHILD_PROCESS ||
2998 rv == NS_ERROR_ABORT) return 0;
2999 if (NS_FAILED(rv)) return 1;
3001 nsCOMPtr<nsILocalFile> profD;
3002 rv = profileLock->GetDirectory(getter_AddRefs(profD));
3003 NS_ENSURE_SUCCESS(rv, 1);
3005 nsCOMPtr<nsILocalFile> profLD;
3006 rv = profileLock->GetLocalDirectory(getter_AddRefs(profLD));
3007 NS_ENSURE_SUCCESS(rv, 1);
3009 rv = dirProvider.SetProfile(profD, profLD);
3010 NS_ENSURE_SUCCESS(rv, 1);
3012 //////////////////////// NOW WE HAVE A PROFILE ////////////////////////
3014 #ifdef MOZ_CRASHREPORTER
3015 if (appData.flags & NS_XRE_ENABLE_CRASH_REPORTER)
3016 MakeOrSetMinidumpPath(profD);
3017 #endif
3019 PRBool upgraded = PR_FALSE;
3021 nsCAutoString version;
3022 BuildVersion(version);
3024 #ifdef TARGET_OS_ABI
3025 NS_NAMED_LITERAL_CSTRING(osABI, TARGET_OS_ABI);
3026 #else
3027 // No TARGET_XPCOM_ABI, but at least the OS is known
3028 NS_NAMED_LITERAL_CSTRING(osABI, OS_TARGET "_UNKNOWN");
3029 #endif
3031 // Check for version compatibility with the last version of the app this
3032 // profile was started with. The format of the version stamp is defined
3033 // by the BuildVersion function.
3034 PRBool versionOK = CheckCompatibility(profD, version, osABI,
3035 dirProvider.GetGREDir(),
3036 gAppData->directory);
3038 // Every time a profile is loaded by a build with a different version,
3039 // it updates the compatibility.ini file saying what version last wrote
3040 // the compreg.dat. On subsequent launches if the version matches,
3041 // there is no need for re-registration. If the user loads the same
3042 // profile in different builds the component registry must be
3043 // re-generated to prevent mysterious component loading failures.
3045 if (gSafeMode) {
3046 RemoveComponentRegistries(profD, profLD, PR_FALSE);
3047 WriteVersion(profD, NS_LITERAL_CSTRING("Safe Mode"), osABI,
3048 dirProvider.GetGREDir(), gAppData->directory);
3050 else if (versionOK) {
3051 if (ComponentsListChanged(profD)) {
3052 // Remove compreg.dat and xpti.dat, forcing component re-registration.
3053 // The new list of additional components directories is derived from
3054 // information in "extensions.ini".
3055 RemoveComponentRegistries(profD, profLD, PR_FALSE);
3057 // Nothing need be done for the normal startup case.
3059 else {
3060 // Remove compreg.dat and xpti.dat, forcing component re-registration
3061 // with the default set of components (this disables any potentially
3062 // troublesome incompatible XPCOM components).
3063 RemoveComponentRegistries(profD, profLD, PR_TRUE);
3065 // Tell the Extension Manager it should check for incompatible
3066 // Extensions and re-write the "extensions.ini" file with a list of
3067 // directories for compatible extensions
3068 upgraded = PR_TRUE;
3070 // Write out version
3071 WriteVersion(profD, version, osABI,
3072 dirProvider.GetGREDir(), gAppData->directory);
3075 PRBool needsRestart = PR_FALSE;
3076 PRBool appInitiatedRestart = PR_FALSE;
3078 // Allows the user to forcefully bypass the restart process at their
3079 // own risk. Useful for debugging or for tinderboxes where child
3080 // processes can be problematic.
3082 // Start the real application
3083 ScopedXPCOMStartup xpcom;
3084 rv = xpcom.Initialize();
3085 NS_ENSURE_SUCCESS(rv, 1);
3086 rv = xpcom.DoAutoreg();
3087 rv |= xpcom.RegisterProfileService();
3088 rv |= xpcom.SetWindowCreator(nativeApp);
3089 NS_ENSURE_SUCCESS(rv, 1);
3092 if (startOffline) {
3093 nsCOMPtr<nsIIOService2> io (do_GetService("@mozilla.org/network/io-service;1"));
3094 NS_ENSURE_TRUE(io, 1);
3095 io->SetManageOfflineStatus(PR_FALSE);
3096 io->SetOffline(PR_TRUE);
3100 NS_TIMELINE_ENTER("startupNotifier");
3101 nsCOMPtr<nsIObserver> startupNotifier
3102 (do_CreateInstance(NS_APPSTARTUPNOTIFIER_CONTRACTID, &rv));
3103 NS_ENSURE_SUCCESS(rv, 1);
3105 startupNotifier->Observe(nsnull, APPSTARTUP_TOPIC, nsnull);
3106 NS_TIMELINE_LEAVE("startupNotifier");
3109 nsCOMPtr<nsIAppStartup> appStartup
3110 (do_GetService(NS_APPSTARTUP_CONTRACTID));
3111 NS_ENSURE_TRUE(appStartup, 1);
3113 if (gDoMigration) {
3114 nsCOMPtr<nsIFile> file;
3115 dirProvider.GetAppDir()->Clone(getter_AddRefs(file));
3116 file->AppendNative(NS_LITERAL_CSTRING("override.ini"));
3117 nsINIParser parser;
3118 nsCOMPtr<nsILocalFile> localFile(do_QueryInterface(file));
3119 nsresult rv = parser.Init(localFile);
3120 if (NS_SUCCEEDED(rv)) {
3121 nsCAutoString buf;
3122 rv = parser.GetString("XRE", "EnableProfileMigrator", buf);
3123 if (NS_SUCCEEDED(rv)) {
3124 if (buf[0] == '0' || buf[0] == 'f' || buf[0] == 'F') {
3125 gDoMigration = PR_FALSE;
3131 // Profile Migration
3132 if (gAppData->flags & NS_XRE_ENABLE_PROFILE_MIGRATOR && gDoMigration) {
3133 gDoMigration = PR_FALSE;
3134 nsCOMPtr<nsIProfileMigrator> pm
3135 (do_CreateInstance(NS_PROFILEMIGRATOR_CONTRACTID));
3136 if (pm)
3137 pm->Migrate(&dirProvider);
3139 dirProvider.DoStartup();
3141 nsCOMPtr<nsICommandLineRunner> cmdLine
3142 (do_CreateInstance("@mozilla.org/toolkit/command-line;1"));
3143 NS_ENSURE_TRUE(cmdLine, 1);
3145 nsCOMPtr<nsIFile> workingDir;
3146 rv = NS_GetSpecialDirectory(NS_OS_CURRENT_WORKING_DIR, getter_AddRefs(workingDir));
3147 NS_ENSURE_SUCCESS(rv, 1);
3149 rv = cmdLine->Init(gArgc, gArgv,
3150 workingDir, nsICommandLine::STATE_INITIAL_LAUNCH);
3151 NS_ENSURE_SUCCESS(rv, 1);
3153 /* Special-case services that need early access to the command
3154 line. */
3155 nsCOMPtr<nsIObserver> chromeObserver
3156 (do_GetService("@mozilla.org/chrome/chrome-registry;1"));
3157 if (chromeObserver) {
3158 chromeObserver->Observe(cmdLine, "command-line-startup", nsnull);
3161 NS_TIMELINE_ENTER("appStartup->CreateHiddenWindow");
3162 rv = appStartup->CreateHiddenWindow();
3163 NS_TIMELINE_LEAVE("appStartup->CreateHiddenWindow");
3164 NS_ENSURE_SUCCESS(rv, 1);
3166 #if defined(HAVE_DESKTOP_STARTUP_ID) && defined(MOZ_WIDGET_GTK2)
3167 nsRefPtr<nsGTKToolkit> toolkit = GetGTKToolkit();
3168 if (toolkit && !desktopStartupID.IsEmpty()) {
3169 toolkit->SetDesktopStartupID(desktopStartupID);
3171 #endif
3173 // Extension Compatibility Checking and Startup
3174 if (gAppData->flags & NS_XRE_ENABLE_EXTENSION_MANAGER) {
3175 nsCOMPtr<nsIExtensionManager> em(do_GetService("@mozilla.org/extensions/manager;1"));
3176 NS_ENSURE_TRUE(em, 1);
3178 ar = CheckArg("install-global-extension", PR_TRUE);
3179 if (ar == ARG_BAD) {
3180 PR_fprintf(PR_STDERR, "Error: argument -install-global-extension is invalid when argument -osint is specified\n");
3181 return 1;
3182 } else if (ar == ARG_FOUND) {
3183 // Do the required processing and then shut down.
3184 em->HandleCommandLineArgs(cmdLine);
3185 return 0;
3188 ar = CheckArg("install-global-theme", PR_TRUE);
3189 if (ar == ARG_BAD) {
3190 PR_fprintf(PR_STDERR, "Error: argument -install-global-theme is invalid when argument -osint is specified\n");
3191 return 1;
3192 } else if (ar == ARG_FOUND) {
3193 // Do the required processing and then shut down.
3194 em->HandleCommandLineArgs(cmdLine);
3195 return 0;
3198 if (upgraded) {
3199 rv = em->CheckForMismatches(&needsRestart);
3200 if (NS_FAILED(rv)) {
3201 needsRestart = PR_FALSE;
3202 upgraded = PR_FALSE;
3206 if (!upgraded || !needsRestart)
3207 em->Start(cmdLine, &needsRestart);
3210 // We want to restart no more than 2 times. The first restart,
3211 // NO_EM_RESTART == "0" , and the second time, "1".
3212 char* noEMRestart = PR_GetEnv("NO_EM_RESTART");
3213 if (noEMRestart && *noEMRestart && *noEMRestart == '1') {
3214 if (upgraded || needsRestart) {
3215 NS_WARNING("EM tried to force us to restart twice! Forcefully preventing that.");
3217 needsRestart = upgraded = PR_FALSE;
3220 if (!upgraded && !needsRestart) {
3221 SaveStateForAppInitiatedRestart();
3223 // clear out any environment variables which may have been set
3224 // during the relaunch process now that we know we won't be relaunching.
3225 PR_SetEnv("XRE_PROFILE_PATH=");
3226 PR_SetEnv("XRE_PROFILE_LOCAL_PATH=");
3227 PR_SetEnv("XRE_PROFILE_NAME=");
3228 PR_SetEnv("XRE_START_OFFLINE=");
3229 PR_SetEnv("XRE_IMPORT_PROFILES=");
3230 PR_SetEnv("NO_EM_RESTART=");
3231 PR_SetEnv("XUL_APP_FILE=");
3232 PR_SetEnv("XRE_BINARY_PATH=");
3234 #ifdef XP_MACOSX
3235 // we re-initialize the command-line service and do appleevents munging
3236 // after we are sure that we're not restarting
3237 cmdLine = do_CreateInstance("@mozilla.org/toolkit/command-line;1");
3238 NS_ENSURE_TRUE(cmdLine, 1);
3240 SetupMacCommandLine(gArgc, gArgv);
3242 rv = cmdLine->Init(gArgc, gArgv,
3243 workingDir, nsICommandLine::STATE_INITIAL_LAUNCH);
3244 NS_ENSURE_SUCCESS(rv, 1);
3245 #endif
3246 #ifdef MOZ_WIDGET_COCOA
3247 // Prepare Cocoa's form of Apple Event handling.
3248 SetupMacApplicationDelegate();
3249 #endif
3250 nsCOMPtr<nsIObserverService> obsService
3251 (do_GetService("@mozilla.org/observer-service;1"));
3252 if (obsService)
3253 obsService->NotifyObservers(nsnull, "final-ui-startup", nsnull);
3255 rv = cmdLine->Run();
3256 NS_ENSURE_SUCCESS_LOG(rv, 1);
3258 #ifdef MOZ_ENABLE_XREMOTE
3259 // if we have X remote support, start listening for requests on the
3260 // proxy window.
3261 nsCOMPtr<nsIRemoteService> remoteService;
3262 remoteService = do_GetService("@mozilla.org/toolkit/remote-service;1");
3263 if (remoteService)
3264 remoteService->Startup(gAppData->name,
3265 PromiseFlatCString(profileName).get());
3266 #endif /* MOZ_ENABLE_XREMOTE */
3268 // enable win32 DDE responses and Mac appleevents responses
3269 nativeApp->Enable();
3271 NS_TIMELINE_ENTER("appStartup->Run");
3272 rv = appStartup->Run();
3273 NS_TIMELINE_LEAVE("appStartup->Run");
3274 if (NS_FAILED(rv)) {
3275 NS_ERROR("failed to run appstartup");
3276 gLogConsoleErrors = PR_TRUE;
3279 // Check for an application initiated restart. This is one that
3280 // corresponds to nsIAppStartup.quit(eRestart)
3281 if (rv == NS_SUCCESS_RESTART_APP) {
3282 needsRestart = PR_TRUE;
3283 appInitiatedRestart = PR_TRUE;
3286 #ifdef MOZ_ENABLE_XREMOTE
3287 // shut down the x remote proxy window
3288 if (remoteService)
3289 remoteService->Shutdown();
3290 #endif /* MOZ_ENABLE_XREMOTE */
3292 #ifdef MOZ_TIMELINE
3293 // Make sure we print this out even if timeline is runtime disabled
3294 if (NS_FAILED(NS_TIMELINE_LEAVE("main1")))
3295 NS_TimelineForceMark("...main1");
3296 #endif
3298 else {
3299 // Upgrade condition (build id changes), but the restart hint was
3300 // not set by the Extension Manager. This is because the compatibility
3301 // resolution for Extensions is different than for the component
3302 // registry - major milestone vs. build id.
3303 needsRestart = PR_TRUE;
3305 #ifdef XP_WIN
3306 ProcessDDE(nativeApp, PR_TRUE);
3307 #endif
3309 #ifdef XP_MACOSX
3310 SetupMacCommandLine(gRestartArgc, gRestartArgv);
3311 #endif
3316 // unlock the profile after ScopedXPCOMStartup object (xpcom)
3317 // has gone out of scope. see bug #386739 for more details
3318 profileLock->Unlock();
3320 // Restart the app after XPCOM has been shut down cleanly.
3321 if (needsRestart) {
3322 if (appInitiatedRestart) {
3323 RestoreStateForAppInitiatedRestart();
3325 else {
3326 char* noEMRestart = PR_GetEnv("NO_EM_RESTART");
3327 if (noEMRestart && *noEMRestart) {
3328 PR_SetEnv("NO_EM_RESTART=1");
3330 else {
3331 PR_SetEnv("NO_EM_RESTART=0");
3335 // Ensure that these environment variables are set:
3336 SaveFileToEnvIfUnset("XRE_PROFILE_PATH", profD);
3337 SaveFileToEnvIfUnset("XRE_PROFILE_LOCAL_PATH", profLD);
3338 SaveWordToEnvIfUnset("XRE_PROFILE_NAME", profileName);
3340 #ifdef XP_MACOSX
3341 if (gBinaryPath) {
3342 static char kEnvVar[MAXPATHLEN];
3343 sprintf(kEnvVar, "XRE_BINARY_PATH=%s", gBinaryPath);
3344 PR_SetEnv(kEnvVar);
3346 #endif
3348 // XXXkt s/MOZ_TOOLKIT_GTK2/MOZ_WIDGET_GTK2/?
3349 // but the hidden window has been destroyed so toolkit is NULL anyway.
3350 #if defined(HAVE_DESKTOP_STARTUP_ID) && defined(MOZ_TOOLKIT_GTK2)
3351 nsGTKToolkit* toolkit = GetGTKToolkit();
3352 if (toolkit) {
3353 nsCAutoString currentDesktopStartupID;
3354 toolkit->GetDesktopStartupID(&currentDesktopStartupID);
3355 if (!currentDesktopStartupID.IsEmpty()) {
3356 nsCAutoString desktopStartupEnv;
3357 desktopStartupEnv.AssignLiteral("DESKTOP_STARTUP_ID=");
3358 desktopStartupEnv.Append(currentDesktopStartupID);
3359 // Leak it with extreme prejudice!
3360 PR_SetEnv(ToNewCString(desktopStartupEnv));
3363 #endif
3365 #ifdef MOZ_WIDGET_GTK2
3366 MOZ_gdk_display_close(display);
3367 #endif
3369 rv = LaunchChild(nativeApp, appInitiatedRestart);
3371 #ifdef MOZ_CRASHREPORTER
3372 if (appData.flags & NS_XRE_ENABLE_CRASH_REPORTER)
3373 CrashReporter::UnsetExceptionHandler();
3374 #endif
3376 return rv == NS_ERROR_LAUNCHED_CHILD_PROCESS ? 0 : 1;
3379 #ifdef MOZ_WIDGET_GTK2
3380 // gdk_display_close also calls gdk_display_manager_set_default_display
3381 // appropriately when necessary.
3382 MOZ_gdk_display_close(display);
3383 #endif
3386 #ifdef MOZ_CRASHREPORTER
3387 if (appData.flags & NS_XRE_ENABLE_CRASH_REPORTER)
3388 CrashReporter::UnsetExceptionHandler();
3389 #endif
3391 return NS_FAILED(rv) ? 1 : 0;