diff options
Diffstat (limited to 'application/palemoon/app/nsBrowserApp.cpp')
-rw-r--r-- | application/palemoon/app/nsBrowserApp.cpp | 452 |
1 files changed, 452 insertions, 0 deletions
diff --git a/application/palemoon/app/nsBrowserApp.cpp b/application/palemoon/app/nsBrowserApp.cpp new file mode 100644 index 000000000..f9645b0c6 --- /dev/null +++ b/application/palemoon/app/nsBrowserApp.cpp @@ -0,0 +1,452 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsXULAppAPI.h" +#include "mozilla/AppData.h" +#include "application.ini.h" +#include "nsXPCOMGlue.h" +#if defined(XP_WIN) +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0600 +#include <windows.h> +#include <winbase.h> +#include <VersionHelpers.h> +#include <stdlib.h> +#include <io.h> +#include <fcntl.h> +#elif defined(XP_UNIX) +#include <sys/resource.h> +#include <time.h> +#include <unistd.h> +#endif + +#ifdef XP_MACOSX +#include <mach/mach_time.h> +#include "MacQuirks.h" +#endif + +#include <stdio.h> +#include <stdarg.h> +#include <time.h> + +#include "nsCOMPtr.h" +#include "nsIFile.h" +#include "nsStringGlue.h" + +// Easy access to a five second startup delay used to get +// a debugger attached in the metro environment. +// #define DEBUG_delay_start_metro + +#ifdef XP_WIN +// we want a wmain entry point +#include "nsWindowsWMain.cpp" +#define snprintf _snprintf +#define strcasecmp _stricmp +#endif +#include "BinaryPath.h" + +#include "nsXPCOMPrivate.h" // for MAXPATHLEN and XPCOM_DLL +#include "mozilla/StartupTimeline.h" + +using namespace mozilla; + +#ifdef XP_MACOSX +#define kOSXResourcesFolder "Resources" +#endif +#define kDesktopFolder "browser" +#define kMetroFolder "metro" +#define kMetroAppIniFilename "metroapp.ini" +#ifdef XP_WIN +#define kMetroTestFile "tests.ini" +const char* kMetroConsoleIdParam = "testconsoleid="; +#endif + +static void Output(const char *fmt, ... ) +{ + va_list ap; + va_start(ap, fmt); + +#ifndef XP_WIN + vfprintf(stderr, fmt, ap); +#else + char msg[2048]; + vsnprintf_s(msg, _countof(msg), _TRUNCATE, fmt, ap); + + wchar_t wide_msg[2048]; + MultiByteToWideChar(CP_UTF8, + 0, + msg, + -1, + wide_msg, + _countof(wide_msg)); +#if MOZ_WINCONSOLE + fwprintf_s(stderr, wide_msg); +#else + MessageBoxW(nullptr, + wide_msg, + L"Pale Moon", + MB_OK | MB_ICONERROR | MB_SETFOREGROUND); +#endif +#endif + + va_end(ap); +} + +/** + * Return true if |arg| matches the given argument name. + */ +static bool IsArg(const char* arg, const char* s) +{ + if (*arg == '-') + { + if (*++arg == '-') + ++arg; + return !strcasecmp(arg, s); + } + +#if defined(XP_WIN) + if (*arg == '/') + return !strcasecmp(++arg, s); +#endif + + return false; +} + +#ifdef XP_WIN +/* + * AttachToTestHarness - Windows helper for when we are running + * in the immersive environment. Firefox is launched by Windows in + * response to a request by metrotestharness, which is launched by + * runtests.py. As such stdout in fx doesn't point to the right + * stream. This helper touches up stdout such that test output gets + * routed to a named pipe metrotestharness creates and dumps to its + * stdout. + */ +static void AttachToTestHarness() +{ + // attach to the metrotestharness named logging pipe + HANDLE winOut = CreateFileA("\\\\.\\pipe\\metrotestharness", + GENERIC_WRITE, + FILE_SHARE_WRITE, 0, + OPEN_EXISTING, 0, 0); + + if (winOut == INVALID_HANDLE_VALUE) { + OutputDebugStringW(L"Could not create named logging pipe.\n"); + return; + } + + // Set the c runtime handle + int stdOut = _open_osfhandle((intptr_t)winOut, _O_APPEND); + if (stdOut == -1) { + OutputDebugStringW(L"Could not open c-runtime handle.\n"); + return; + } + FILE *fp = _fdopen(stdOut, "a"); + *stdout = *fp; +} +#endif + +XRE_GetFileFromPathType XRE_GetFileFromPath; +XRE_CreateAppDataType XRE_CreateAppData; +XRE_FreeAppDataType XRE_FreeAppData; +#ifdef XRE_HAS_DLL_BLOCKLIST +XRE_SetupDllBlocklistType XRE_SetupDllBlocklist; +#endif +XRE_StartupTimelineRecordType XRE_StartupTimelineRecord; +XRE_mainType XRE_main; +XRE_StopLateWriteChecksType XRE_StopLateWriteChecks; + +static const nsDynamicFunctionLoad kXULFuncs[] = { + { "XRE_GetFileFromPath", (NSFuncPtr*) &XRE_GetFileFromPath }, + { "XRE_CreateAppData", (NSFuncPtr*) &XRE_CreateAppData }, + { "XRE_FreeAppData", (NSFuncPtr*) &XRE_FreeAppData }, +#ifdef XRE_HAS_DLL_BLOCKLIST + { "XRE_SetupDllBlocklist", (NSFuncPtr*) &XRE_SetupDllBlocklist }, +#endif + { "XRE_StartupTimelineRecord", (NSFuncPtr*) &XRE_StartupTimelineRecord }, + { "XRE_main", (NSFuncPtr*) &XRE_main }, + { "XRE_StopLateWriteChecks", (NSFuncPtr*) &XRE_StopLateWriteChecks }, + { nullptr, nullptr } +}; + +static int do_main(int argc, char* argv[], nsIFile *xreDirectory) +{ + nsCOMPtr<nsIFile> appini; + nsresult rv; + uint32_t mainFlags = 0; + +#ifdef XP_WIN + if (!IsWindowsVistaOrGreater()) { + Output("Couldn't load valid PE image.\n"); + return 255; + } + +#endif + // Allow palemoon.exe to launch XULRunner apps via -app <application.ini> + // Note that -app must be the *first* argument. + const char *appDataFile = getenv("XUL_APP_FILE"); + if (appDataFile && *appDataFile) { + rv = XRE_GetFileFromPath(appDataFile, getter_AddRefs(appini)); + if (NS_FAILED(rv)) { + Output("Invalid path found: '%s'", appDataFile); + return 255; + } + } + else if (argc > 1 && IsArg(argv[1], "app")) { + if (argc == 2) { + Output("Incorrect number of arguments passed to -app"); + return 255; + } + + rv = XRE_GetFileFromPath(argv[2], getter_AddRefs(appini)); + if (NS_FAILED(rv)) { + Output("application.ini path not recognized: '%s'", argv[2]); + return 255; + } + + char appEnv[MAXPATHLEN]; + snprintf(appEnv, MAXPATHLEN, "XUL_APP_FILE=%s", argv[2]); + if (putenv(appEnv)) { + Output("Couldn't set %s.\n", appEnv); + return 255; + } + argv[2] = argv[0]; + argv += 2; + argc -= 2; + } + + if (appini) { + nsXREAppData *appData; + rv = XRE_CreateAppData(appini, &appData); + if (NS_FAILED(rv)) { + Output("Couldn't read application.ini"); + return 255; + } + // xreDirectory already has a refcount from NS_NewLocalFile + appData->xreDirectory = xreDirectory; + int result = XRE_main(argc, argv, appData, mainFlags); + XRE_FreeAppData(appData); + return result; + } + + // Desktop browser launch + ScopedAppData appData(&sAppData); + nsCOMPtr<nsIFile> exeFile; + rv = mozilla::BinaryPath::GetFile(argv[0], getter_AddRefs(exeFile)); + if (NS_FAILED(rv)) { + Output("Couldn't find the application directory.\n"); + return 255; + } + + nsCOMPtr<nsIFile> greDir; + exeFile->GetParent(getter_AddRefs(greDir)); +#ifdef XP_MACOSX + nsCOMPtr<nsIFile> parent; + greDir->GetParent(getter_AddRefs(parent)); + greDir = parent.forget(); + greDir->AppendNative(NS_LITERAL_CSTRING(kOSXResourcesFolder)); +#endif + nsCOMPtr<nsIFile> appSubdir; + greDir->Clone(getter_AddRefs(appSubdir)); + appSubdir->Append(NS_LITERAL_STRING(kDesktopFolder)); + + SetStrongPtr(appData.directory, static_cast<nsIFile*>(appSubdir.get())); + // xreDirectory already has a refcount from NS_NewLocalFile + appData.xreDirectory = xreDirectory; + + return XRE_main(argc, argv, &appData, mainFlags); +} + +/** + * Local TimeStamp::Now()-compatible implementation used to record timestamps + * which will be passed to XRE_StartupTimelineRecord(). + */ +static uint64_t +TimeStamp_Now() +{ +#ifdef XP_WIN + LARGE_INTEGER freq; + ::QueryPerformanceFrequency(&freq); + return GetTickCount64() * freq.QuadPart; +#elif defined(XP_MACOSX) + return mach_absolute_time(); +#elif defined(HAVE_CLOCK_MONOTONIC) + struct timespec ts; + int rv = clock_gettime(CLOCK_MONOTONIC, &ts); + + if (rv != 0) { + return 0; + } + + uint64_t baseNs = (uint64_t)ts.tv_sec * 1000000000; + return baseNs + (uint64_t)ts.tv_nsec; +#endif +} + +static bool +FileExists(const char *path) +{ +#ifdef XP_WIN + wchar_t wideDir[MAX_PATH]; + MultiByteToWideChar(CP_UTF8, 0, path, -1, wideDir, MAX_PATH); + DWORD fileAttrs = GetFileAttributesW(wideDir); + return fileAttrs != INVALID_FILE_ATTRIBUTES; +#else + return access(path, R_OK) == 0; +#endif +} + +#ifdef LIBXUL_SDK +# define XPCOM_PATH "xulrunner" XPCOM_FILE_PATH_SEPARATOR XPCOM_DLL +#else +# define XPCOM_PATH XPCOM_DLL +#endif +static nsresult +InitXPCOMGlue(const char *argv0, nsIFile **xreDirectory) +{ + char exePath[MAXPATHLEN]; + + nsresult rv = mozilla::BinaryPath::Get(argv0, exePath); + if (NS_FAILED(rv)) { + Output("Couldn't find the application directory.\n"); + return rv; + } + + char *lastSlash = strrchr(exePath, XPCOM_FILE_PATH_SEPARATOR[0]); + if (!lastSlash || (size_t(lastSlash - exePath) > MAXPATHLEN - sizeof(XPCOM_PATH) - 1)) + return NS_ERROR_FAILURE; + + strcpy(lastSlash + 1, XPCOM_PATH); + lastSlash += sizeof(XPCOM_PATH) - sizeof(XPCOM_DLL); + + if (!FileExists(exePath)) { +#if defined(LIBXUL_SDK) && defined(XP_MACOSX) + // Check for <bundle>/Contents/Frameworks/XUL.framework/libxpcom.dylib + bool greFound = false; + CFBundleRef appBundle = CFBundleGetMainBundle(); + if (!appBundle) + return NS_ERROR_FAILURE; + CFURLRef fwurl = CFBundleCopyPrivateFrameworksURL(appBundle); + CFURLRef absfwurl = nullptr; + if (fwurl) { + absfwurl = CFURLCopyAbsoluteURL(fwurl); + CFRelease(fwurl); + } + if (absfwurl) { + CFURLRef xulurl = + CFURLCreateCopyAppendingPathComponent(nullptr, absfwurl, + CFSTR("XUL.framework"), + true); + + if (xulurl) { + CFURLRef xpcomurl = + CFURLCreateCopyAppendingPathComponent(nullptr, xulurl, + CFSTR("libxpcom.dylib"), + false); + + if (xpcomurl) { + if (CFURLGetFileSystemRepresentation(xpcomurl, true, + (UInt8*) exePath, + sizeof(exePath)) && + access(tbuffer, R_OK | X_OK) == 0) { + if (realpath(tbuffer, exePath)) { + greFound = true; + } + } + CFRelease(xpcomurl); + } + CFRelease(xulurl); + } + CFRelease(absfwurl); + } + } + if (!greFound) { +#endif + Output("Could not find the Mozilla runtime.\n"); + return NS_ERROR_FAILURE; + } + + // We do this because of data in bug 771745 + XPCOMGlueEnablePreload(); + + rv = XPCOMGlueStartup(exePath); + if (NS_FAILED(rv)) { + Output("Couldn't load XPCOM.\n"); + return rv; + } + + rv = XPCOMGlueLoadXULFunctions(kXULFuncs); + if (NS_FAILED(rv)) { + Output("Couldn't load XRE functions.\n"); + return rv; + } + + NS_LogInit(); + + // chop XPCOM_DLL off exePath + *lastSlash = '\0'; +#ifdef XP_MACOSX + lastSlash = strrchr(exePath, XPCOM_FILE_PATH_SEPARATOR[0]); + strcpy(lastSlash + 1, kOSXResourcesFolder); +#endif +#ifdef XP_WIN + rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(exePath), false, + xreDirectory); +#else + rv = NS_NewNativeLocalFile(nsDependentCString(exePath), false, + xreDirectory); +#endif + + return rv; +} + +int main(int argc, char* argv[]) +{ +#ifdef DEBUG_delay_start_metro + Sleep(5000); +#endif + uint64_t start = TimeStamp_Now(); + +#ifdef XP_MACOSX + TriggerQuirks(); +#endif + + int gotCounters; +#if defined(XP_UNIX) + struct rusage initialRUsage; + gotCounters = !getrusage(RUSAGE_SELF, &initialRUsage); +#elif defined(XP_WIN) + IO_COUNTERS ioCounters; + gotCounters = GetProcessIoCounters(GetCurrentProcess(), &ioCounters); +#endif + + nsIFile *xreDirectory; + + nsresult rv = InitXPCOMGlue(argv[0], &xreDirectory); + if (NS_FAILED(rv)) { + return 255; + } + + XRE_StartupTimelineRecord(mozilla::StartupTimeline::START, start); + +#ifdef XRE_HAS_DLL_BLOCKLIST + XRE_SetupDllBlocklist(); +#endif + + int result = do_main(argc, argv, xreDirectory); + + NS_LogTerm(); + +#ifdef XP_MACOSX + // Allow writes again. While we would like to catch writes from static + // destructors to allow early exits to use _exit, we know that there is + // at least one such write that we don't control (see bug 826029). For + // now we enable writes again and early exits will have to use exit instead + // of _exit. + XRE_StopLateWriteChecks(); +#endif + + return result; +} |