diff options
author | Brian Smith <brian@dbsoft.org> | 2022-04-26 10:13:11 -0500 |
---|---|---|
committer | Brian Smith <brian@dbsoft.org> | 2022-04-26 10:19:04 -0500 |
commit | 3daf711085889bad1bd68651bc4e8790412ae105 (patch) | |
tree | f5b0e4c1befb320cdf158e1839ac5e273373087f | |
parent | 7fe702603066e7f122d5dd66a3a1892ac7e06215 (diff) | |
download | uxp-3daf711085889bad1bd68651bc4e8790412ae105.tar.gz |
Issue #1829 - Revert “Issue #1751 -- Remove XP_MACOSX conditionals from the rest of the tree.”
This also removes some PP abuse and takes file entries out of PP when no longer
needed without XP_MACOSX conditionals.
This reverts commit 6f707bde95dab6998ac204f9ee6c925ee230c740.
148 files changed, 4472 insertions, 173 deletions
diff --git a/accessible/base/Platform.h b/accessible/base/Platform.h index 264aa438f6..64f7ff7ee2 100644 --- a/accessible/base/Platform.h +++ b/accessible/base/Platform.h @@ -35,10 +35,10 @@ EPlatformDisabledState PlatformDisabledState(); void PreInit(); #endif -#if defined(MOZ_ACCESSIBILITY_ATK) +#if defined(MOZ_ACCESSIBILITY_ATK) || defined(XP_MACOSX) /** * Is platform accessibility enabled. - * Only used on linux with atk. + * Only used on linux with atk and MacOS for now. */ bool ShouldA11yBeEnabled(); #endif diff --git a/build/moz.configure/init.configure b/build/moz.configure/init.configure index 281f2c1ad7..b2d05e795a 100644 --- a/build/moz.configure/init.configure +++ b/build/moz.configure/init.configure @@ -541,6 +541,13 @@ def target_is_unix(target): set_define('XP_UNIX', target_is_unix) @depends(target) +def target_is_osx(target): + if target.kernel == 'Darwin' and target.os == 'OSX': + return True + +set_define('XP_MACOSX', target_is_osx) + +@depends(target) def target_is_linux(target): if target.kernel == 'Linux': return True diff --git a/chrome/nsChromeRegistry.cpp b/chrome/nsChromeRegistry.cpp index ef2cb79ab7..74de3b80d5 100644 --- a/chrome/nsChromeRegistry.cpp +++ b/chrome/nsChromeRegistry.cpp @@ -296,6 +296,8 @@ nsChromeRegistry::ConvertChromeURL(nsIURI* aChromeURI, nsIURI* *aResult) if (flags & PLATFORM_PACKAGE) { #if defined(XP_WIN) path.Insert("win/", 0); +#elif defined(XP_MACOSX) + path.Insert("mac/", 0); #else path.Insert("unix/", 0); #endif diff --git a/chrome/nsChromeRegistryChrome.cpp b/chrome/nsChromeRegistryChrome.cpp index c115280fdc..7678183fd3 100644 --- a/chrome/nsChromeRegistryChrome.cpp +++ b/chrome/nsChromeRegistryChrome.cpp @@ -11,6 +11,8 @@ #if defined(XP_WIN) #include <windows.h> +#elif defined(XP_MACOSX) +#include <CoreServices/CoreServices.h> #endif #include "nsArrayEnumerator.h" diff --git a/config/rules.mk b/config/rules.mk index 840e266ba5..cb3e307ae2 100644 --- a/config/rules.mk +++ b/config/rules.mk @@ -1,4 +1,5 @@ # -*- makefile -*- +# vim:set ts=8 sw=8 sts=8 noet: # # 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, @@ -750,6 +751,7 @@ $(HOST_LIBRARY): $(HOST_OBJS) Makefile $(EXPAND_LIBS_EXEC) --extract -- $(HOST_AR) $(HOST_AR_FLAGS) $(HOST_OBJS) ifdef HAVE_DTRACE +ifndef XP_MACOSX ifdef DTRACE_PROBE_OBJ ifndef DTRACE_LIB_DEPENDENT NON_DTRACE_OBJS := $(filter-out $(DTRACE_PROBE_OBJ),$(OBJS)) @@ -758,6 +760,7 @@ $(DTRACE_PROBE_OBJ): $(NON_DTRACE_OBJS) endif endif endif +endif # On Darwin (Mac OS X), dwarf2 debugging uses debug info left in .o files, # so instead of deleting .o files after repacking them into a dylib, we make @@ -770,7 +773,9 @@ ifndef INCREMENTAL_LINKER $(RM) $@ endif ifdef DTRACE_LIB_DEPENDENT +ifndef XP_MACOSX dtrace -x nolibs -G -C -s $(MOZILLA_DTRACE_SRC) -o $(DTRACE_PROBE_OBJ) $(shell $(EXPAND_LIBS) $(MOZILLA_PROBE_LIBS)) +endif $(EXPAND_MKSHLIB) $(SHLIB_LDSTARTFILE) $(OBJS) $(SUB_SHLOBJS) $(DTRACE_PROBE_OBJ) $(MOZILLA_PROBE_LIBS) $(RESFILE) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(RUST_STATIC_LIB_FOR_SHARED_LIB) $(SHARED_LIBS) $(EXTRA_DSO_LDOPTS) $(MOZ_GLUE_LDFLAGS) $(EXTRA_LIBS) $(OS_LIBS) $(SHLIB_LDENDFILE) @$(RM) $(DTRACE_PROBE_OBJ) else # ! DTRACE_LIB_DEPENDENT diff --git a/db/mork/src/morkConfig.h b/db/mork/src/morkConfig.h index dbd4ebdf5b..370cf17139 100644 --- a/db/mork/src/morkConfig.h +++ b/db/mork/src/morkConfig.h @@ -18,6 +18,10 @@ // { %%%%% begin platform defs peculiar to Mork %%%%% +#ifdef XP_MACOSX +#define MORK_MAC 1 +#endif + #ifdef XP_WIN #define MORK_WIN 1 #endif @@ -28,7 +32,7 @@ // } %%%%% end platform defs peculiar to Mork %%%%% -#if defined(MORK_WIN) || defined(MORK_UNIX) +#if defined(MORK_WIN) || defined(MORK_UNIX) || defined(MORK_MAC) #include <stdio.h> #include <ctype.h> #include <errno.h> @@ -84,15 +88,20 @@ void mork_fileflush(FILE * file); #define mork_kTAB '\011' #define mork_kCRLF "\015\012" /* A CR LF equivalent string */ -#if defined(MORK_WIN) -# define mork_kNewline "\015\012" -# define mork_kNewlineSize 2 +#if defined(MORK_MAC) +# define mork_kNewline "\015" +# define mork_kNewlineSize 1 #else -# if defined(MORK_UNIX) -# define mork_kNewline "\012" -# define mork_kNewlineSize 1 -# endif /* MORK_UNIX */ -#endif /* MORK_WIN */ +# if defined(MORK_WIN) +# define mork_kNewline "\015\012" +# define mork_kNewlineSize 2 +# else +# if defined(MORK_UNIX) +# define mork_kNewline "\012" +# define mork_kNewlineSize 1 +# endif /* MORK_UNIX */ +# endif /* MORK_WIN */ +#endif /* MORK_MAC */ // { %%%%% begin assertion macro %%%%% extern void mork_assertion_signal(const char* inMessage); @@ -105,7 +114,7 @@ extern void mork_assertion_signal(const char* inMessage); // { %%%%% begin standard c utility methods %%%%% -#if defined(MORK_WIN) || defined(MORK_UNIX) +#if defined(MORK_WIN) || defined(MORK_UNIX) || defined(MORK_MAC) #define MORK_USE_C_STDLIB 1 #endif /*MORK_WIN*/ diff --git a/devtools/client/framework/dev-edition-promo/dev-edition-promo.css b/devtools/client/framework/dev-edition-promo/dev-edition-promo.css index b4d6383825..01489fd47f 100644 --- a/devtools/client/framework/dev-edition-promo/dev-edition-promo.css +++ b/devtools/client/framework/dev-edition-promo/dev-edition-promo.css @@ -21,10 +21,14 @@ window { * depend on. Must style font-size to target linux. */ %ifdef XP_UNIX +%ifndef XP_MACOSX font-size: 13px; %else font-size: 15px; %endif +%else + font-size: 15px; +%endif line-height: 19px; min-height: 100px; } diff --git a/devtools/client/framework/toolbox-process-window.js b/devtools/client/framework/toolbox-process-window.js index 87b3efa438..82edabe9c6 100644 --- a/devtools/client/framework/toolbox-process-window.js +++ b/devtools/client/framework/toolbox-process-window.js @@ -142,6 +142,16 @@ function evaluateTestScript(script, toolbox) { function bindToolboxHandlers() { gToolbox.once("destroyed", quitApp); window.addEventListener("unload", onUnload); + +#ifdef XP_MACOSX + // Badge the dock icon to differentiate this process from the main application process. + updateBadgeText(false); + + // Once the debugger panel opens listen for thread pause / resume. + gToolbox.getPanelWhenReady("jsdebugger").then(panel => { + setupThreadListeners(panel); + }); +#endif } function setupThreadListeners(panel) { diff --git a/devtools/client/jar.mn b/devtools/client/jar.mn index 9951e7e3dc..763a59fbd6 100644 --- a/devtools/client/jar.mn +++ b/devtools/client/jar.mn @@ -110,7 +110,7 @@ devtools.jar: content/framework/toolbox-init.js (framework/toolbox-init.js) content/framework/options-panel.css (framework/options-panel.css) content/framework/toolbox-process-window.xul (framework/toolbox-process-window.xul) - content/framework/toolbox-process-window.js (framework/toolbox-process-window.js) +* content/framework/toolbox-process-window.js (framework/toolbox-process-window.js) content/framework/dev-edition-promo/dev-edition-promo.xul (framework/dev-edition-promo/dev-edition-promo.xul) * content/framework/dev-edition-promo/dev-edition-promo.css (framework/dev-edition-promo/dev-edition-promo.css) content/framework/dev-edition-promo/dev-edition-logo.png (framework/dev-edition-promo/dev-edition-logo.png) diff --git a/dom/html/HTMLObjectElement.h b/dom/html/HTMLObjectElement.h index 0e69ef5faa..6f0990918f 100644 --- a/dom/html/HTMLObjectElement.h +++ b/dom/html/HTMLObjectElement.h @@ -32,6 +32,18 @@ public: NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLObjectElement, object) virtual int32_t TabIndexDefault() override; +#ifdef XP_MACOSX + // nsIDOMEventTarget + NS_IMETHOD PostHandleEvent(EventChainPostVisitor& aVisitor) override; + // Helper methods + static void OnFocusBlurPlugin(Element* aElement, bool aFocus); + static void HandleFocusBlurPlugin(Element* aElement, WidgetEvent* aEvent); + static void HandlePluginCrashed(Element* aElement); + static void HandlePluginInstantiated(Element* aElement); + // Weak pointer. Null if last action was blur. + static Element* sLastFocused; +#endif + // Element virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const override; diff --git a/extensions/auth/gssapi.h b/extensions/auth/gssapi.h index a5331d741b..a3ce3d8c58 100644 --- a/extensions/auth/gssapi.h +++ b/extensions/auth/gssapi.h @@ -1,3 +1,4 @@ +/* vim:set ts=4 sw=4 sts=4 et cindent: */ /* ***** BEGIN LICENSE BLOCK ***** * Copyright 1993 by OpenVision Technologies, Inc. * @@ -93,6 +94,10 @@ EXTERN_C_BEGIN +#if defined(XP_MACOSX) +# pragma pack(push,2) +#endif + /* * If the platform supports the xom.h header file, it should be * included here. @@ -833,6 +838,10 @@ GSS_CALLCONV GSS_FUNC(gss_duplicate_name) ); +#if defined(XP_MACOSX) +# pragma pack(pop) +#endif + EXTERN_C_END #endif /* GSSAPI_H_ */ diff --git a/extensions/auth/nsAuthGSSAPI.cpp b/extensions/auth/nsAuthGSSAPI.cpp index bc99d519e3..0e273a3005 100644 --- a/extensions/auth/nsAuthGSSAPI.cpp +++ b/extensions/auth/nsAuthGSSAPI.cpp @@ -1,3 +1,4 @@ +/* vim:set ts=4 sw=4 sts=4 et cindent: */ /* 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/. */ @@ -24,6 +25,19 @@ #include "nsAuthGSSAPI.h" +#ifdef XP_MACOSX +#include <Kerberos/Kerberos.h> +#endif + +#ifdef XP_MACOSX +typedef KLStatus (*KLCacheHasValidTickets_type)( + KLPrincipal, + KLKerberosVersion, + KLBoolean *, + KLPrincipal *, + char **); +#endif + #if defined(HAVE_RES_NINIT) #include <sys/types.h> #include <netinet/in.h> @@ -77,6 +91,12 @@ static PRLibrary* gssLibrary = nullptr; #define gss_wrap_ptr ((gss_wrap_type)*gssFuncs[8].func) #define gss_unwrap_ptr ((gss_unwrap_type)*gssFuncs[9].func) +#ifdef XP_MACOSX +static PRFuncPtr KLCacheHasValidTicketsPtr; +#define KLCacheHasValidTickets_ptr \ + ((KLCacheHasValidTickets_type)*KLCacheHasValidTicketsPtr) +#endif + static nsresult gssInit() { @@ -192,6 +212,15 @@ gssInit() return NS_ERROR_FAILURE; } } +#ifdef XP_MACOSX + if (gssNativeImp && + !(KLCacheHasValidTicketsPtr = + PR_FindFunctionSymbol(lib, "KLCacheHasValidTickets"))) { + LOG(("Fail to load KLCacheHasValidTickets function from gssapi library\n")); + PR_UnloadLibrary(lib); + return NS_ERROR_FAILURE; + } +#endif gssLibrary = lib; return NS_OK; @@ -412,6 +441,24 @@ nsAuthGSSAPI::GetNextToken(const void *inToken, return NS_ERROR_UNEXPECTED; } +#if defined(XP_MACOSX) + // Suppress Kerberos prompts to get credentials. See bug 240643. + // We can only use Mac OS X specific kerb functions if we are using + // the native lib + KLBoolean found; + bool doingMailTask = mServiceName.Find("imap@") || + mServiceName.Find("pop@") || + mServiceName.Find("smtp@") || + mServiceName.Find("ldap@"); + + if (!doingMailTask && (gssNativeImp && + (KLCacheHasValidTickets_ptr(nullptr, kerberosVersion_V5, &found, nullptr, nullptr) != klNoErr || !found))) + { + major_status = GSS_S_FAILURE; + minor_status = 0; + } + else +#endif /* XP_MACOSX */ major_status = gss_init_sec_context_ptr(&minor_status, GSS_C_NO_CREDENTIAL, &mCtx, diff --git a/image/imgFrame.cpp b/image/imgFrame.cpp index e2be7673b4..9a0846bce2 100644 --- a/image/imgFrame.cpp +++ b/image/imgFrame.cpp @@ -123,12 +123,20 @@ AllowedImageSize(int32_t aWidth, int32_t aHeight) return false; } - // check to make sure we don't overflow 32-bit size for RGBA + // check to make sure we don't overflow a 32-bit CheckedInt32 requiredBytes = CheckedInt32(aWidth) * CheckedInt32(aHeight) * 4; if (MOZ_UNLIKELY(!requiredBytes.isValid())) { NS_WARNING("width or height too large"); return false; } +#if defined(XP_MACOSX) + // CoreGraphics is limited to images < 32K in *height*, so clamp all surfaces + // on the Mac to that height + if (MOZ_UNLIKELY(aHeight > SHRT_MAX)) { + NS_WARNING("image too big"); + return false; + } +#endif return true; } diff --git a/intl/locale/nsIDateTimeFormat.cpp b/intl/locale/nsIDateTimeFormat.cpp index 1290fdc3ee..263b3abb4e 100644 --- a/intl/locale/nsIDateTimeFormat.cpp +++ b/intl/locale/nsIDateTimeFormat.cpp @@ -6,7 +6,9 @@ #include "nsIDateTimeFormat.h" #include "mozilla/RefPtr.h" -#if defined(XP_UNIX) +#if defined(XP_MACOSX) +#define USE_MAC_LOCALE +#elif defined(XP_UNIX) #define USE_UNIX_LOCALE #endif @@ -16,6 +18,9 @@ #ifdef USE_UNIX_LOCALE #include "unix/nsDateTimeFormatUnix.h" #endif +#ifdef USE_MAC_LOCALE +#include "mac/nsDateTimeFormatMac.h" +#endif using mozilla::MakeAndAddRef; diff --git a/intl/locale/nsLocaleConstructors.h b/intl/locale/nsLocaleConstructors.h index 212f70ea53..2d2e579740 100644 --- a/intl/locale/nsLocaleConstructors.h +++ b/intl/locale/nsLocaleConstructors.h @@ -15,7 +15,11 @@ #include "nsLanguageAtomService.h" #include "nsPlatformCharset.h" -#if defined(XP_UNIX) +#if defined(XP_MACOSX) +#define USE_MAC_LOCALE +#endif + +#if defined(XP_UNIX) && !defined(XP_MACOSX) #define USE_UNIX_LOCALE #endif @@ -24,6 +28,11 @@ #include "windows/nsDateTimeFormatWin.h" #endif +#ifdef USE_MAC_LOCALE +#include "mac/nsCollationMacUC.h" +#include "mac/nsDateTimeFormatMac.h" +#endif + #ifdef USE_UNIX_LOCALE #include "unix/nsCollationUnix.h" #include "unix/nsDateTimeFormatUnix.h" diff --git a/intl/locale/nsLocaleService.cpp b/intl/locale/nsLocaleService.cpp index 5984d12274..d81fb50c2e 100644 --- a/intl/locale/nsLocaleService.cpp +++ b/intl/locale/nsLocaleService.cpp @@ -17,6 +17,8 @@ #if defined(XP_WIN) # include "nsWin32Locale.h" +#elif defined(XP_MACOSX) +# include <Carbon/Carbon.h> #elif defined(XP_UNIX) # include <locale.h> # include <stdlib.h> @@ -39,7 +41,7 @@ const char* LocaleList[LocaleListLength] = #define NSILOCALE_MAX_ACCEPT_LANGUAGE 16 #define NSILOCALE_MAX_ACCEPT_LENGTH 18 -#if defined(XP_UNIX) +#if (defined(XP_UNIX) && !defined(XP_MACOSX)) static int posix_locale_category[LocaleListLength] = { LC_COLLATE, @@ -111,7 +113,7 @@ nsLocaleService::nsLocaleService(void) rv = NewLocale(xpLocale, getter_AddRefs(mApplicationLocale)); NS_ENSURE_SUCCESS_VOID(rv); #endif -#if defined(XP_UNIX) +#if defined(XP_UNIX) && !defined(XP_MACOSX) RefPtr<nsLocale> resultLocale(new nsLocale()); NS_ENSURE_TRUE_VOID(resultLocale); @@ -152,7 +154,36 @@ nsLocaleService::nsLocaleService(void) } mSystemLocale = do_QueryInterface(resultLocale); mApplicationLocale = do_QueryInterface(resultLocale); + #endif // XP_UNIX + +#ifdef XP_MACOSX + // Get string representation of user's current locale + CFLocaleRef userLocaleRef = ::CFLocaleCopyCurrent(); + CFStringRef userLocaleStr = ::CFLocaleGetIdentifier(userLocaleRef); + ::CFRetain(userLocaleStr); + + AutoTArray<UniChar, 32> buffer; + int size = ::CFStringGetLength(userLocaleStr); + buffer.SetLength(size + 1); + CFRange range = ::CFRangeMake(0, size); + ::CFStringGetCharacters(userLocaleStr, range, buffer.Elements()); + buffer[size] = 0; + + // Convert the locale string to the format that Mozilla expects + nsAutoString xpLocale(reinterpret_cast<char16_t*>(buffer.Elements())); + xpLocale.ReplaceChar('_', '-'); + + nsresult rv = NewLocale(xpLocale, getter_AddRefs(mSystemLocale)); + if (NS_SUCCEEDED(rv)) { + mApplicationLocale = mSystemLocale; + } + + ::CFRelease(userLocaleStr); + ::CFRelease(userLocaleRef); + + NS_ASSERTION(mApplicationLocale, "Failed to create locale objects"); +#endif // XP_MACOSX } nsLocaleService::~nsLocaleService(void) @@ -175,7 +206,7 @@ nsLocaleService::NewLocale(const nsAString &aLocale, nsILocale **_retval) NS_ConvertASCIItoUTF16 category(LocaleList[i]); result = resultLocale->AddCategory(category, aLocale); if (NS_FAILED(result)) return result; -#if defined(XP_UNIX) +#if defined(XP_UNIX) && !defined(XP_MACOSX) category.AppendLiteral("##PLATFORM"); result = resultLocale->AddCategory(category, aLocale); if (NS_FAILED(result)) return result; diff --git a/ipc/glue/GeckoChildProcessHost.h b/ipc/glue/GeckoChildProcessHost.h index 561c3c6d2d..529fde6f03 100644 --- a/ipc/glue/GeckoChildProcessHost.h +++ b/ipc/glue/GeckoChildProcessHost.h @@ -101,6 +101,12 @@ public: return mProcessType; } +#ifdef XP_MACOSX + task_t GetChildTask() { + return mChildTask; + } +#endif + /** * Must run on the IO thread. Cause the OS process to exit and * ensure its OS resources are cleaned up. diff --git a/js/src/jit/JitOptions.cpp b/js/src/jit/JitOptions.cpp index d14aac1941..daae3d53b5 100644 --- a/js/src/jit/JitOptions.cpp +++ b/js/src/jit/JitOptions.cpp @@ -126,8 +126,12 @@ DefaultJitOptions::DefaultJitOptions() SET_DEFAULT(disableSharedStubs, false); // Toggles whether sincos optimization is globally disabled. - // See bug 984018 as to why this is disabled. - SET_DEFAULT(disableSincos, true); + // See bug984018: The MacOS is the only one that has the sincos fast. + #if defined(XP_MACOSX) + SET_DEFAULT(disableSincos, false); + #else + SET_DEFAULT(disableSincos, true); + #endif // Toggles whether sink code motion is globally disabled. SET_DEFAULT(disableSink, true); diff --git a/js/src/old-configure.in b/js/src/old-configure.in index ec599b676d..e5ec98a8a2 100644 --- a/js/src/old-configure.in +++ b/js/src/old-configure.in @@ -1,4 +1,5 @@ dnl -*- Mode: Autoconf; tab-width: 4; indent-tabs-mode: nil; -*- +dnl vi: set tabstop=4 shiftwidth=4 expandtab syntax=m4: dnl This Source Code Form is subject to the terms of the Mozilla Public dnl License, v. 2.0. If a copy of the MPL was not distributed with this dnl file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -561,6 +562,11 @@ case "$host" in esac ;; +*-darwin*) + HOST_CFLAGS="$HOST_CFLAGS -DXP_UNIX -DXP_MACOSX" + HOST_OPTIMIZE_FLAGS="${HOST_OPTIMIZE_FLAGS=-O3}" + ;; + *-linux*|*-kfreebsd*-gnu|*-gnu*) HOST_CFLAGS="$HOST_CFLAGS -DXP_UNIX" HOST_OPTIMIZE_FLAGS="${HOST_OPTIMIZE_FLAGS=-O3}" diff --git a/js/xpconnect/shell/xpcshell.cpp b/js/xpconnect/shell/xpcshell.cpp index 3460e98a15..35e12449f8 100644 --- a/js/xpconnect/shell/xpcshell.cpp +++ b/js/xpconnect/shell/xpcshell.cpp @@ -10,6 +10,9 @@ #include "mozilla/WindowsDllBlocklist.h" #include "nsXULAppAPI.h" +#ifdef XP_MACOSX +#include "xpcshellMacUtils.h" +#endif #ifdef XP_WIN #include <windows.h> #include <shlobj.h> @@ -34,6 +37,10 @@ main(int argc, char** argv, char** envp) gtk_parse_args(&argc, &argv); #endif +#ifdef XP_MACOSX + InitAutoreleasePool(); +#endif + // unbuffer stdout so that output is in the correct order; note that stderr // is unbuffered by default setbuf(stdout, 0); @@ -44,5 +51,9 @@ main(int argc, char** argv, char** envp) int result = XRE_XPCShellMain(argc, argv, envp); +#ifdef XP_MACOSX + FinishAutoreleasePool(); +#endif + return result; } diff --git a/js/xpconnect/src/Sandbox.cpp b/js/xpconnect/src/Sandbox.cpp index 569da5d56f..6888dee376 100644 --- a/js/xpconnect/src/Sandbox.cpp +++ b/js/xpconnect/src/Sandbox.cpp @@ -127,6 +127,17 @@ SandboxDump(JSContext* cx, unsigned argc, Value* vp) if (!cstr) return false; +#if defined(XP_MACOSX) + // Be nice and convert all \r to \n. + char* c = cstr; + char* cEnd = cstr + strlen(cstr); + while (c < cEnd) { + if (*c == '\r') + *c = '\n'; + c++; + } +#endif + fputs(cstr, stdout); fflush(stdout); args.rval().setBoolean(true); diff --git a/js/xpconnect/src/XPCJSContext.cpp b/js/xpconnect/src/XPCJSContext.cpp index 48a3aa26ac..a02c5e103b 100644 --- a/js/xpconnect/src/XPCJSContext.cpp +++ b/js/xpconnect/src/XPCJSContext.cpp @@ -3209,7 +3209,12 @@ XPCJSContext::Initialize() // the web to base this decision primarily on the default stack size that the // underlying platform makes available, but that seems to be what we do. :-( -#if defined(MOZ_ASAN) +#if defined(XP_MACOSX) || defined(DARWIN) + // MacOS has a gargantuan default stack size of 8MB. Go wild with 7MB, + // and give trusted script 180k extra. The stack is huge on mac anyway. + const size_t kStackQuota = 7 * 1024 * 1024; + const size_t kTrustedScriptBuffer = 180 * 1024; +#elif defined(MOZ_ASAN) // ASan requires more stack space due to red-zones, so give it double the // default (1MB on 32-bit, 2MB on 64-bit). ASAN stack frame measurements // were not taken at the time of this writing, so we hazard a guess that diff --git a/js/xpconnect/src/XPCShellImpl.cpp b/js/xpconnect/src/XPCShellImpl.cpp index 72ab89c402..ba56a4a0ee 100644 --- a/js/xpconnect/src/XPCShellImpl.cpp +++ b/js/xpconnect/src/XPCShellImpl.cpp @@ -1276,6 +1276,22 @@ XRE_XPCShellMain(int argc, char** argv, char** envp) argc -= 2; argv += 2; } else { +#ifdef XP_MACOSX + // On OSX, the GreD needs to point to Contents/Resources in the .app + // bundle. Libraries will be loaded at a relative path to GreD, i.e. + // ../MacOS. + nsCOMPtr<nsIFile> tmpDir; + XRE_GetFileFromPath(argv[0], getter_AddRefs(greDir)); + greDir->GetParent(getter_AddRefs(tmpDir)); + tmpDir->Clone(getter_AddRefs(greDir)); + tmpDir->SetNativeLeafName(NS_LITERAL_CSTRING("Resources")); + bool dirExists = false; + tmpDir->Exists(&dirExists); + if (dirExists) { + greDir = tmpDir.forget(); + } + dirprovider.SetGREDirs(greDir); +#else nsAutoString workingDir; if (!GetCurrentWorkingDirectory(workingDir)) { printf("GetCurrentWorkingDirectory failed.\n"); @@ -1286,6 +1302,7 @@ XRE_XPCShellMain(int argc, char** argv, char** envp) printf("NS_NewLocalFile failed.\n"); return 1; } +#endif } if (argc > 1 && !strcmp(argv[1], "-a")) { @@ -1538,6 +1555,13 @@ XPCShellDirProvider::SetGREDirs(nsIFile* greDir) { mGREDir = greDir; mGREDir->Clone(getter_AddRefs(mGREBinDir)); +#ifdef XP_MACOSX + nsAutoCString leafName; + mGREDir->GetNativeLeafName(leafName); + if (leafName.Equals("Resources")) { + mGREBinDir->SetNativeLeafName(NS_LITERAL_CSTRING("MacOS")); + } +#endif } void diff --git a/mailnews/addrbook/public/nsAbBaseCID.h b/mailnews/addrbook/public/nsAbBaseCID.h index 611300d0ab..0dcc630c50 100644 --- a/mailnews/addrbook/public/nsAbBaseCID.h +++ b/mailnews/addrbook/public/nsAbBaseCID.h @@ -387,6 +387,47 @@ #define NS_ABVIEW_CONTRACTID \ "@mozilla.org/addressbook/abview;1" +#ifdef XP_MACOSX +// +// nsAbOSXDirectory +// +#define NS_ABOSXDIRECTORY_PREFIX "moz-abosxdirectory" +#define NS_ABOSXCARD_PREFIX "moz-abosxcard" + +#define NS_ABOSXDIRECTORY_CONTRACTID \ + NS_AB_DIRECTORY_TYPE_CONTRACTID_PREFIX NS_ABOSXDIRECTORY_PREFIX + +#define NS_ABOSXDIRECTORY_CID \ +{ /* {83781cc6-c682-11d6-bdeb-0005024967b8}*/ \ + 0x83781cc6, 0xc682, 0x11d6, \ + {0xbd, 0xeb, 0x00, 0x05, 0x02, 0x49, 0x67, 0xb8} \ +} + +// +// nsAbOSXCard +// +#define NS_ABOSXCARD_CONTRACTID \ + NS_AB_DIRECTORY_TYPE_CONTRACTID_PREFIX NS_ABOSXCARD_PREFIX + +#define NS_ABOSXCARD_CID \ +{ /* {89bbf582-c682-11d6-bc9d-0005024967b8}*/ \ + 0x89bbf582, 0xc682, 0x11d6, \ + {0xbc, 0x9d, 0x00, 0x05, 0x02, 0x49, 0x67, 0xb8} \ +} + +// +// OS X directory factory +// +#define NS_ABOSXDIRFACTORY_CONTRACTID \ + NS_AB_DIRECTORY_FACTORY_CONTRACTID_PREFIX NS_ABOSXDIRECTORY_PREFIX + +#define NS_ABOSXDIRFACTORY_CID \ +{ /* {90efe2fe-c682-11d6-9c83-0005024967b8}*/ \ + 0x90efe2fe, 0xc682, 0x11d6, \ + {0x9c, 0x83, 0x00, 0x05, 0x02, 0x49, 0x67, 0xb8} \ +} +#endif + #define NS_MSGVCARDSERVICE_CID \ { 0x3c4ac0da, 0x2cda, 0x4018, \ { 0x95, 0x51, 0xe1, 0x58, 0xb2, 0xe1, 0x22, 0xd3 }} diff --git a/mailnews/base/prefs/content/AccountWizard.xul b/mailnews/base/prefs/content/AccountWizard.xul index 9d825084b2..2aee2e3a5d 100644 --- a/mailnews/base/prefs/content/AccountWizard.xul +++ b/mailnews/base/prefs/content/AccountWizard.xul @@ -343,7 +343,11 @@ checked="true"/> </hbox> <spacer flex="1"/> +#ifndef XP_MACOSX <description>&clickFinish.label;</description> +#else + <description>&clickFinish.labelMac;</description> +#endif </vbox> </wizardpage> diff --git a/mailnews/base/search/src/nsMsgFilter.cpp b/mailnews/base/search/src/nsMsgFilter.cpp index d7e9ac9408..e94240f299 100644 --- a/mailnews/base/search/src/nsMsgFilter.cpp +++ b/mailnews/base/search/src/nsMsgFilter.cpp @@ -822,6 +822,11 @@ nsresult nsMsgFilter::ConvertMoveOrCopyToFolderValue(nsIMsgRuleAction *filterAct if (offset != -1) moveValue.Cut(offset, 4); +#ifdef XP_MACOSX + nsCString unescapedMoveValue; + MsgUnescapeString(moveValue, 0, unescapedMoveValue); + moveValue = unescapedMoveValue; +#endif destFolderUri.Append('/'); if (filterVersion == k45Version) { diff --git a/mailnews/base/src/nsMessenger.cpp b/mailnews/base/src/nsMessenger.cpp index 8719530f79..953b462b6a 100644 --- a/mailnews/base/src/nsMessenger.cpp +++ b/mailnews/base/src/nsMessenger.cpp @@ -698,6 +698,7 @@ nsresult nsMessenger::SaveAttachment(nsIFile *aFile, saveListener->QueryInterface(NS_GET_IID(nsIStreamListener), getter_AddRefs(convertedListener)); +#ifndef XP_MACOSX // if the content type is bin hex we are going to do a hokey hack and make sure we decode the bin hex // when saving an attachment to disk.. if (MsgLowerCaseEqualsLiteral(aContentType, APPLICATION_BINHEX)) @@ -712,6 +713,7 @@ nsresult nsMessenger::SaveAttachment(nsIFile *aFile, channelSupport, getter_AddRefs(convertedListener)); } +#endif nsCOMPtr<nsIURI> dummyNull; if (fetchService) rv = fetchService->FetchMimePart(URL, fullMessageUri.get(), @@ -769,6 +771,10 @@ nsMessenger::SaveAttachmentToFolder(const nsACString& contentType, const nsACStr ConvertAndSanitizeFileName(PromiseFlatCString(displayName).get(), unescapedFileName); rv = attachmentDestination->Append(unescapedFileName); NS_ENSURE_SUCCESS(rv, rv); +#ifdef XP_MACOSX + rv = attachmentDestination->CreateUnique(nsIFile::NORMAL_FILE_TYPE, ATTACHMENT_PERMISSION); + NS_ENSURE_SUCCESS(rv, rv); +#endif rv = SaveAttachment(attachmentDestination, url, messageUri, contentType, nullptr, nullptr); attachmentDestination.swap(*aOutFile); diff --git a/mailnews/base/src/nsMsgMailSession.cpp b/mailnews/base/src/nsMsgMailSession.cpp index 20d6f045c3..f9e396988c 100644 --- a/mailnews/base/src/nsMsgMailSession.cpp +++ b/mailnews/base/src/nsMsgMailSession.cpp @@ -353,9 +353,11 @@ NS_IMETHODIMP nsMsgMailSession::AddMsgWindow(nsIMsgWindow *msgWindow) NS_IMETHODIMP nsMsgMailSession::RemoveMsgWindow(nsIMsgWindow *msgWindow) { mWindows.RemoveObject(msgWindow); - // For suite, we don't want to disable mailnews when the last mail window - // is closed (other component windows may still be open). -#if !defined(MOZ_SUITE) + // Mac keeps a hidden window open so the app doesn't shut down when + // the last window is closed. So don't shutdown the account manager in that + // case. Similarly, for suite, we don't want to disable mailnews when the + // last mail window is closed. +#if !defined(XP_MACOSX) && !defined(MOZ_SUITE) if (!mWindows.Count()) { nsresult rv; diff --git a/mailnews/base/src/nsStatusBarBiffManager.cpp b/mailnews/base/src/nsStatusBarBiffManager.cpp index 08dfb7b76e..27f393986d 100644 --- a/mailnews/base/src/nsStatusBarBiffManager.cpp +++ b/mailnews/base/src/nsStatusBarBiffManager.cpp @@ -136,11 +136,13 @@ nsresult nsStatusBarBiffManager::PlayBiffSound(const char *aPrefBranch) } } } +#ifndef XP_MACOSX // if nothing played, play the default system sound if (!customSoundPlayed) { rv = mSound->PlayEventSound(nsISound::EVENT_NEW_MAIL_RECEIVED); NS_ENSURE_SUCCESS(rv, rv); } +#endif return rv; } diff --git a/mailnews/base/util/nsMsgUtils.cpp b/mailnews/base/util/nsMsgUtils.cpp index 6fc884d510..44609bea00 100644 --- a/mailnews/base/util/nsMsgUtils.cpp +++ b/mailnews/base/util/nsMsgUtils.cpp @@ -611,7 +611,7 @@ nsresult NS_MsgCreatePathStringFromFolderURI(const char *aFolderURI, ? oldPath.FindChar('/', startSlashPos + 1) - 1 : oldPath.Length() - 1; if (endSlashPos < 0) endSlashPos = oldPath.Length(); -#if defined(XP_UNIX) +#if defined(XP_UNIX) || defined(XP_MACOSX) bool isLocalUri = aScheme.EqualsLiteral("none") || aScheme.EqualsLiteral("pop3") || aScheme.EqualsLiteral("rss"); @@ -636,7 +636,7 @@ nsresult NS_MsgCreatePathStringFromFolderURI(const char *aFolderURI, CopyUTF16toMUTF7(pathPiece, tmp); CopyASCIItoUTF16(tmp, pathPiece); } -#if defined(XP_UNIX) +#if defined(XP_UNIX) || defined(XP_MACOSX) // Don't hash path pieces because local mail folder uri's have already // been hashed. We're only doing this on the mac to limit potential // regressions. diff --git a/mailnews/build/nsMailModule.cpp b/mailnews/build/nsMailModule.cpp index dea26047a0..5b86b4c3ef 100644 --- a/mailnews/build/nsMailModule.cpp +++ b/mailnews/build/nsMailModule.cpp @@ -102,6 +102,9 @@ #ifdef XP_WIN #include "nsMessengerWinIntegration.h" #endif +#ifdef XP_MACOSX +#include "nsMessengerOSXIntegration.h" +#endif #if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_GTK2) #include "nsMessengerUnixIntegration.h" #endif @@ -154,6 +157,12 @@ #include "nsAbOutlookDirectory.h" #endif +#ifdef XP_MACOSX +#include "nsAbOSXDirectory.h" +#include "nsAbOSXCard.h" +#include "nsAbOSXDirFactory.h" +#endif + //////////////////////////////////////////////////////////////////////////////// // bayesian spam filter includes //////////////////////////////////////////////////////////////////////////////// @@ -370,6 +379,9 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsMsgShutdownService) #ifdef XP_WIN NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsMessengerWinIntegration, Init) #endif +#ifdef XP_MACOSX +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsMessengerOSXIntegration, Init) +#endif #if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_GTK2) NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsMessengerUnixIntegration, Init) #endif @@ -427,6 +439,9 @@ NS_DEFINE_NAMED_CID(NS_MSGNOTIFICATIONSERVICE_CID); #ifdef XP_WIN NS_DEFINE_NAMED_CID(NS_MESSENGERWININTEGRATION_CID); #endif +#ifdef XP_MACOSX +NS_DEFINE_NAMED_CID(NS_MESSENGEROSXINTEGRATION_CID); +#endif #if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_GTK2) NS_DEFINE_NAMED_CID(NS_MESSENGERUNIXINTEGRATION_CID); #endif @@ -484,6 +499,12 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsAbView) NS_GENERIC_FACTORY_CONSTRUCTOR(nsMsgVCardService) NS_GENERIC_FACTORY_CONSTRUCTOR(nsAbLDIFService) +#ifdef XP_MACOSX +NS_GENERIC_FACTORY_CONSTRUCTOR(nsAbOSXDirectory) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsAbOSXCard) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsAbOSXDirFactory) +#endif + NS_DEFINE_NAMED_CID(NS_ABMANAGER_CID); NS_DEFINE_NAMED_CID(NS_ABDIRECTORY_CID); NS_DEFINE_NAMED_CID(NS_ABMDBDIRECTORY_CID); @@ -515,6 +536,11 @@ NS_DEFINE_NAMED_CID(NS_ABLDAP_REPLICATIONQUERY_CID); NS_DEFINE_NAMED_CID(NS_ABLDAP_PROCESSREPLICATIONDATA_CID); #endif NS_DEFINE_NAMED_CID(NS_ABDIRECTORYQUERYPROXY_CID); +#ifdef XP_MACOSX +NS_DEFINE_NAMED_CID(NS_ABOSXDIRECTORY_CID); +NS_DEFINE_NAMED_CID(NS_ABOSXCARD_CID); +NS_DEFINE_NAMED_CID(NS_ABOSXDIRFACTORY_CID); +#endif NS_DEFINE_NAMED_CID(NS_ABVIEW_CID); NS_DEFINE_NAMED_CID(NS_MSGVCARDSERVICE_CID); NS_DEFINE_NAMED_CID(NS_ABLDIFSERVICE_CID); @@ -897,6 +923,9 @@ const mozilla::Module::CIDEntry kMailNewsCIDs[] = { #ifdef XP_WIN { &kNS_MESSENGERWININTEGRATION_CID, false, NULL, nsMessengerWinIntegrationConstructor}, #endif +#ifdef XP_MACOSX + { &kNS_MESSENGEROSXINTEGRATION_CID, false, NULL, nsMessengerOSXIntegrationConstructor}, +#endif #if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_GTK2) { &kNS_MESSENGERUNIXINTEGRATION_CID, false, NULL, nsMessengerUnixIntegrationConstructor}, #endif @@ -939,6 +968,11 @@ const mozilla::Module::CIDEntry kMailNewsCIDs[] = { { &kNS_ABLDAPDIRFACTORY_CID, false, NULL, nsAbLDAPDirFactoryConstructor }, #endif { &kNS_ABDIRECTORYQUERYPROXY_CID, false, NULL, nsAbDirectoryQueryProxyConstructor }, +#ifdef XP_MACOSX + { &kNS_ABOSXDIRECTORY_CID, false, NULL, nsAbOSXDirectoryConstructor }, + { &kNS_ABOSXCARD_CID, false, NULL, nsAbOSXCardConstructor }, + { &kNS_ABOSXDIRFACTORY_CID, false, NULL, nsAbOSXDirFactoryConstructor }, +#endif { &kNS_ABVIEW_CID, false, NULL, nsAbViewConstructor }, { &kNS_MSGVCARDSERVICE_CID, false, NULL, nsMsgVCardServiceConstructor }, { &kNS_ABLDIFSERVICE_CID, false, NULL, nsAbLDIFServiceConstructor }, @@ -1107,6 +1141,9 @@ const mozilla::Module::ContractIDEntry kMailNewsContracts[] = { #ifdef XP_WIN { NS_MESSENGEROSINTEGRATION_CONTRACTID, &kNS_MESSENGERWININTEGRATION_CID }, #endif +#ifdef XP_MACOSX + { NS_MESSENGEROSINTEGRATION_CONTRACTID, &kNS_MESSENGEROSXINTEGRATION_CID }, +#endif #if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_GTK2) { NS_MESSENGEROSINTEGRATION_CONTRACTID, &kNS_MESSENGERUNIXINTEGRATION_CID }, #endif @@ -1153,6 +1190,11 @@ const mozilla::Module::ContractIDEntry kMailNewsContracts[] = { #endif { NS_ABDIRECTORYQUERYPROXY_CONTRACTID, &kNS_ABDIRECTORYQUERYPROXY_CID }, +#ifdef XP_MACOSX + { NS_ABOSXDIRECTORY_CONTRACTID, &kNS_ABOSXDIRECTORY_CID }, + { NS_ABOSXCARD_CONTRACTID, &kNS_ABOSXCARD_CID }, + { NS_ABOSXDIRFACTORY_CONTRACTID, &kNS_ABOSXDIRFACTORY_CID }, +#endif { NS_ABVIEW_CONTRACTID, &kNS_ABVIEW_CID }, { NS_MSGVCARDSERVICE_CONTRACTID, &kNS_MSGVCARDSERVICE_CID }, { NS_ABLDIFSERVICE_CONTRACTID, &kNS_ABLDIFSERVICE_CID }, @@ -1301,6 +1343,10 @@ static const mozilla::Module::CategoryEntry kMailNewsCategories[] = { { XPCOM_DIRECTORY_PROVIDER_CATEGORY, "mail-directory-provider", NS_MAILDIRPROVIDER_CONTRACTID }, { "content-policy", NS_MSGCONTENTPOLICY_CONTRACTID, NS_MSGCONTENTPOLICY_CONTRACTID }, MAILNEWSDLF_CATEGORIES +#ifdef XP_MACOSX + { "app-startup", NS_MESSENGEROSINTEGRATION_CONTRACTID, "service," NS_MESSENGEROSINTEGRATION_CONTRACTID} +, +#endif // Address Book Entries { "command-line-handler", "m-addressbook", NS_ABMANAGERSTARTUPHANDLER_CONTRACTID }, // Bayesian Filter Entries diff --git a/mailnews/compose/src/nsMsgAttachmentHandler.cpp b/mailnews/compose/src/nsMsgAttachmentHandler.cpp index 3c7e08bc13..4994c3fe69 100644 --- a/mailnews/compose/src/nsMsgAttachmentHandler.cpp +++ b/mailnews/compose/src/nsMsgAttachmentHandler.cpp @@ -36,6 +36,77 @@ #include "mozilla/mailnews/MimeEncoder.h" #include "nsIPrincipal.h" +/////////////////////////////////////////////////////////////////////////// +// Mac Specific Attachment Handling for AppleDouble Encoded Files +/////////////////////////////////////////////////////////////////////////// +#ifdef XP_MACOSX + +#define AD_WORKING_BUFF_SIZE FILE_IO_BUFFER_SIZE + +extern void MacGetFileType(nsIFile *fs, bool *useDefault, char **type, char **encoding); + +#include "nsILocalFileMac.h" + +/* static */ +nsresult nsSimpleZipper::Zip(nsIFile *aInputFile, nsIFile *aOutputFile) +{ + // create zipwriter object + nsresult rv; + nsCOMPtr<nsIZipWriter> zipWriter = do_CreateInstance("@mozilla.org/zipwriter;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + rv = zipWriter->Open(aOutputFile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE); + NS_ENSURE_SUCCESS(rv, rv); + + rv = AddToZip(zipWriter, aInputFile, EmptyCString()); + NS_ENSURE_SUCCESS(rv, rv); + + // we're done. + zipWriter->Close(); + return rv; +} + +/* static */ +nsresult nsSimpleZipper::AddToZip(nsIZipWriter *aZipWriter, + nsIFile *aFile, + const nsACString &aPath) +{ + // find out the path this file/dir should have in the zip + nsCString leafName; + aFile->GetNativeLeafName(leafName); + nsCString currentPath(aPath); + currentPath += leafName; + + bool isDirectory; + aFile->IsDirectory(&isDirectory); + // append slash for a directory entry + if (isDirectory) + currentPath.Append('/'); + + // add the file or directory entry to the zip + nsresult rv = aZipWriter->AddEntryFile(currentPath, nsIZipWriter::COMPRESSION_DEFAULT, aFile, false); + NS_ENSURE_SUCCESS(rv, rv); + + // if it's a directory, add all its contents too + if (isDirectory) { + nsCOMPtr<nsISimpleEnumerator> e; + nsresult rv = aFile->GetDirectoryEntries(getter_AddRefs(e)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIDirectoryEnumerator> dirEnumerator = do_QueryInterface(e, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIFile> currentFile; + while (NS_SUCCEEDED(dirEnumerator->GetNextFile(getter_AddRefs(currentFile))) && currentFile) { + rv = AddToZip(aZipWriter, currentFile, currentPath); + NS_ENSURE_SUCCESS(rv, rv); + } + } + + return NS_OK; +} +#endif // XP_MACOSX + // // Class implementation... // @@ -168,7 +239,12 @@ NS_IMETHODIMP nsMsgAttachmentHandler::GetAlreadyEncoded(bool* aAlreadyEncoded) void nsMsgAttachmentHandler::CleanupTempFile() { -/** Mac Stub **/ +#ifdef XP_MACOSX + if (mEncodedWorkingFile) { + mEncodedWorkingFile->Remove(false); + mEncodedWorkingFile = nullptr; + } +#endif // XP_MACOSX } void @@ -473,8 +549,13 @@ FetcherURLDoneCallback(nsresult aStatus, ma->m_size = totalSize; if (!aContentType.IsEmpty()) { - // can't send appledouble on non-macs +#ifdef XP_MACOSX + //Do not change the type if we are dealing with an encoded (e.g., appledouble or zip) file + if (!ma->mEncodedWorkingFile) +#else + // can't send appledouble on non-macs if (!aContentType.EqualsLiteral("multipart/appledouble")) +#endif ma->m_type = aContentType; } @@ -617,6 +698,15 @@ done: return rv; } +#ifdef XP_MACOSX +bool nsMsgAttachmentHandler::HasResourceFork(FSRef *fsRef) +{ + FSCatalogInfo catalogInfo; + OSErr err = FSGetCatalogInfo(fsRef, kFSCatInfoDataSizes + kFSCatInfoRsrcSizes, &catalogInfo, nullptr, nullptr, nullptr); + return (err == noErr && catalogInfo.rsrcLogicalSize != 0); +} +#endif + nsresult nsMsgAttachmentHandler::SnarfAttachment(nsMsgCompFields *compFields) { @@ -657,6 +747,33 @@ nsMsgAttachmentHandler::SnarfAttachment(nsMsgCompFields *compFields) nsCString sourceURISpec; rv = mURL->GetSpec(sourceURISpec); NS_ENSURE_SUCCESS(rv, rv); +#ifdef XP_MACOSX + if (!m_bogus_attachment && StringBeginsWith(sourceURISpec, NS_LITERAL_CSTRING("file://"))) + { + // Unescape the path (i.e. un-URLify it) before making a FSSpec + nsAutoCString filePath; + filePath.Adopt(nsMsgGetLocalFileFromURL(sourceURISpec.get())); + nsAutoCString unescapedFilePath; + MsgUnescapeString(filePath, 0, unescapedFilePath); + + nsCOMPtr<nsIFile> sourceFile; + NS_NewNativeLocalFile(unescapedFilePath, true, getter_AddRefs(sourceFile)); + if (!sourceFile) + return NS_ERROR_FAILURE; + + // check if it is a bundle. if it is, we'll zip it. + // if not, we'll apple encode it (applesingle or appledouble) + nsCOMPtr<nsILocalFileMac> macFile(do_QueryInterface(sourceFile)); + bool isPackage; + macFile->IsPackage(&isPackage); + if (isPackage) + rv = ConvertToZipFile(macFile); + else + rv = ConvertToAppleEncoding(sourceURISpec, unescapedFilePath, macFile); + + NS_ENSURE_SUCCESS(rv, rv); + } +#endif /* XP_MACOSX */ // // Ok, here we are, we need to fire the URL off and get the data @@ -676,6 +793,236 @@ nsMsgAttachmentHandler::SnarfAttachment(nsMsgCompFields *compFields) return fetcher->FireURLRequest(mURL, mTmpFile, mOutFile, FetcherURLDoneCallback, this); } +#ifdef XP_MACOSX +nsresult +nsMsgAttachmentHandler::ConvertToZipFile(nsILocalFileMac *aSourceFile) +{ + // append ".zip" to the real file name + nsAutoCString zippedName; + nsresult rv = aSourceFile->GetNativeLeafName(zippedName); + NS_ENSURE_SUCCESS(rv, rv); + zippedName.AppendLiteral(".zip"); + + // create a temporary file that we'll work on + nsCOMPtr <nsIFile> tmpFile; + rv = nsMsgCreateTempFile(zippedName.get(), getter_AddRefs(tmpFile)); + NS_ENSURE_SUCCESS(rv, rv); + mEncodedWorkingFile = do_QueryInterface(tmpFile); + + // point our URL at the zipped temp file + NS_NewFileURI(getter_AddRefs(mURL), mEncodedWorkingFile); + + // zip it! + rv = nsSimpleZipper::Zip(aSourceFile, mEncodedWorkingFile); + NS_ENSURE_SUCCESS(rv, rv); + + // set some metadata for this attachment, that will affect the MIME headers. + m_type = APPLICATION_ZIP; + m_realName = zippedName.get(); + + return NS_OK; +} + +nsresult +nsMsgAttachmentHandler::ConvertToAppleEncoding(const nsCString &aFileURI, + const nsCString &aFilePath, + nsILocalFileMac *aSourceFile) +{ + // convert the apple file to AppleDouble first, and then patch the + // address in the url. + + //We need to retrieve the file type and creator... + + char fileInfo[32]; + OSType type, creator; + + nsresult rv = aSourceFile->GetFileType(&type); + if (NS_FAILED(rv)) + return rv; + PR_snprintf(fileInfo, sizeof(fileInfo), "%X", type); + m_xMacType = fileInfo; + + rv = aSourceFile->GetFileCreator(&creator); + if (NS_FAILED(rv)) + return rv; + PR_snprintf(fileInfo, sizeof(fileInfo), "%X", creator); + m_xMacCreator = fileInfo; + + FSRef fsRef; + aSourceFile->GetFSRef(&fsRef); + bool sendResourceFork = HasResourceFork(&fsRef); + + // if we have a resource fork, check the filename extension, maybe we don't need the resource fork! + if (sendResourceFork) + { + nsCOMPtr<nsIURL> fileUrl(do_CreateInstance(NS_STANDARDURL_CONTRACTID)); + if (fileUrl) + { + rv = fileUrl->SetSpec(aFileURI); + if (NS_SUCCEEDED(rv)) + { + nsAutoCString ext; + rv = fileUrl->GetFileExtension(ext); + if (NS_SUCCEEDED(rv) && !ext.IsEmpty()) + { + sendResourceFork = + PL_strcasecmp(ext.get(), "TXT") && + PL_strcasecmp(ext.get(), "JPG") && + PL_strcasecmp(ext.get(), "GIF") && + PL_strcasecmp(ext.get(), "TIF") && + PL_strcasecmp(ext.get(), "HTM") && + PL_strcasecmp(ext.get(), "HTML") && + PL_strcasecmp(ext.get(), "ART") && + PL_strcasecmp(ext.get(), "XUL") && + PL_strcasecmp(ext.get(), "XML") && + PL_strcasecmp(ext.get(), "CSS") && + PL_strcasecmp(ext.get(), "JS"); + } + } + } + } + + // Only use appledouble if we aren't uuencoding. + if( sendResourceFork ) + { + char *separator; + + separator = mime_make_separator("ad"); + if (!separator) + return NS_ERROR_OUT_OF_MEMORY; + + nsCOMPtr <nsIFile> tmpFile; + nsresult rv = nsMsgCreateTempFile("appledouble", getter_AddRefs(tmpFile)); + if (NS_SUCCEEDED(rv)) + mEncodedWorkingFile = do_QueryInterface(tmpFile); + if (!mEncodedWorkingFile) + { + PR_FREEIF(separator); + return NS_ERROR_OUT_OF_MEMORY; + } + + // + // RICHIE_MAC - ok, here's the deal, we have a file that we need + // to encode in appledouble encoding for the resource fork and put that + // into the mEncodedWorkingFile location. Then, we need to patch the new file + // spec into the array and send this as part of the 2 part appledouble/mime + // encoded mime part. + // + AppleDoubleEncodeObject *obj = new (AppleDoubleEncodeObject); + if (obj == NULL) + { + mEncodedWorkingFile = nullptr; + PR_FREEIF(separator); + return NS_ERROR_OUT_OF_MEMORY; + } + + rv = MsgGetFileStream(mEncodedWorkingFile, getter_AddRefs(obj->fileStream)); + if (NS_FAILED(rv) || !obj->fileStream) + { + PR_FREEIF(separator); + delete obj; + return NS_ERROR_OUT_OF_MEMORY; + } + + char *working_buff = (char *) PR_Malloc(AD_WORKING_BUFF_SIZE); + if (!working_buff) + { + PR_FREEIF(separator); + delete obj; + return NS_ERROR_OUT_OF_MEMORY; + } + + obj->buff = working_buff; + obj->s_buff = AD_WORKING_BUFF_SIZE; + + // + // Setup all the need information on the apple double encoder. + // + ap_encode_init(&(obj->ap_encode_obj), aFilePath.get(), separator); + + int32_t count; + + OSErr status = noErr; + m_size = 0; + while (status == noErr) + { + status = ap_encode_next(&(obj->ap_encode_obj), obj->buff, obj->s_buff, &count); + if (status == noErr || status == errDone) + { + // + // we got the encode data, so call the next stream to write it to the disk. + // + uint32_t bytesWritten; + obj->fileStream->Write(obj->buff, count, &bytesWritten); + if (bytesWritten != (uint32_t) count) + status = errFileWrite; + } + } + + ap_encode_end(&(obj->ap_encode_obj), (status >= 0)); // if this is true, ok, false abort + if (obj->fileStream) + obj->fileStream->Close(); + + PR_FREEIF(obj->buff); /* free the working buff. */ + PR_FREEIF(obj); + + nsCOMPtr <nsIURI> fileURI; + NS_NewFileURI(getter_AddRefs(fileURI), mEncodedWorkingFile); + + nsCOMPtr<nsIFileURL> theFileURL = do_QueryInterface(fileURI, &rv); + NS_ENSURE_SUCCESS(rv,rv); + + nsCString newURLSpec; + rv = fileURI->GetSpec(newURLSpec); + NS_ENSURE_SUCCESS(rv, rv); + + if (newURLSpec.IsEmpty()) + { + PR_FREEIF(separator); + return NS_ERROR_OUT_OF_MEMORY; + } + + if (NS_FAILED(nsMsgNewURL(getter_AddRefs(mURL), newURLSpec.get()))) + { + PR_FREEIF(separator); + return NS_ERROR_OUT_OF_MEMORY; + } + + // Now after conversion, also patch the types. + char tmp[128]; + PR_snprintf(tmp, sizeof(tmp), MULTIPART_APPLEDOUBLE ";\r\n boundary=\"%s\"", separator); + PR_FREEIF(separator); + m_type = tmp; + } + else + { + if ( sendResourceFork ) + { + // For now, just do the encoding, but in the old world we would ask the + // user about doing this conversion + printf("...we could ask the user about this conversion, but for now, nahh..\n"); + } + + bool useDefault; + char *macType, *macEncoding; + if (m_type.IsEmpty() || m_type.LowerCaseEqualsLiteral(TEXT_PLAIN)) + { +# define TEXT_TYPE 0x54455854 /* the characters 'T' 'E' 'X' 'T' */ +# define text_TYPE 0x74657874 /* the characters 't' 'e' 'x' 't' */ + + if (type != TEXT_TYPE && type != text_TYPE) + { + MacGetFileType(aSourceFile, &useDefault, &macType, &macEncoding); + m_type = macType; + } + } + // don't bother to set the types if we failed in getting the file info. + } + + return NS_OK; +} +#endif // XP_MACOSX + nsresult nsMsgAttachmentHandler::LoadDataFromFile(nsIFile *file, nsString &sigData, bool charsetConversion) { diff --git a/mailnews/compose/src/nsMsgAttachmentHandler.h b/mailnews/compose/src/nsMsgAttachmentHandler.h index 67ac474abd..2034cba032 100644 --- a/mailnews/compose/src/nsMsgAttachmentHandler.h +++ b/mailnews/compose/src/nsMsgAttachmentHandler.h @@ -16,6 +16,42 @@ #include "nsAutoPtr.h" #include "nsIMsgAttachmentHandler.h" +#ifdef XP_MACOSX + +#include "nsMsgAppleDouble.h" +#include "nsILocalFileMac.h" + +class AppleDoubleEncodeObject +{ +public: + appledouble_encode_object ap_encode_obj; + char *buff; // the working buff + int32_t s_buff; // the working buff size + nsCOMPtr <nsIOutputStream> fileStream; // file to hold the encoding +}; + +class nsILocalFileMac; +class nsIZipWriter; + +/* Simple utility class that will synchronously zip any file + (or folder hierarchy) you give it. */ +class nsSimpleZipper +{ + public: + + // Synchronously zips the input file/folder and writes all + // data to the output file. + static nsresult Zip(nsIFile *aInputFile, nsIFile *aOutputFile); + + private: + + // Recursively adds the file or folder to aZipWriter. + static nsresult AddToZip(nsIZipWriter *aZipWriter, + nsIFile *aFile, + const nsACString &aPath); +}; +#endif // XP_MACOSX + namespace mozilla { namespace mailnews { class MimeEncoder; @@ -59,6 +95,14 @@ private: bool UseUUEncode_p(void); void AnalyzeDataChunk (const char *chunk, int32_t chunkSize); nsresult LoadDataFromFile(nsIFile *file, nsString &sigData, bool charsetConversion); //A similar function already exist in nsMsgCompose! +#ifdef XP_MACOSX + nsresult ConvertToAppleEncoding(const nsCString &aFileSpecURI, + const nsCString &aFilePath, + nsILocalFileMac *aSourceFile); + // zips this attachment and does the work to make this attachment handler handle it properly. + nsresult ConvertToZipFile(nsILocalFileMac *aSourceFile); + bool HasResourceFork(FSRef *fsRef); +#endif // public: @@ -69,6 +113,12 @@ public: nsMsgCompFields *mCompFields; // Message composition fields for the sender bool m_bogus_attachment; // This is to catch problem children... +#ifdef XP_MACOSX + // if we need to encode this file into for example an appledouble, or zip file, + // this file is our working file. currently only needed on mac. + nsCOMPtr<nsIFile> mEncodedWorkingFile; +#endif + nsCString m_xMacType; // Mac file type nsCString m_xMacCreator; // Mac file creator diff --git a/mailnews/compose/src/nsMsgSend.cpp b/mailnews/compose/src/nsMsgSend.cpp index e328a9e21d..919d9bfc54 100644 --- a/mailnews/compose/src/nsMsgSend.cpp +++ b/mailnews/compose/src/nsMsgSend.cpp @@ -2088,7 +2088,9 @@ nsMsgComposeAndSend::AddCompFieldLocalAttachments() if (NS_SUCCEEDED(rv) && !fileExt.IsEmpty()) { nsAutoCString type; mimeFinder->GetTypeFromExtension(fileExt, type); + #ifndef XP_MACOSX if (!type.Equals("multipart/appledouble")) // can't do apple double on non-macs + #endif m_attachments[newLoc]->m_type = type; } } @@ -2103,7 +2105,9 @@ nsMsgComposeAndSend::AddCompFieldLocalAttachments() if (NS_SUCCEEDED(rv) && !fileExt.IsEmpty()) { nsAutoCString type; mimeFinder->GetTypeFromExtension(fileExt, type); + #ifndef XP_MACOSX if (!type.Equals("multipart/appledouble")) // can't do apple double on non-macs + #endif m_attachments[newLoc]->m_type = type; // rtf and vcs files may look like text to sniffers, // but they're not human readable. diff --git a/mailnews/imap/src/nsIMAPBodyShell.cpp b/mailnews/imap/src/nsIMAPBodyShell.cpp index b81978cc7b..087fe20337 100644 --- a/mailnews/imap/src/nsIMAPBodyShell.cpp +++ b/mailnews/imap/src/nsIMAPBodyShell.cpp @@ -724,8 +724,27 @@ bool nsIMAPBodypartLeaf::ShouldFetchInline(nsIMAPBodyShell *aShell) return false; // we can leave it on the server } +#ifdef XP_MACOSX + // If it is either applesingle, or a resource fork for appledouble + if (!PL_strcasecmp(m_contentType, "application/applefile")) + { + // if it is appledouble + if (m_parentPart->GetType() == IMAP_BODY_MULTIPART && + !PL_strcasecmp(m_parentPart->GetBodySubType(), "appledouble")) + { + // This is the resource fork of a multipart/appledouble. + // We inherit the inline attributes of the parent, + // which was derived from its OTHER child. (The data fork.) + return m_parentPart->ShouldFetchInline(aShell); + } + else // it is applesingle + { + return false; // we can leave it on the server + } + } +#endif // XP_MACOSX - // Leave out parts with type application/(*) + // Leave out parts with type application/* if (!PL_strcasecmp(m_bodyType, "APPLICATION") && // If it is of type "application" PL_strncasecmp(m_bodySubType, "x-pkcs7", 7) // and it's not a signature (signatures are inline) ) diff --git a/mailnews/import/applemail/src/moz.build b/mailnews/import/applemail/src/moz.build new file mode 100644 index 0000000000..fafbebc990 --- /dev/null +++ b/mailnews/import/applemail/src/moz.build @@ -0,0 +1,14 @@ +# 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/. + +SOURCES += [ + 'nsAppleMailImport.cpp', +] + +SOURCES += [ + 'nsEmlxHelperUtils.mm', +] + +FINAL_LIBRARY = 'import' + diff --git a/mailnews/import/applemail/src/nsAppleMailImport.cpp b/mailnews/import/applemail/src/nsAppleMailImport.cpp new file mode 100644 index 0000000000..3097b7df5e --- /dev/null +++ b/mailnews/import/applemail/src/nsAppleMailImport.cpp @@ -0,0 +1,623 @@ +/* -*- 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 "nsStringGlue.h" +#include "nsCOMPtr.h" +#include "nsISupportsPrimitives.h" +#include "nsIImportService.h" +#include "nsIImportMailboxDescriptor.h" +#include "nsIImportGeneric.h" +#include "nsIFile.h" +#include "nsIStringBundle.h" +#include "nsIMsgFolder.h" +#include "nsIMsgHdr.h" +#include "nsIMsgPluggableStore.h" +#include "nsIMutableArray.h" +#include "nsNetUtil.h" +#include "nsMsgUtils.h" +#include "mozilla/Services.h" + +#include "nsEmlxHelperUtils.h" +#include "nsAppleMailImport.h" +#include "nsIOutputStream.h" + +PRLogModuleInfo *APPLEMAILLOGMODULE = nullptr; + +// some hard-coded strings +#define DEFAULT_MAIL_FOLDER "~/Library/Mail/" +#define POP_MBOX_SUFFIX ".mbox" +#define IMAP_MBOX_SUFFIX ".imapmbox" + +// stringbundle URI +#define APPLEMAIL_MSGS_URL "chrome://messenger/locale/appleMailImportMsgs.properties" + +// magic constants +#define kAccountMailboxID 1234 + +nsAppleMailImportModule::nsAppleMailImportModule() +{ + // Init logging module. + if (!APPLEMAILLOGMODULE) + APPLEMAILLOGMODULE = PR_NewLogModule("APPLEMAILIMPORTLOG"); + + IMPORT_LOG0("nsAppleMailImportModule Created"); + + nsCOMPtr<nsIStringBundleService> bundleService = + mozilla::services::GetStringBundleService(); + if (bundleService) + bundleService->CreateBundle(APPLEMAIL_MSGS_URL, getter_AddRefs(mBundle)); +} + + +nsAppleMailImportModule::~nsAppleMailImportModule() +{ + IMPORT_LOG0("nsAppleMailImportModule Deleted"); +} + + +NS_IMPL_ISUPPORTS(nsAppleMailImportModule, nsIImportModule) + + +NS_IMETHODIMP nsAppleMailImportModule::GetName(char16_t **aName) +{ + return mBundle ? + mBundle->GetStringFromName(u"ApplemailImportName", aName) : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP nsAppleMailImportModule::GetDescription(char16_t **aName) +{ + return mBundle ? + mBundle->GetStringFromName(u"ApplemailImportDescription", aName) : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP nsAppleMailImportModule::GetSupports(char **aSupports) +{ + NS_ENSURE_ARG_POINTER(aSupports); + *aSupports = strdup(NS_IMPORT_MAIL_STR); + return NS_OK; +} + +NS_IMETHODIMP nsAppleMailImportModule::GetSupportsUpgrade(bool *aUpgrade) +{ + NS_ENSURE_ARG_POINTER(aUpgrade); + *aUpgrade = false; + return NS_OK; +} + +NS_IMETHODIMP nsAppleMailImportModule::GetImportInterface(const char *aImportType, nsISupports **aInterface) +{ + NS_ENSURE_ARG_POINTER(aImportType); + NS_ENSURE_ARG_POINTER(aInterface); + *aInterface = nullptr; + nsresult rv = NS_ERROR_NOT_AVAILABLE; + + if (!strcmp(aImportType, "mail")) { + nsCOMPtr<nsIImportMail> mail(do_CreateInstance(NS_APPLEMAILIMPL_CONTRACTID, &rv)); + if (NS_SUCCEEDED(rv)) { + nsCOMPtr<nsIImportService> impSvc(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv)); + if (NS_SUCCEEDED(rv)) { + nsCOMPtr<nsIImportGeneric> generic; + rv = impSvc->CreateNewGenericMail(getter_AddRefs(generic)); + if (NS_SUCCEEDED(rv)) { + nsAutoString name; + rv = mBundle->GetStringFromName(u"ApplemailImportName", getter_Copies(name)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsISupportsString> nameString(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv)); + NS_ENSURE_SUCCESS(rv, rv); + nameString->SetData(name); + + generic->SetData("name", nameString); + generic->SetData("mailInterface", mail); + + generic.forget(aInterface); + } + } + } + } + + return rv; +} + +#pragma mark - + +nsAppleMailImportMail::nsAppleMailImportMail() : mProgress(0), mCurDepth(0) +{ + IMPORT_LOG0("nsAppleMailImportMail created"); +} + +nsresult nsAppleMailImportMail::Initialize() +{ + nsCOMPtr<nsIStringBundleService> bundleService = + mozilla::services::GetStringBundleService(); + NS_ENSURE_TRUE(bundleService, NS_ERROR_UNEXPECTED); + + return bundleService->CreateBundle(APPLEMAIL_MSGS_URL, getter_AddRefs(mBundle)); +} + +nsAppleMailImportMail::~nsAppleMailImportMail() +{ + IMPORT_LOG0("nsAppleMailImportMail destroyed"); +} + +NS_IMPL_ISUPPORTS(nsAppleMailImportMail, nsIImportMail) + +NS_IMETHODIMP nsAppleMailImportMail::GetDefaultLocation(nsIFile **aLocation, bool *aFound, bool *aUserVerify) +{ + NS_ENSURE_ARG_POINTER(aFound); + NS_ENSURE_ARG_POINTER(aLocation); + NS_ENSURE_ARG_POINTER(aUserVerify); + + *aLocation = nullptr; + *aFound = false; + *aUserVerify = true; + + // try to find current user's top-level Mail folder + nsCOMPtr<nsIFile> mailFolder(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID)); + if (mailFolder) { + nsresult rv = mailFolder->InitWithNativePath(NS_LITERAL_CSTRING(DEFAULT_MAIL_FOLDER)); + if (NS_SUCCEEDED(rv)) { + *aFound = true; + *aUserVerify = false; + mailFolder.forget(aLocation); + } + } + + return NS_OK; +} + +// this is the method that initiates all searching for mailboxes. +// it will assume that it has a directory like ~/Library/Mail/ +NS_IMETHODIMP nsAppleMailImportMail::FindMailboxes(nsIFile *aMailboxFile, nsIArray **aResult) +{ + NS_ENSURE_ARG_POINTER(aMailboxFile); + NS_ENSURE_ARG_POINTER(aResult); + + IMPORT_LOG0("FindMailboxes for Apple mail invoked"); + + bool exists = false; + nsresult rv = aMailboxFile->Exists(&exists); + if (NS_FAILED(rv) || !exists) + return NS_ERROR_FAILURE; + + nsCOMPtr<nsIImportService> importService(do_GetService(NS_IMPORTSERVICE_CONTRACTID, &rv)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIMutableArray> resultsArray(do_CreateInstance(NS_ARRAY_CONTRACTID, &rv)); + if (!resultsArray) + return NS_ERROR_OUT_OF_MEMORY; + + mCurDepth = 1; + + // 1. look for accounts with mailboxes + FindAccountMailDirs(aMailboxFile, resultsArray, importService); + mCurDepth--; + + if (NS_SUCCEEDED(rv)) { + // 2. look for "global" mailboxes, that don't belong to any specific account. they are inside the + // root's Mailboxes/ folder + nsCOMPtr<nsIFile> mailboxesDir(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv)); + if (NS_SUCCEEDED(rv)) { + mailboxesDir->InitWithFile(aMailboxFile); + rv = mailboxesDir->Append(NS_LITERAL_STRING("Mailboxes")); + if (NS_SUCCEEDED(rv)) { + IMPORT_LOG0("Looking for global Apple mailboxes"); + + mCurDepth++; + rv = FindMboxDirs(mailboxesDir, resultsArray, importService); + mCurDepth--; + } + } + } + + if (NS_SUCCEEDED(rv) && resultsArray) + resultsArray.forget(aResult); + + return rv; +} + +// operates on the Mail/ directory root, trying to find accounts (which are folders named something like "POP-hwaara@gmail.com") +// and add their .mbox dirs +void nsAppleMailImportMail::FindAccountMailDirs(nsIFile *aRoot, nsIMutableArray *aMailboxDescs, nsIImportService *aImportService) +{ + nsCOMPtr<nsISimpleEnumerator> directoryEnumerator; + nsresult rv = aRoot->GetDirectoryEntries(getter_AddRefs(directoryEnumerator)); + if (NS_FAILED(rv)) + return; + + bool hasMore = false; + while (NS_SUCCEEDED(directoryEnumerator->HasMoreElements(&hasMore)) && hasMore) { + + // get the next file entry + nsCOMPtr<nsIFile> currentEntry; + { + nsCOMPtr<nsISupports> rawSupports; + directoryEnumerator->GetNext(getter_AddRefs(rawSupports)); + if (!rawSupports) + continue; + currentEntry = do_QueryInterface(rawSupports); + if (!currentEntry) + continue; + } + + // make sure it's a directory + bool isDirectory = false; + currentEntry->IsDirectory(&isDirectory); + + if (isDirectory) { + // now let's see if it's an account folder. if so, we want to traverse it for .mbox children + nsAutoString folderName; + currentEntry->GetLeafName(folderName); + bool isAccountFolder = false; + + if (StringBeginsWith(folderName, NS_LITERAL_STRING("POP-"))) { + // cut off "POP-" prefix so we get a nice folder name + folderName.Cut(0, 4); + isAccountFolder = true; + } + else if (StringBeginsWith(folderName, NS_LITERAL_STRING("IMAP-"))) { + // cut off "IMAP-" prefix so we get a nice folder name + folderName.Cut(0, 5); + isAccountFolder = true; + } + + if (isAccountFolder) { + IMPORT_LOG1("Found account: %s\n", NS_ConvertUTF16toUTF8(folderName).get()); + + // create a mailbox for this account, so we get a parent for "Inbox", "Sent Messages", etc. + nsCOMPtr<nsIImportMailboxDescriptor> desc; + nsresult rv = aImportService->CreateNewMailboxDescriptor(getter_AddRefs(desc)); + desc->SetSize(1); + desc->SetDepth(mCurDepth); + desc->SetDisplayName(folderName.get()); + desc->SetIdentifier(kAccountMailboxID); + + nsCOMPtr<nsIFile> mailboxDescFile; + rv = desc->GetFile(getter_AddRefs(mailboxDescFile)); + if (!mailboxDescFile) + continue; + + mailboxDescFile->InitWithFile(currentEntry); + + // add this mailbox descriptor to the list + aMailboxDescs->AppendElement(desc, false); + + // now add all the children mailboxes + mCurDepth++; + FindMboxDirs(currentEntry, aMailboxDescs, aImportService); + mCurDepth--; + } + } + } +} + +// adds the specified file as a mailboxdescriptor to the array +nsresult nsAppleMailImportMail::AddMboxDir(nsIFile *aFolder, nsIMutableArray *aMailboxDescs, nsIImportService *aImportService) +{ + nsAutoString folderName; + aFolder->GetLeafName(folderName); + + // cut off the suffix, if any, or prefix if this is an account folder. + if (StringEndsWith(folderName, NS_LITERAL_STRING(POP_MBOX_SUFFIX))) + folderName.SetLength(folderName.Length()-5); + else if (StringEndsWith(folderName, NS_LITERAL_STRING(IMAP_MBOX_SUFFIX))) + folderName.SetLength(folderName.Length()-9); + else if (StringBeginsWith(folderName, NS_LITERAL_STRING("POP-"))) + folderName.Cut(4, folderName.Length()); + else if (StringBeginsWith(folderName, NS_LITERAL_STRING("IMAP-"))) + folderName.Cut(5, folderName.Length()); + + nsCOMPtr<nsIImportMailboxDescriptor> desc; + nsresult rv = aImportService->CreateNewMailboxDescriptor(getter_AddRefs(desc)); + if (NS_SUCCEEDED(rv)) { + // find out number of messages in this .mbox + uint32_t numMessages = 0; + { + // move to the .mbox's Messages folder + nsCOMPtr<nsIFile> messagesFolder; + aFolder->Clone(getter_AddRefs(messagesFolder)); + nsresult rv = messagesFolder->Append(NS_LITERAL_STRING("Messages")); + NS_ENSURE_SUCCESS(rv, rv); + + // count the number of messages in this folder. it sucks that we have to iterate through the folder + // but XPCOM doesn't give us any way to just get the file count, unfortunately. :-( + nsCOMPtr<nsISimpleEnumerator> dirEnumerator; + messagesFolder->GetDirectoryEntries(getter_AddRefs(dirEnumerator)); + if (dirEnumerator) { + bool hasMore = false; + while (NS_SUCCEEDED(dirEnumerator->HasMoreElements(&hasMore)) && hasMore) { + nsCOMPtr<nsISupports> rawSupports; + dirEnumerator->GetNext(getter_AddRefs(rawSupports)); + if (!rawSupports) + continue; + + nsCOMPtr<nsIFile> file(do_QueryInterface(rawSupports)); + if (file) { + bool isFile = false; + file->IsFile(&isFile); + if (isFile) + numMessages++; + } + } + } + } + + desc->SetSize(numMessages); + desc->SetDisplayName(folderName.get()); + desc->SetDepth(mCurDepth); + + IMPORT_LOG3("Will import %s with approx %d messages, depth is %d", NS_ConvertUTF16toUTF8(folderName).get(), numMessages, mCurDepth); + + // XXX: this is silly. there's no setter for the mailbox descriptor's file, so we need to get it, and then modify it. + nsCOMPtr<nsIFile> mailboxDescFile; + rv = desc->GetFile(getter_AddRefs(mailboxDescFile)); + NS_ENSURE_SUCCESS(rv, rv); + + if (mailboxDescFile) + mailboxDescFile->InitWithFile(aFolder); + + // add this mailbox descriptor to the list + aMailboxDescs->AppendElement(desc, false); + } + + return NS_OK; +} + +// Starts looking for .mbox dirs in the specified dir. The .mbox dirs contain messages and can be considered leafs in a tree of +// nested mailboxes (subfolders). +// +// If a mailbox has sub-mailboxes, they are contained in a sibling folder with the same name without the ".mbox" part. +// example: +// MyParentMailbox.mbox/ +// MyParentMailbox/ +// MyChildMailbox.mbox/ +// MyOtherChildMailbox.mbox/ +// +nsresult nsAppleMailImportMail::FindMboxDirs(nsIFile *aFolder, nsIMutableArray *aMailboxDescs, nsIImportService *aImportService) +{ + NS_ENSURE_ARG_POINTER(aFolder); + NS_ENSURE_ARG_POINTER(aMailboxDescs); + NS_ENSURE_ARG_POINTER(aImportService); + + // make sure this is a directory. + bool isDir = false; + if (NS_FAILED(aFolder->IsDirectory(&isDir)) || !isDir) + return NS_ERROR_FAILURE; + + // iterate through the folder contents + nsCOMPtr<nsISimpleEnumerator> directoryEnumerator; + nsresult rv = aFolder->GetDirectoryEntries(getter_AddRefs(directoryEnumerator)); + if (NS_FAILED(rv) || !directoryEnumerator) + return rv; + + bool hasMore = false; + while (NS_SUCCEEDED(directoryEnumerator->HasMoreElements(&hasMore)) && hasMore) { + + // get the next file entry + nsCOMPtr<nsIFile> currentEntry; + { + nsCOMPtr<nsISupports> rawSupports; + directoryEnumerator->GetNext(getter_AddRefs(rawSupports)); + if (!rawSupports) + continue; + currentEntry = do_QueryInterface(rawSupports); + if (!currentEntry) + continue; + } + + // we only care about directories... + if (NS_FAILED(currentEntry->IsDirectory(&isDir)) || !isDir) + continue; + + // now find out if this is a .mbox dir + nsAutoString currentFolderName; + if (NS_SUCCEEDED(currentEntry->GetLeafName(currentFolderName)) && + (StringEndsWith(currentFolderName, NS_LITERAL_STRING(POP_MBOX_SUFFIX)) || + StringEndsWith(currentFolderName, NS_LITERAL_STRING(IMAP_MBOX_SUFFIX)))) { + IMPORT_LOG1("Adding .mbox dir: %s", NS_ConvertUTF16toUTF8(currentFolderName).get()); + + // add this .mbox + rv = AddMboxDir(currentEntry, aMailboxDescs, aImportService); + if (NS_FAILED(rv)) { + IMPORT_LOG1("Couldn't add .mbox for import: %s ... continuing anyway", NS_ConvertUTF16toUTF8(currentFolderName).get()); + continue; + } + + // see if this .mbox dir has any sub-mailboxes + nsAutoString siblingMailboxDirPath; + currentEntry->GetPath(siblingMailboxDirPath); + + // cut off suffix + if (StringEndsWith(siblingMailboxDirPath, NS_LITERAL_STRING(IMAP_MBOX_SUFFIX))) + siblingMailboxDirPath.SetLength(siblingMailboxDirPath.Length()-9); + else if (StringEndsWith(siblingMailboxDirPath, NS_LITERAL_STRING(POP_MBOX_SUFFIX))) + siblingMailboxDirPath.SetLength(siblingMailboxDirPath.Length()-5); + + IMPORT_LOG1("trying to locate a '%s'", NS_ConvertUTF16toUTF8(siblingMailboxDirPath).get()); + nsCOMPtr<nsIFile> siblingMailboxDir(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv)); + if (NS_FAILED(rv)) + continue; + + rv = siblingMailboxDir->InitWithPath(siblingMailboxDirPath); + bool reallyExists = false; + siblingMailboxDir->Exists(&reallyExists); + + if (NS_SUCCEEDED(rv) && reallyExists) { + IMPORT_LOG1("Found what looks like an .mbox container: %s", NS_ConvertUTF16toUTF8(currentFolderName).get()); + + // traverse this folder for other .mboxes + mCurDepth++; + FindMboxDirs(siblingMailboxDir, aMailboxDescs, aImportService); + mCurDepth--; + } + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsAppleMailImportMail::ImportMailbox(nsIImportMailboxDescriptor *aMailbox, + nsIMsgFolder *aDstFolder, + char16_t **aErrorLog, + char16_t **aSuccessLog, bool *aFatalError) +{ + nsAutoString errorLog, successLog; + + // reset progress + mProgress = 0; + + nsAutoString mailboxName; + aMailbox->GetDisplayName(getter_Copies(mailboxName)); + + nsCOMPtr<nsIFile> mboxFolder; + nsresult rv = aMailbox->GetFile(getter_AddRefs(mboxFolder)); + if (NS_FAILED(rv) || !mboxFolder) { + ReportStatus(u"ApplemailImportMailboxConverterror", mailboxName, errorLog); + SetLogs(successLog, errorLog, aSuccessLog, aErrorLog); + return NS_ERROR_FAILURE; + } + + // if we're an account mailbox, nothing do. if we're a real mbox + // then we've got some messages to import! + uint32_t mailboxIdentifier; + aMailbox->GetIdentifier(&mailboxIdentifier); + + if (mailboxIdentifier != kAccountMailboxID) { + // move to the .mbox's Messages folder + nsCOMPtr<nsIFile> messagesFolder; + mboxFolder->Clone(getter_AddRefs(messagesFolder)); + rv = messagesFolder->Append(NS_LITERAL_STRING("Messages")); + if (NS_FAILED(rv)) { + // even if there are no messages, it might still be a valid mailbox, or even + // a parent for other mailboxes. + // + // just indicate that we're done, using the same number that we used to estimate + // number of messages earlier. + uint32_t finalSize; + aMailbox->GetSize(&finalSize); + mProgress = finalSize; + + // report that we successfully imported this mailbox + ReportStatus(u"ApplemailImportMailboxSuccess", mailboxName, successLog); + SetLogs(successLog, errorLog, aSuccessLog, aErrorLog); + return NS_OK; + } + + // let's import the messages! + nsCOMPtr<nsISimpleEnumerator> directoryEnumerator; + rv = messagesFolder->GetDirectoryEntries(getter_AddRefs(directoryEnumerator)); + if (NS_FAILED(rv)) { + ReportStatus(u"ApplemailImportMailboxConvertError", mailboxName, errorLog); + SetLogs(successLog, errorLog, aSuccessLog, aErrorLog); + return NS_ERROR_FAILURE; + } + + // prepare an outstream to the destination file + nsCOMPtr<nsIMsgPluggableStore> msgStore; + rv = aDstFolder->GetMsgStore(getter_AddRefs(msgStore)); + if (!msgStore || NS_FAILED(rv)) { + ReportStatus(u"ApplemailImportMailboxConverterror", mailboxName, errorLog); + SetLogs(successLog, errorLog, aSuccessLog, aErrorLog); + return NS_ERROR_FAILURE; + } + + bool hasMore = false; + nsCOMPtr<nsIOutputStream> outStream; + + while (NS_SUCCEEDED(directoryEnumerator->HasMoreElements(&hasMore)) && hasMore) { + // get the next file entry + nsCOMPtr<nsIFile> currentEntry; + { + nsCOMPtr<nsISupports> rawSupports; + directoryEnumerator->GetNext(getter_AddRefs(rawSupports)); + if (!rawSupports) + continue; + currentEntry = do_QueryInterface(rawSupports); + if (!currentEntry) + continue; + } + + // make sure it's an .emlx file + bool isFile = false; + currentEntry->IsFile(&isFile); + if (!isFile) + continue; + + nsAutoString leafName; + currentEntry->GetLeafName(leafName); + if (!StringEndsWith(leafName, NS_LITERAL_STRING(".emlx"))) + continue; + + nsCOMPtr<nsIMsgDBHdr> msgHdr; + bool reusable; + rv = msgStore->GetNewMsgOutputStream(aDstFolder, getter_AddRefs(msgHdr), + &reusable, + getter_AddRefs(outStream)); + if (NS_FAILED(rv)) + break; + + // add the data to the mbox stream + if (NS_SUCCEEDED(nsEmlxHelperUtils::AddEmlxMessageToStream(currentEntry, outStream))) { + mProgress++; + msgStore->FinishNewMessage(outStream, msgHdr); + } + else { + msgStore->DiscardNewMessage(outStream, msgHdr); + break; + } + if (!reusable) + outStream->Close(); + } + if (outStream) + outStream->Close(); + } + // just indicate that we're done, using the same number that we used to estimate + // number of messages earlier. + uint32_t finalSize; + aMailbox->GetSize(&finalSize); + mProgress = finalSize; + + // report that we successfully imported this mailbox + ReportStatus(u"ApplemailImportMailboxSuccess", mailboxName, successLog); + SetLogs(successLog, errorLog, aSuccessLog, aErrorLog); + + return NS_OK; +} + +void nsAppleMailImportMail::ReportStatus(const char16_t* aErrorName, nsString &aName, + nsAString &aStream) +{ + // get (and format, if needed) the error string from the bundle + nsAutoString outString; + const char16_t *fmt = { aName.get() }; + nsresult rv = mBundle->FormatStringFromName(aErrorName, &fmt, 1, getter_Copies(outString)); + // write it out the stream + if (NS_SUCCEEDED(rv)) { + aStream.Append(outString); + aStream.Append(char16_t('\n')); + } +} + +void nsAppleMailImportMail::SetLogs(const nsAString &aSuccess, const nsAString &aError, char16_t **aOutSuccess, char16_t **aOutError) +{ + if (aOutError && !*aOutError) + *aOutError = ToNewUnicode(aError); + if (aOutSuccess && !*aOutSuccess) + *aOutSuccess = ToNewUnicode(aSuccess); +} + +NS_IMETHODIMP nsAppleMailImportMail::GetImportProgress(uint32_t *aDoneSoFar) +{ + NS_ENSURE_ARG_POINTER(aDoneSoFar); + *aDoneSoFar = mProgress; + return NS_OK; +} + +NS_IMETHODIMP nsAppleMailImportMail::TranslateFolderName(const nsAString &aFolderName, nsAString &aResult) +{ + aResult = aFolderName; + return NS_OK; +} diff --git a/mailnews/import/applemail/src/nsAppleMailImport.h b/mailnews/import/applemail/src/nsAppleMailImport.h new file mode 100644 index 0000000000..b906aecf56 --- /dev/null +++ b/mailnews/import/applemail/src/nsAppleMailImport.h @@ -0,0 +1,78 @@ +/* -*- 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/. */ + +#ifndef nsAppleMailImport_h___ +#define nsAppleMailImport_h___ + +#include "mozilla/Logging.h" +#include "nsIImportModule.h" +#include "nsCOMPtr.h" +#include "nsIStringBundle.h" +#include "nsIImportMail.h" + +// logging facilities +extern PRLogModuleInfo *APPLEMAILLOGMODULE; + +#define IMPORT_LOG0(x) MOZ_LOG(APPLEMAILLOGMODULE, mozilla::LogLevel::Debug, (x)) +#define IMPORT_LOG1(x, y) MOZ_LOG(APPLEMAILLOGMODULE, mozilla::LogLevel::Debug, (x, y)) +#define IMPORT_LOG2(x, y, z) MOZ_LOG(APPLEMAILLOGMODULE, mozilla::LogLevel::Debug, (x, y, z)) +#define IMPORT_LOG3(a, b, c, d) MOZ_LOG(APPLEMAILLOGMODULE, mozilla::LogLevel::Debug, (a, b, c, d)) + +#define NS_APPLEMAILIMPL_CID \ +{ 0x9117a1ea, 0xe012, 0x43b5, { 0xa0, 0x20, 0xcb, 0x8a, 0x66, 0xcc, 0x09, 0xe1 } } + +#define NS_APPLEMAILIMPORT_CID \ +{ 0x6d3f101c, 0x70ec, 0x4e04, { 0xb6, 0x8d, 0x99, 0x08, 0xd1, 0xae, 0xdd, 0xf3 } } + +#define NS_APPLEMAILIMPL_CONTRACTID "@mozilla.org/import/import-appleMailImpl;1" + +#define kAppleMailSupportsString "mail" + +class nsIImportService; +class nsIMutableArray; + +class nsAppleMailImportModule : public nsIImportModule +{ + public: + + nsAppleMailImportModule(); + + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIIMPORTMODULE + + private: + virtual ~nsAppleMailImportModule(); + + nsCOMPtr<nsIStringBundle> mBundle; +}; + +class nsAppleMailImportMail : public nsIImportMail +{ + public: + + nsAppleMailImportMail(); + + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIIMPORTMAIL + + nsresult Initialize(); + + private: + virtual ~nsAppleMailImportMail(); + + void FindAccountMailDirs(nsIFile *aRoot, nsIMutableArray *aMailboxDescs, nsIImportService *aImportService); + nsresult FindMboxDirs(nsIFile *aFolder, nsIMutableArray *aMailboxDescs, nsIImportService *aImportService); + nsresult AddMboxDir(nsIFile *aFolder, nsIMutableArray *aMailboxDescs, nsIImportService *aImportService); + + // aInfoString is the format to a "foo %s" string. It may be NULL if the error string needs no such format. + void ReportStatus(const char16_t* aErrorName, nsString &aName, nsAString &aStream); + static void SetLogs(const nsAString& success, const nsAString& error, char16_t **aOutErrorLog, char16_t **aSuccessLog); + + nsCOMPtr<nsIStringBundle> mBundle; + uint32_t mProgress; + uint16_t mCurDepth; +}; + +#endif /* nsAppleMailImport_h___ */ diff --git a/mailnews/import/applemail/src/nsEmlxHelperUtils.h b/mailnews/import/applemail/src/nsEmlxHelperUtils.h new file mode 100644 index 0000000000..728b725b60 --- /dev/null +++ b/mailnews/import/applemail/src/nsEmlxHelperUtils.h @@ -0,0 +1,55 @@ +/* -*- 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/. */ + +#ifndef nsEmlxHelperUtils_h___ +#define nsEmlxHelperUtils_h___ + +#include "nscore.h" +#include "nsStringGlue.h" + +class nsIOutputStream; +class nsIFile; + +class nsEmlxHelperUtils { + /* All emlx messages have a "flags" number in the metadata. + These are the masks to decode that, found via http://jwz.livejournal.com/505711.html */ + enum EmlxMetadataMask { + kRead = 1 << 0, // read + // 1 << 1, // deleted + kAnswered = 1 << 2, // answered + // 1 << 3, // encrypted + kFlagged = 1 << 4, // flagged + // 1 << 5, // recent + // 1 << 6, // draft + // 1 << 7, // initial (no longer used) + kForwarded = 1 << 8, // forwarded + // 1 << 9, // redirected + // 3F << 10, // attachment count (6 bits) + // 7F << 16, // priority level (7 bits) + // 1 << 23, // signed + // 1 << 24, // is junk + // 1 << 25, // is not junk + // 1 << 26, // font size delta 7 (3 bits) + // 1 << 29, // junk mail level recorded + // 1 << 30, // highlight text in toc + // 1 << 31 // (unused) + }; + + // This method will scan the raw EMLX message buffer for "dangerous" so-called "From-lines" that we need to escape. + // If it needs to modify any lines, it will return a non-NULL aOutBuffer. If aOutBuffer is NULL, no modification needed + // to be made. + static nsresult ConvertToMboxRD(const char *aMessageBufferStart, const char *aMessageBufferEnd, nsCString &aOutBuffer); + + // returns an int representing the X-Mozilla-Status flags set (e.g. "read", "flagged") converted from EMLX flags. + static nsresult ConvertToMozillaStatusFlags(const char *aXMLBufferStart, const char *aXMLBufferEnd, uint32_t *aMozillaStatusFlags); + + public: + + // add an .emlx message to the mbox output + static nsresult AddEmlxMessageToStream(nsIFile *aEmlxFile, nsIOutputStream *aOutoutStream); + +}; + +#endif // nsEmlxHelperUtils_h___ diff --git a/mailnews/import/applemail/src/nsEmlxHelperUtils.mm b/mailnews/import/applemail/src/nsEmlxHelperUtils.mm new file mode 100644 index 0000000000..d2feb166e6 --- /dev/null +++ b/mailnews/import/applemail/src/nsEmlxHelperUtils.mm @@ -0,0 +1,240 @@ +/* -*- 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 "nsEmlxHelperUtils.h" +#include "nsIFileStreams.h" +#include "nsIBufferedStreams.h" +#include "nsIOutputStream.h" +#include "nsNetUtil.h" +#include "nsCOMPtr.h" +#include "nsObjCExceptions.h" +#include "nsMsgMessageFlags.h" +#include "nsMsgLocalFolderHdrs.h" +#include "msgCore.h" +#include "nsTArray.h" +#include "nsAppleMailImport.h" +#include "prprf.h" +#include "nsIFile.h" + +#import <Cocoa/Cocoa.h> + + +nsresult nsEmlxHelperUtils::ConvertToMozillaStatusFlags(const char *aXMLBufferStart, + const char *aXMLBufferEnd, + uint32_t *aMozillaStatusFlags) +{ + // create a NSData wrapper around the buffer, so we can use the Cocoa call below + NSData *metadata = + [[[NSData alloc] initWithBytesNoCopy:(void *)aXMLBufferStart length:(aXMLBufferEnd-aXMLBufferStart) freeWhenDone:NO] autorelease]; + + // get the XML data as a dictionary + NSPropertyListFormat format; + id plist = [NSPropertyListSerialization propertyListWithData:metadata + options:NSPropertyListImmutable + format:&format + error:NULL]; + + if (!plist) + return NS_ERROR_FAILURE; + + // find the <flags>...</flags> value and convert to int + const uint32_t emlxMessageFlags = [[(NSDictionary *)plist objectForKey:@"flags"] intValue]; + + if (emlxMessageFlags == 0) + return NS_ERROR_FAILURE; + + if (emlxMessageFlags & nsEmlxHelperUtils::kRead) + *aMozillaStatusFlags |= nsMsgMessageFlags::Read; + if (emlxMessageFlags & nsEmlxHelperUtils::kForwarded) + *aMozillaStatusFlags |= nsMsgMessageFlags::Forwarded; + if (emlxMessageFlags & nsEmlxHelperUtils::kAnswered) + *aMozillaStatusFlags |= nsMsgMessageFlags::Replied; + if (emlxMessageFlags & nsEmlxHelperUtils::kFlagged) + *aMozillaStatusFlags |= nsMsgMessageFlags::Marked; + + return NS_OK; +} + +nsresult nsEmlxHelperUtils::ConvertToMboxRD(const char *aMessageBufferStart, const char *aMessageBufferEnd, nsCString &aOutBuffer) +{ + nsTArray<const char *> foundFromLines; + + const char *cur = aMessageBufferStart; + while (cur < aMessageBufferEnd) { + + const char *foundFromStr = strnstr(cur, "From ", aMessageBufferEnd-cur); + + if (foundFromStr) { + // skip all prepending '>' chars + const char *fromLineStart = foundFromStr; + while (fromLineStart-- >= aMessageBufferStart) { + if (*fromLineStart == '\n' || fromLineStart == aMessageBufferStart) { + if (fromLineStart > aMessageBufferStart) + fromLineStart++; + foundFromLines.AppendElement(fromLineStart); + break; + } + else if (*fromLineStart != '>') + break; + } + + // advance past the last found From string. + cur = foundFromStr + 5; + + // look for more From lines. + continue; + } + + break; + } + + // go through foundFromLines + if (foundFromLines.Length()) { + + const char *chunkStart = aMessageBufferStart; + for (unsigned i=0; i<foundFromLines.Length(); ++i) { + aOutBuffer.Append(chunkStart, (foundFromLines[i]-chunkStart)); + aOutBuffer.Append(NS_LITERAL_CSTRING(">")); + + chunkStart = foundFromLines[i]; + } + aOutBuffer.Append(chunkStart, (aMessageBufferEnd - chunkStart)); + } + + return NS_OK; +} + +nsresult nsEmlxHelperUtils::AddEmlxMessageToStream(nsIFile *aMessage, nsIOutputStream *aOut) +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; + + // needed to be sure autoreleased objects are released too, which they might not + // in a C++ environment where the main event loop has no autorelease pool (e.g on a XPCOM thread) + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + nsresult rv = NS_ERROR_FAILURE; + + nsAutoCString path; + aMessage->GetNativePath(path); + + NSData *data = [NSData dataWithContentsOfFile:[NSString stringWithUTF8String:path.get()]]; + if (!data) { + [pool release]; + return NS_ERROR_FAILURE; + } + + char *startOfMessageData = NULL; + uint32_t actualBytesWritten = 0; + + // The anatomy of an EMLX file: + // + // ------------------------------- + // < A number describing how many bytes ahead there is message data > + // < Message data > + // < XML metadata for this message > + // ------------------------------- + + // read the first line of the emlx file, which is a number of how many bytes ahead the actual + // message data is. + uint64_t numberOfBytesToRead = strtol((char *)[data bytes], &startOfMessageData, 10); + if (numberOfBytesToRead <= 0 || !startOfMessageData) { + [pool release]; + return NS_ERROR_FAILURE; + } + + // skip whitespace + while (*startOfMessageData == ' ' || + *startOfMessageData == '\n' || + *startOfMessageData == '\r' || + *startOfMessageData == '\t') + ++startOfMessageData; + + NS_NAMED_LITERAL_CSTRING(kBogusFromLine, "From \n"); + NS_NAMED_LITERAL_CSTRING(kEndOfMessage, "\n\n"); + + // write the bogus "From " line which is a magic separator in the mbox format + rv = aOut->Write(kBogusFromLine.get(), kBogusFromLine.Length(), &actualBytesWritten); + if (NS_FAILED(rv)) { + [pool release]; + return rv; + } + + // now read the XML metadata, so we can extract info like which flags (read? replied? flagged? etc) this message has. + const char *startOfXMLMetadata = startOfMessageData + numberOfBytesToRead; + const char *endOfXMLMetadata = (char *)[data bytes] + [data length]; + + uint32_t x_mozilla_flags = 0; + ConvertToMozillaStatusFlags(startOfXMLMetadata, endOfXMLMetadata, &x_mozilla_flags); + + // write the X-Mozilla-Status header according to which flags we've gathered above. + uint32_t dummyRv; + nsAutoCString buf(PR_smprintf(X_MOZILLA_STATUS_FORMAT MSG_LINEBREAK, x_mozilla_flags)); + NS_ASSERTION(!buf.IsEmpty(), "printf error with X-Mozilla-Status header"); + if (buf.IsEmpty()) { + [pool release]; + return rv; + } + + rv = aOut->Write(buf.get(), buf.Length(), &dummyRv); + if (NS_FAILED(rv)) { + [pool release]; + return rv; + } + + // write out X-Mozilla-Keywords header as well to reserve some space for it + // in the mbox file. + rv = aOut->Write(X_MOZILLA_KEYWORDS, X_MOZILLA_KEYWORDS_LEN, &dummyRv); + if (NS_FAILED(rv)) { + [pool release]; + return rv; + } + + // write out empty X-Mozilla_status2 header + buf.Adopt(PR_smprintf(X_MOZILLA_STATUS2_FORMAT MSG_LINEBREAK, 0)); + NS_ASSERTION(!buf.IsEmpty(), "printf error with X-Mozilla-Status2 header"); + if (buf.IsEmpty()) { + [pool release]; + return NS_ERROR_OUT_OF_MEMORY; + } + + rv = aOut->Write(buf.get(), buf.Length(), &dummyRv); + if (NS_FAILED(rv)) { + [pool release]; + return rv; + } + + // do any conversion needed for the mbox data to be valid mboxrd. + nsCString convertedData; + rv = ConvertToMboxRD(startOfMessageData, (startOfMessageData + numberOfBytesToRead), convertedData); + if (NS_FAILED(rv)) { + [pool release]; + return rv; + } + + // write the actual message data. + if (convertedData.IsEmpty()) + rv = aOut->Write(startOfMessageData, (uint32_t)numberOfBytesToRead, &actualBytesWritten); + else { + IMPORT_LOG1("Escaped From-lines in %s!", path.get()); + rv = aOut->Write(convertedData.get(), convertedData.Length(), &actualBytesWritten); + } + + if (NS_FAILED(rv)) { + [pool release]; + return rv; + } + + NS_ASSERTION(actualBytesWritten == (convertedData.IsEmpty() ? numberOfBytesToRead : convertedData.Length()), + "Didn't write as many bytes as expected for .emlx file?"); + + // add newlines to denote the end of this message in the mbox + rv = aOut->Write(kEndOfMessage.get(), kEndOfMessage.Length(), &actualBytesWritten); + + [pool release]; + + return rv; + + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; +} diff --git a/mailnews/import/build/nsImportModule.cpp b/mailnews/import/build/nsImportModule.cpp index 813271b08f..f8f3814e6e 100644 --- a/mailnews/import/build/nsImportModule.cpp +++ b/mailnews/import/build/nsImportModule.cpp @@ -33,6 +33,16 @@ NS_DEFINE_NAMED_CID(NS_TEXTIMPORT_CID); NS_DEFINE_NAMED_CID(NS_VCARDIMPORT_CID); //////////////////////////////////////////////////////////////////////////////// +// Apple Mail import Include Files +//////////////////////////////////////////////////////////////////////////////// +#if defined(XP_MACOSX) +#include "nsAppleMailImport.h" + +NS_DEFINE_NAMED_CID(NS_APPLEMAILIMPORT_CID); +NS_DEFINE_NAMED_CID(NS_APPLEMAILIMPL_CID); +#endif + +//////////////////////////////////////////////////////////////////////////////// // outlook import Include Files //////////////////////////////////////////////////////////////////////////////// #ifdef XP_WIN @@ -76,6 +86,14 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsTextImport) NS_GENERIC_FACTORY_CONSTRUCTOR(nsVCardImport) //////////////////////////////////////////////////////////////////////////////// +// apple mail import factories +//////////////////////////////////////////////////////////////////////////////// +#if defined(XP_MACOSX) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsAppleMailImportModule) +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsAppleMailImportMail, Initialize) +#endif + +//////////////////////////////////////////////////////////////////////////////// // outlook import factories //////////////////////////////////////////////////////////////////////////////// #ifdef XP_WIN @@ -103,6 +121,9 @@ static const mozilla::Module::CategoryEntry kMailNewsImportCategories[] = { { "mailnewsimport", "{1DB469A0-8B00-11d3-A206-00A0CC26DA63}", kOutlookSupportsString }, #endif #endif +#if defined(XP_MACOSX) + { "mailnewsimport", "{6d3f101c-70ec-4e04-b68d-9908d1aeddf3}", kAppleMailSupportsString }, +#endif { NULL } }; @@ -111,6 +132,11 @@ const mozilla::Module::CIDEntry kMailNewsImportCIDs[] = { { &kNS_IMPORTMIMEENCODE_CID, false, NULL, nsIImportMimeEncodeImplConstructor }, { &kNS_TEXTIMPORT_CID, false, NULL, nsTextImportConstructor }, { &kNS_VCARDIMPORT_CID, false, NULL, nsVCardImportConstructor }, +#if defined(XP_MACOSX) + { &kNS_APPLEMAILIMPORT_CID, false, NULL, nsAppleMailImportModuleConstructor }, + { &kNS_APPLEMAILIMPL_CID, false, NULL, nsAppleMailImportMailConstructor }, +#endif + #ifdef XP_WIN { &kNS_WMIMPORT_CID, false, NULL, nsWMImportConstructor }, { &kNS_BECKYIMPORT_CID, false, NULL, nsBeckyImportConstructor }, @@ -126,6 +152,11 @@ const mozilla::Module::ContractIDEntry kMailNewsImportContracts[] = { { "@mozilla.org/import/import-mimeencode;1", &kNS_IMPORTMIMEENCODE_CID }, { "@mozilla.org/import/import-text;1", &kNS_TEXTIMPORT_CID }, { "@mozilla.org/import/import-vcard;1", &kNS_VCARDIMPORT_CID }, +#if defined(XP_MACOSX) + { "@mozilla.org/import/import-applemail;1", &kNS_APPLEMAILIMPORT_CID }, + { NS_APPLEMAILIMPL_CONTRACTID, &kNS_APPLEMAILIMPL_CID }, +#endif + #ifdef XP_WIN { "@mozilla.org/import/import-wm;1", &kNS_WMIMPORT_CID }, { "@mozilla.org/import/import-becky;1", &kNS_BECKYIMPORT_CID }, diff --git a/mailnews/import/content/importDialog.xul b/mailnews/import/content/importDialog.xul index 1223a12635..383585f83e 100644 --- a/mailnews/import/content/importDialog.xul +++ b/mailnews/import/content/importDialog.xul @@ -15,7 +15,11 @@ <window xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" onload="OnLoadImportDialog()" +#ifdef XP_MACOSX + style="width: &window.macWidth; !important;" +#else style="width: &window.width; !important;" +#endif title="&importDialog.windowTitle;"> <stringbundle id="bundle_importMsgs" src="chrome://messenger/locale/importMsgs.properties"/> diff --git a/mailnews/jar.mn b/mailnews/jar.mn index 8b850ecb91..71539e9aa0 100644 --- a/mailnews/jar.mn +++ b/mailnews/jar.mn @@ -131,6 +131,8 @@ messenger.jar: content/messenger/dateFormat.js (base/content/dateFormat.js) content/messenger/shutdownWindow.xul (base/content/shutdownWindow.xul) content/messenger/shutdownWindow.js (base/content/shutdownWindow.js) +#ifndef XP_MACOSX content/messenger/newmailalert.css (base/content/newmailalert.css) content/messenger/newmailalert.js (base/content/newmailalert.js) content/messenger/newmailalert.xul (base/content/newmailalert.xul) +#endif diff --git a/mailnews/mailnews.js b/mailnews/mailnews.js index ae172305d2..49ac33827e 100644 --- a/mailnews/mailnews.js +++ b/mailnews/mailnews.js @@ -696,7 +696,11 @@ pref("mail.biff.alert.show_subject", true); pref("mail.biff.alert.show_sender", true); pref("mail.biff.alert.preview_length", 40); +#ifdef XP_MACOSX +pref("mail.biff.play_sound", false); +#else pref("mail.biff.play_sound", true); +#endif // 0 == default system sound, 1 == user specified wav pref("mail.biff.play_sound.type", 0); // _moz_mailbeep is a magic key, for the default sound. @@ -706,6 +710,8 @@ pref("mail.biff.show_alert", true); #ifdef XP_WIN pref("mail.biff.show_tray_icon", true); pref("mail.biff.show_balloon", false); +#elifdef XP_MACOSX +pref("mail.biff.animate_dock_icon", false); #elifdef XP_UNIX pref("mail.biff.use_system_alert", false); #endif @@ -718,6 +724,13 @@ pref("mail.biff.add_interval_jitter", true); pref("mail.biff.on_new_window", true); #endif +#ifdef XP_MACOSX +// If true, the number used in the Mac OS X dock notification will be the +// the number of "new" messages, as per the classic Thunderbird definition. +// Defaults to false, which notifies about the number of unread messages. +pref("mail.biff.use_new_count_in_mac_dock", false); +#endif + // For feed account serverType=rss sound on biff; if true, mail.biff.play_sound.* settings are used. pref("mail.feed.play_sound", false); @@ -834,6 +847,15 @@ pref("ldap_2.servers.oe.description", "chrome://messenger/locale/addressbook/add pref("ldap_2.servers.oe.dirType", 3); #endif #endif +#ifdef XP_MACOSX +pref("ldap_2.servers.osx.uri", "moz-abosxdirectory:///"); +pref("ldap_2.servers.osx.description", "chrome://messenger/locale/addressbook/addressBook.properties"); +pref("ldap_2.servers.osx.dirType", 3); +pref("mail.notification.sound", ""); +pref("mail.notification.count.inbox_only", true); +// Work around bug 482811 by disabling slow script warning for chrome scripts on Mac +pref("dom.max_chrome_script_run_time", 0); +#endif // gtk2 (*nix) lacks transparent/translucent drag support (bug 376238), so we // want to disable it so people can see where they are dragging things. diff --git a/mailnews/mime/src/mimeebod.cpp b/mailnews/mime/src/mimeebod.cpp index ee66c40ca2..2ca056feb8 100644 --- a/mailnews/mime/src/mimeebod.cpp +++ b/mailnews/mime/src/mimeebod.cpp @@ -21,6 +21,10 @@ MimeDefClass(MimeExternalBody, MimeExternalBodyClass, mimeExternalBodyClass, &MIME_SUPERCLASS); +#ifdef XP_MACOSX +extern MimeObjectClass mimeMultipartAppleDoubleClass; +#endif + static int MimeExternalBody_initialize (MimeObject *); static void MimeExternalBody_finalize (MimeObject *); static int MimeExternalBody_parse_line (const char *, int32_t, MimeObject *); @@ -248,6 +252,12 @@ MimeExternalBody_parse_eof (MimeObject *obj, bool abort_p) status = ((MimeObjectClass*)&MIME_SUPERCLASS)->parse_eof(obj, abort_p); if (status < 0) return status; +#ifdef XP_MACOSX + if (obj->parent && mime_typep(obj->parent, + (MimeObjectClass*) &mimeMultipartAppleDoubleClass)) + goto done; +#endif /* XP_MACOSX */ + if (!abort_p && obj->output_p && obj->options && @@ -415,6 +425,10 @@ FAIL: PR_FREEIF(subj); } +#ifdef XP_MACOSX +done: +#endif + return status; } diff --git a/mailnews/mime/src/mimemapl.cpp b/mailnews/mime/src/mimemapl.cpp index c7363ceff1..449d80ac08 100644 --- a/mailnews/mime/src/mimemapl.cpp +++ b/mailnews/mime/src/mimemapl.cpp @@ -55,6 +55,19 @@ MimeMultipartAppleDouble_parse_begin (MimeObject *obj) NS_ASSERTION(obj->options->state->first_data_written_p, "first data not written"); } +#ifdef XP_MACOSX + if (obj->options && obj->options->state) + { +// obj->options->state->separator_suppressed_p = true; + goto done; + } + /* + * It would be nice to not showing the resource fork links + * if we are displaying inline. But, there is no way we could + * know ahead of time that we could display the data fork and + * the data fork is always hidden on MAC platform. + */ +#endif /* If we're writing this object as HTML, then emit a link for the multipart/appledouble part (both links) that looks just like the links that MimeExternalObject emits for external leaf parts. @@ -143,6 +156,10 @@ GOTTA STILL DO THIS FOR QUOTING! if (status < 0) return status; } +#ifdef XP_MACOSX +done: +#endif + return 0; } @@ -159,8 +176,13 @@ MimeMultipartAppleDouble_output_child_p(MimeObject *obj, MimeObject *child) if (cont->nchildren >= 1 && cont->children[0] == child && child->content_type && !PL_strcasecmp(child->content_type, APPLICATION_APPLEFILE)) { - /* Don't emit the resources fork. */ +#ifdef XP_MACOSX + if (obj->output_p && obj->options && obj->options->write_html_p) //output HTML + return false; +#else + /* if we are not on a Macintosh, don't emitte the resources fork at all. */ return false; +#endif } return true; diff --git a/mailnews/mime/src/mimemult.cpp b/mailnews/mime/src/mimemult.cpp index c92cc44dcf..4695ba9910 100644 --- a/mailnews/mime/src/mimemult.cpp +++ b/mailnews/mime/src/mimemult.cpp @@ -16,6 +16,10 @@ #include "nsMimeTypes.h" #include <ctype.h> +#ifdef XP_MACOSX + extern MimeObjectClass mimeMultipartAppleDoubleClass; +#endif + #define MIME_SUPERCLASS mimeContainerClass MimeDefClass(MimeMultipart, MimeMultipartClass, mimeMultipartClass, &MIME_SUPERCLASS); @@ -488,6 +492,19 @@ MimeMultipart_create_child(MimeObject *obj) { status = body->clazz->parse_begin(body); +#ifdef XP_MACOSX + /* if we are saving an apple double attachment, we need to set correctly the conten type of the channel */ + if (mime_typep(obj, (MimeObjectClass *) &mimeMultipartAppleDoubleClass)) + { + mime_stream_data *msd = (mime_stream_data *)body->options->stream_closure; + if (!body->options->write_html_p && body->content_type && !PL_strcasecmp(body->content_type, APPLICATION_APPLEFILE)) + { + if (msd && msd->channel) + msd->channel->SetContentType(NS_LITERAL_CSTRING(APPLICATION_APPLEFILE)); + } + } +#endif + if (status < 0) return status; } diff --git a/mailnews/moz.build b/mailnews/moz.build index 55b80c443a..6e75c8012e 100644 --- a/mailnews/moz.build +++ b/mailnews/moz.build @@ -23,6 +23,11 @@ DIRS += [ 'news', ] +if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + DIRS += [ + 'import/applemail/src', + ] + if CONFIG['OS_ARCH'] == 'WINNT': DIRS += [ 'import/becky/src' ] diff --git a/memory/mozalloc/mozalloc.h b/memory/mozalloc/mozalloc.h index 50dc53e5ce..f42c7b04a0 100644 --- a/memory/mozalloc/mozalloc.h +++ b/memory/mozalloc/mozalloc.h @@ -1,4 +1,6 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: sw=4 ts=4 et : + */ /* 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/. */ @@ -150,9 +152,13 @@ MFBT_API void* moz_xvalloc(size_t size) */ /* NB: This is defined just to silence vacuous warnings about symbol - * visibility on gcc. These symbols are force-inline and not exported. - */ -#define MOZALLOC_EXPORT_NEW + * visibility on OS X/gcc. These symbols are force-inline and not + * exported. */ +#if defined(XP_MACOSX) +# define MOZALLOC_EXPORT_NEW MFBT_API +#else +# define MOZALLOC_EXPORT_NEW +#endif #if defined(_MSC_VER) /* diff --git a/mfbt/ThreadLocal.h b/mfbt/ThreadLocal.h index 9466630c30..7acfa46548 100644 --- a/mfbt/ThreadLocal.h +++ b/mfbt/ThreadLocal.h @@ -30,7 +30,7 @@ typedef sig_atomic_t sig_safe_t; namespace detail { -#if defined(HAVE_THREAD_TLS_KEYWORD) || defined(XP_WIN) +#if defined(HAVE_THREAD_TLS_KEYWORD) || defined(XP_WIN) || defined(XP_MACOSX) #define MOZ_HAS_THREAD_LOCAL #endif @@ -180,7 +180,7 @@ ThreadLocal<T>::set(const T aValue) } #ifdef MOZ_HAS_THREAD_LOCAL -#if defined(XP_WIN) +#if defined(XP_WIN) || defined(XP_MACOSX) #define MOZ_THREAD_LOCAL(TYPE) thread_local mozilla::detail::ThreadLocal<TYPE> #else #define MOZ_THREAD_LOCAL(TYPE) __thread mozilla::detail::ThreadLocal<TYPE> diff --git a/modules/libmar/tool/mar.c b/modules/libmar/tool/mar.c index 8c9a05ec4d..f1dd761367 100644 --- a/modules/libmar/tool/mar.c +++ b/modules/libmar/tool/mar.c @@ -1,4 +1,5 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ /* 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/. */ @@ -61,7 +62,7 @@ static void print_usage() { "signed_input_archive.mar base_64_encoded_signature_file " "changed_signed_output.mar\n"); printf("(i) is the index of the certificate to extract\n"); -#if (defined(XP_WIN) && !defined(MAR_NSS)) +#if defined(XP_MACOSX) || (defined(XP_WIN) && !defined(MAR_NSS)) printf("Verify a MAR file:\n"); printf(" mar [-C workingDir] -D DERFilePath -v signed_archive.mar\n"); printf("At most %d signature certificate DER files are specified by " @@ -125,10 +126,11 @@ int main(int argc, char **argv) { #if !defined(NO_SIGN_VERIFY) uint32_t fileSizes[MAX_SIGNATURES]; const uint8_t* certBuffers[MAX_SIGNATURES]; -#if defined(XP_WIN) && !defined(MAR_NSS) +#if ((!defined(MAR_NSS) && defined(XP_WIN)) || defined(XP_MACOSX)) || \ + ((defined(XP_WIN) || defined(XP_MACOSX)) && !defined(MAR_NSS)) char* DERFilePaths[MAX_SIGNATURES]; #endif -#if !defined(XP_WIN) || defined(MAR_NSS) +#if (!defined(XP_WIN) && !defined(XP_MACOSX)) || defined(MAR_NSS) CERTCertificate* certs[MAX_SIGNATURES]; #endif #endif @@ -137,7 +139,8 @@ int main(int argc, char **argv) { #if defined(XP_WIN) && !defined(MAR_NSS) && !defined(NO_SIGN_VERIFY) memset((void*)certBuffers, 0, sizeof(certBuffers)); #endif -#if !defined(NO_SIGN_VERIFY) && (!defined(MAR_NSS) && defined(XP_WIN)) +#if !defined(NO_SIGN_VERIFY) && ((!defined(MAR_NSS) && defined(XP_WIN)) || \ + defined(XP_MACOSX)) memset(DERFilePaths, 0, sizeof(DERFilePaths)); memset(fileSizes, 0, sizeof(fileSizes)); #endif @@ -168,7 +171,8 @@ int main(int argc, char **argv) { argv += 2; argc -= 2; } -#if !defined(NO_SIGN_VERIFY) && (!defined(MAR_NSS) && defined(XP_WIN)) +#if !defined(NO_SIGN_VERIFY) && ((!defined(MAR_NSS) && defined(XP_WIN)) || \ + defined(XP_MACOSX)) /* -D DERFilePath, also matches -D[index] DERFilePath We allow an index for verifying to be symmetric with the import and export command line arguments. */ @@ -326,7 +330,7 @@ int main(int argc, char **argv) { return -1; } -#if !defined(XP_WIN) || defined(MAR_NSS) +#if (!defined(XP_WIN) && !defined(XP_MACOSX)) || defined(MAR_NSS) if (!NSSConfigDir || certCount == 0) { print_usage(); return -1; @@ -340,7 +344,7 @@ int main(int argc, char **argv) { rv = 0; for (k = 0; k < certCount; ++k) { -#if defined(XP_WIN) && !defined(MAR_NSS) +#if (defined(XP_WIN) || defined(XP_MACOSX)) && !defined(MAR_NSS) rv = mar_read_entire_file(DERFilePaths[k], MAR_MAX_CERT_SIZE, &certBuffers[k], &fileSizes[k]); @@ -380,7 +384,7 @@ int main(int argc, char **argv) { } } for (k = 0; k < certCount; ++k) { -#if defined(XP_WIN) && !defined(MAR_NSS) +#if (defined(XP_WIN) || defined(XP_MACOSX)) && !defined(MAR_NSS) free((void*)certBuffers[k]); #else /* certBuffers[k] is owned by certs[k] so don't free it */ @@ -398,7 +402,7 @@ int main(int argc, char **argv) { " no signature to verify.\n"); } } -#if !defined(XP_WIN) || defined(MAR_NSS) +#if (!defined(XP_WIN) && !defined(XP_MACOSX)) || defined(MAR_NSS) (void) NSS_Shutdown(); #endif return rv ? -1 : 0; diff --git a/modules/libmar/verify/cryptox.h b/modules/libmar/verify/cryptox.h index d6dceb366c..2296b815f4 100644 --- a/modules/libmar/verify/cryptox.h +++ b/modules/libmar/verify/cryptox.h @@ -57,7 +57,54 @@ CryptoX_Result NSS_VerifySignature(VFYContext * const *ctx , #define CryptoX_FreeCertificate(cert) \ CERT_DestroyCertificate(*cert) -#if defined(XP_WIN) +#elif XP_MACOSX + +#define CryptoX_InvalidHandleValue NULL +#define CryptoX_ProviderHandle void* +#define CryptoX_SignatureHandle void* +#define CryptoX_PublicKey void* +#define CryptoX_Certificate void* + +// Forward-declare Objective-C functions implemented in MacVerifyCrypto.mm. +#ifdef __cplusplus +extern "C" { +#endif +CryptoX_Result CryptoMac_InitCryptoProvider(); +CryptoX_Result CryptoMac_VerifyBegin(CryptoX_SignatureHandle* aInputData); +CryptoX_Result CryptoMac_VerifyUpdate(CryptoX_SignatureHandle* aInputData, + void* aBuf, unsigned int aLen); +CryptoX_Result CryptoMac_LoadPublicKey(const unsigned char* aCertData, + unsigned int aDataSize, + CryptoX_PublicKey* aPublicKey); +CryptoX_Result CryptoMac_VerifySignature(CryptoX_SignatureHandle* aInputData, + CryptoX_PublicKey* aPublicKey, + const unsigned char* aSignature, + unsigned int aSignatureLen); +void CryptoMac_FreeSignatureHandle(CryptoX_SignatureHandle* aInputData); +void CryptoMac_FreePublicKey(CryptoX_PublicKey* aPublicKey); +#ifdef __cplusplus +} // extern "C" +#endif + +#define CryptoX_InitCryptoProvider(aProviderHandle) \ + CryptoMac_InitCryptoProvider() +#define CryptoX_VerifyBegin(aCryptoHandle, aInputData, aPublicKey) \ + CryptoMac_VerifyBegin(aInputData) +#define CryptoX_VerifyUpdate(aInputData, aBuf, aLen) \ + CryptoMac_VerifyUpdate(aInputData, aBuf, aLen) +#define CryptoX_LoadPublicKey(aProviderHandle, aCertData, aDataSize, \ + aPublicKey) \ + CryptoMac_LoadPublicKey(aCertData, aDataSize, aPublicKey) +#define CryptoX_VerifySignature(aInputData, aPublicKey, aSignature, \ + aSignatureLen) \ + CryptoMac_VerifySignature(aInputData, aPublicKey, aSignature, aSignatureLen) +#define CryptoX_FreeSignatureHandle(aInputData) \ + CryptoMac_FreeSignatureHandle(aInputData) +#define CryptoX_FreePublicKey(aPublicKey) \ + CryptoMac_FreePublicKey(aPublicKey) +#define CryptoX_FreeCertificate(aCertificate) + +#elif defined(XP_WIN) #include <windows.h> #include <wincrypt.h> diff --git a/modules/libpref/Preferences.cpp b/modules/libpref/Preferences.cpp index 5f17125da9..53540bdf85 100644 --- a/modules/libpref/Preferences.cpp +++ b/modules/libpref/Preferences.cpp @@ -1291,7 +1291,9 @@ static nsresult pref_InitInitialObjects() /* these pref file names should not be used: we process them after all other application pref files for backwards compatibility */ static const char* specialFiles[] = { -#if defined(XP_WIN) +#if defined(XP_MACOSX) + "macprefs.js" +#elif defined(XP_WIN) "winpref.js" #elif defined(XP_UNIX) "unix.js" diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 42ccc24ba6..d0bc9269c7 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -398,7 +398,11 @@ pref("media.wmf.disable-d3d11-for-dlls", "igd11dxva64.dll: 20.19.15.4463, 20.19. pref("media.wmf.disable-d3d9-for-dlls", "igdumd64.dll: 8.15.10.2189, 8.15.10.2119, 8.15.10.2104, 8.15.10.2102, 8.771.1.0; atiumd64.dll: 7.14.10.833, 7.14.10.867, 7.14.10.885, 7.14.10.903, 7.14.10.911, 8.14.10.768, 9.14.10.1001, 9.14.10.1017, 9.14.10.1080, 9.14.10.1128, 9.14.10.1162, 9.14.10.1171, 9.14.10.1183, 9.14.10.1197, 9.14.10.945, 9.14.10.972, 9.14.10.984, 9.14.10.996"); #endif #if defined(MOZ_FFMPEG) +#if defined(XP_MACOSX) +pref("media.ffmpeg.enabled", false); +#else pref("media.ffmpeg.enabled", true); +#endif pref("media.libavcodec.allow-obsolete", false); #endif #if defined(MOZ_FFVPX) @@ -530,7 +534,11 @@ pref("media.getusermedia.agc", 1); // capture_delay: Adjustments for OS-specific input delay (lower bound) // playout_delay: Adjustments for OS-specific AudioStream+cubeb+output delay (lower bound) // full_duplex: enable cubeb full-duplex capture/playback -#if defined(XP_WIN) +#if defined(XP_MACOSX) +pref("media.peerconnection.capture_delay", 50); +pref("media.getusermedia.playout_delay", 10); +pref("media.navigator.audio.full_duplex", false); +#elif defined(XP_WIN) pref("media.peerconnection.capture_delay", 50); pref("media.getusermedia.playout_delay", 40); pref("media.navigator.audio.full_duplex", false); @@ -567,7 +575,7 @@ pref("media.mediasource.enabled", true); pref("media.mediasource.mp4.enabled", true); -#if defined(XP_WIN) +#if defined(XP_WIN) || defined(XP_MACOSX) pref("media.mediasource.webm.enabled", false); #else pref("media.mediasource.webm.enabled", true); @@ -695,6 +703,14 @@ pref("apz.scale_repaint_delay_ms", 500); pref("apz.desktop.enabled", false); #endif +#ifdef XP_MACOSX +// Whether to run in native HiDPI mode on machines with "Retina"/HiDPI display; +// <= 0 : hidpi mode disabled, display will just use pixel-based upscaling +// == 1 : hidpi supported if all screens share the same backingScaleFactor +// >= 2 : hidpi supported even with mixed backingScaleFactors (somewhat broken) +pref("gfx.hidpi.enabled", 2); +#endif + // Use containerless scrolling for now. pref("layout.scroll.root-frame-containers", false); @@ -709,8 +725,8 @@ pref("gfx.perf-warnings.enabled", false); // Color Management System // 0 = Off, 1 = All Images, 2 = Tagged Images Only. // See eCMSMode in gfx/thebes/gfxPlatform.h -// Enabled by default on Windows, disabled elsewhere -#if defined(XP_WIN) +// Enabled by default on Windows and Mac, disabled elsewhere +#if defined(XP_WIN) || defined(XP_MACOSX) pref("gfx.color_management.mode", 2); #else pref("gfx.color_management.mode", 0); @@ -768,10 +784,17 @@ pref("gfx.font_rendering.opentype_svg.enabled", true); pref("gfx.canvas.azure.backends", "direct2d1.1,skia,cairo"); pref("gfx.content.azure.backends", "direct2d1.1,cairo"); #else +#ifdef XP_MACOSX +pref("gfx.content.azure.backends", "cg"); +pref("gfx.canvas.azure.backends", "skia,cg"); +// Accelerated cg canvas where available (10.7+) +pref("gfx.canvas.azure.accelerated", true); +#else // Linux etc. pref("gfx.canvas.azure.backends", "skia,cairo"); pref("gfx.content.azure.backends", "cairo"); #endif +#endif pref("gfx.canvas.skiagl.dynamic-cache", true); @@ -793,6 +816,7 @@ pref("accessibility.warn_on_browsewithcaret", true); pref("accessibility.browsewithcaret_shortcut.enabled", true); +#ifndef XP_MACOSX // Tab focus model bit field: // 1 focuses text controls, 2 focuses other form elements, 4 adds links. // Most users will want 1, 3, or 7. @@ -800,11 +824,15 @@ pref("accessibility.browsewithcaret_shortcut.enabled", true); // unless accessibility.tabfocus is set by the user. pref("accessibility.tabfocus", 7); pref("accessibility.tabfocus_applies_to_xul", false); +#else +// Only on mac tabfocus is expected to handle UI widgets as well as web content +pref("accessibility.tabfocus_applies_to_xul", true); +#endif // We follow the "Click in the scrollbar to:" system preference on OS X and // "gtk-primary-button-warps-slider" property with GTK (since 2.24 / 3.6), // unless this preference is explicitly set. -#if !defined(MOZ_WIDGET_GTK) +#if !defined(XP_MACOSX) && !defined(MOZ_WIDGET_GTK) pref("ui.scrollToClick", 0); #endif @@ -868,7 +896,11 @@ pref("accessibility.typeaheadfind.timeout", 4000); pref("accessibility.typeaheadfind.enabletimeout", true); pref("accessibility.typeaheadfind.soundURL", "beep"); pref("accessibility.typeaheadfind.enablesound", true); +#ifdef XP_MACOSX +pref("accessibility.typeaheadfind.prefillwithselection", false); +#else pref("accessibility.typeaheadfind.prefillwithselection", true); +#endif pref("accessibility.typeaheadfind.matchesCountLimit", 1000); pref("findbar.highlightAll", false); pref("findbar.modalHighlight", false); @@ -1071,7 +1103,7 @@ pref("print.print_edge_right", 0); pref("print.print_edge_bottom", 0); // Print via the parent process. This is only used when e10s is enabled. -#if defined(XP_WIN) +#if defined(XP_WIN) || defined(XP_MACOSX) pref("print.print_via_parent", true); #else pref("print.print_via_parent", false); @@ -1333,6 +1365,9 @@ pref("network.protocol-handler.external.mk", false); pref("network.protocol-handler.external.res", false); pref("network.protocol-handler.external.shell", false); pref("network.protocol-handler.external.vnd.ms.radio", false); +#ifdef XP_MACOSX +pref("network.protocol-handler.external.help", false); +#endif pref("network.protocol-handler.external.disk", false); pref("network.protocol-handler.external.disks", false); pref("network.protocol-handler.external.afp", false); @@ -2507,7 +2542,13 @@ pref("layout.css.text-combine-upright-digits.enabled", false); // Is support for object-fit and object-position enabled? pref("layout.css.object-fit-and-position.enabled", true); +// Is -moz-osx-font-smoothing enabled? +// Only supported in OSX builds +#ifdef XP_MACOSX +pref("layout.css.osx-font-smoothing.enabled", true); +#else pref("layout.css.osx-font-smoothing.enabled", false); +#endif // Is support for the CSS-wide "unset" value enabled? pref("layout.css.unset-value.enabled", true); @@ -3505,6 +3546,328 @@ pref("ui.osk.debug.keyboardDisplayReason", ""); # XP_WIN #endif +#ifdef XP_MACOSX +// Mac specific preference defaults +pref("browser.drag_out_of_frame_style", 1); +pref("ui.key.saveLink.shift", false); // true = shift, false = meta + +pref("font.name-list.emoji", "Apple Color Emoji"); + +// default fonts (in UTF8 and using canonical names) +// to determine canonical font names, use a debug build and +// enable NSPR logging for module fontInfoLog:5 +// canonical names immediately follow '(fontinit) family:' in the log + +pref("font.name.serif.ar", "Al Bayan"); +pref("font.name.sans-serif.ar", "Geeza Pro"); +pref("font.name.monospace.ar", "Geeza Pro"); +pref("font.name.cursive.ar", "DecoType Naskh"); +pref("font.name.fantasy.ar", "KufiStandardGK"); +pref("font.name-list.serif.ar", "Al Bayan"); +pref("font.name-list.sans-serif.ar", "Geeza Pro"); +pref("font.name-list.monospace.ar", "Geeza Pro"); +pref("font.name-list.cursive.ar", "DecoType Naskh"); +pref("font.name-list.fantasy.ar", "KufiStandardGK"); + +pref("font.name.serif.el", "Times"); +pref("font.name.sans-serif.el", "Helvetica"); +pref("font.name.monospace.el", "Courier New"); +pref("font.name.cursive.el", "Lucida Grande"); +pref("font.name.fantasy.el", "Lucida Grande"); +pref("font.name-list.serif.el", "Times,Times New Roman"); +pref("font.name-list.sans-serif.el", "Helvetica,Lucida Grande"); +pref("font.name-list.monospace.el", "Courier New,Lucida Grande"); +pref("font.name-list.cursive.el", "Times,Lucida Grande"); +pref("font.name-list.fantasy.el", "Times,Lucida Grande"); + +pref("font.name.serif.he", "Times New Roman"); +pref("font.name.sans-serif.he", "Arial"); +pref("font.name.monospace.he", "Courier New"); +pref("font.name.cursive.he", "Times New Roman"); +pref("font.name.fantasy.he", "Times New Roman"); +pref("font.name-list.serif.he", "Times New Roman"); +pref("font.name-list.sans-serif.he", "Arial"); +pref("font.name-list.monospace.he", "Courier New"); +pref("font.name-list.cursive.he", "Times New Roman"); +pref("font.name-list.fantasy.he", "Times New Roman"); + +pref("font.name.serif.ja", "Hiragino Mincho ProN"); +pref("font.name.sans-serif.ja", "Hiragino Kaku Gothic ProN"); +pref("font.name.monospace.ja", "Osaka-Mono"); +pref("font.name-list.serif.ja", "Hiragino Mincho ProN,Hiragino Mincho Pro"); +pref("font.name-list.sans-serif.ja", "Hiragino Kaku Gothic ProN,Hiragino Kaku Gothic Pro"); +pref("font.name-list.monospace.ja", "Osaka-Mono"); + +pref("font.name.serif.ko", "AppleMyungjo"); +pref("font.name.sans-serif.ko", "Apple SD Gothic Neo"); +pref("font.name.monospace.ko", "Apple SD Gothic Neo"); +pref("font.name-list.serif.ko", "AppleMyungjo"); +pref("font.name-list.sans-serif.ko", "Apple SD Gothic Neo,AppleGothic"); +pref("font.name-list.monospace.ko", "Apple SD Gothic Neo,AppleGothic"); + +pref("font.name.serif.th", "Thonburi"); +pref("font.name.sans-serif.th", "Thonburi"); +pref("font.name.monospace.th", "Ayuthaya"); +pref("font.name-list.serif.th", "Thonburi"); +pref("font.name-list.sans-serif.th", "Thonburi"); +pref("font.name-list.monospace.th", "Ayuthaya"); + +pref("font.name.serif.x-armn", "Mshtakan"); +pref("font.name.sans-serif.x-armn", "Mshtakan"); +pref("font.name.monospace.x-armn", "Mshtakan"); +pref("font.name-list.serif.x-armn", "Mshtakan"); +pref("font.name-list.sans-serif.x-armn", "Mshtakan"); +pref("font.name-list.monospace.x-armn", "Mshtakan"); + +// SolaimanLipi, Rupali http://ekushey.org/?page/mac_download +pref("font.name.serif.x-beng", "Bangla MN"); +pref("font.name.sans-serif.x-beng", "Bangla Sangam MN"); +pref("font.name.monospace.x-beng", "Bangla Sangam MN"); +pref("font.name-list.serif.x-beng", "Bangla MN"); +pref("font.name-list.sans-serif.x-beng", "Bangla Sangam MN"); +pref("font.name-list.monospace.x-beng", "Bangla Sangam MN"); + +pref("font.name.serif.x-cans", "Euphemia UCAS"); +pref("font.name.sans-serif.x-cans", "Euphemia UCAS"); +pref("font.name.monospace.x-cans", "Euphemia UCAS"); +pref("font.name-list.serif.x-cans", "Euphemia UCAS"); +pref("font.name-list.sans-serif.x-cans", "Euphemia UCAS"); +pref("font.name-list.monospace.x-cans", "Euphemia UCAS"); + +pref("font.name.serif.x-cyrillic", "Times"); +pref("font.name.sans-serif.x-cyrillic", "Helvetica"); +pref("font.name.monospace.x-cyrillic", "Monaco"); +pref("font.name.cursive.x-cyrillic", "Geneva"); +pref("font.name.fantasy.x-cyrillic", "Charcoal CY"); +pref("font.name-list.serif.x-cyrillic", "Times,Times New Roman"); +pref("font.name-list.sans-serif.x-cyrillic", "Helvetica,Arial"); +pref("font.name-list.monospace.x-cyrillic", "Monaco,Courier New"); +pref("font.name-list.cursive.x-cyrillic", "Geneva"); +pref("font.name-list.fantasy.x-cyrillic", "Charcoal CY"); + +pref("font.name.serif.x-devanagari", "Devanagari MT"); +pref("font.name.sans-serif.x-devanagari", "Devanagari Sangam MN"); +pref("font.name.monospace.x-devanagari", "Devanagari Sangam MN"); +pref("font.name-list.serif.x-devanagari", "Devanagari MT"); +pref("font.name-list.sans-serif.x-devanagari", "Devanagari Sangam MN,Devanagari MT"); +pref("font.name-list.monospace.x-devanagari", "Devanagari Sangam MN,Devanagari MT"); + +// Abyssinica SIL http://scripts.sil.org/AbyssinicaSIL_Download +pref("font.name.serif.x-ethi", "Kefa"); +pref("font.name.sans-serif.x-ethi", "Kefa"); +pref("font.name.monospace.x-ethi", "Kefa"); +pref("font.name-list.serif.x-ethi", "Kefa,Abyssinica SIL"); +pref("font.name-list.sans-serif.x-ethi", "Kefa,Abyssinica SIL"); +pref("font.name-list.monospace.x-ethi", "Kefa,Abyssinica SIL"); + +// no suitable fonts for georgian ship with mac os x +// however some can be freely downloaded +// TITUS Cyberbit Basic http://titus.fkidg1.uni-frankfurt.de/unicode/tituut.asp +// Zuzumbo http://homepage.mac.com/rsiradze/FileSharing91.html +pref("font.name.serif.x-geor", "TITUS Cyberbit Basic"); +pref("font.name.sans-serif.x-geor", "Zuzumbo"); +pref("font.name.monospace.x-geor", "Zuzumbo"); +pref("font.name-list.serif.x-geor", "TITUS Cyberbit Basic"); +pref("font.name-list.sans-serif.x-geor", "Zuzumbo"); +pref("font.name-list.monospace.x-geor", "Zuzumbo"); + +pref("font.name.serif.x-gujr", "Gujarati MT"); +pref("font.name.sans-serif.x-gujr", "Gujarati Sangam MN"); +pref("font.name.monospace.x-gujr", "Gujarati Sangam MN"); +pref("font.name-list.serif.x-gujr", "Gujarati MT"); +pref("font.name-list.sans-serif.x-gujr", "Gujarati Sangam MN,Gujarati MT"); +pref("font.name-list.monospace.x-gujr", "Gujarati Sangam MN,Gujarati MT"); + +pref("font.name.serif.x-guru", "Gurmukhi MT"); +pref("font.name.sans-serif.x-guru", "Gurmukhi MT"); +pref("font.name.monospace.x-guru", "Gurmukhi MT"); +pref("font.name-list.serif.x-guru", "Gurmukhi MT"); +pref("font.name-list.sans-serif.x-guru", "Gurmukhi MT"); +pref("font.name-list.monospace.x-guru", "Gurmukhi MT"); + +pref("font.name.serif.x-khmr", "Khmer MN"); +pref("font.name.sans-serif.x-khmr", "Khmer Sangam MN"); +pref("font.name.monospace.x-khmr", "Khmer Sangam MN"); +pref("font.name-list.serif.x-khmr", "Khmer MN"); +pref("font.name-list.sans-serif.x-khmr", "Khmer Sangam MN"); +pref("font.name-list.monospace.x-khmr", "Khmer Sangam MN"); + +pref("font.name.serif.x-mlym", "Malayalam MN"); +pref("font.name.sans-serif.x-mlym", "Malayalam Sangam MN"); +pref("font.name.monospace.x-mlym", "Malayalam Sangam MN"); +pref("font.name-list.serif.x-mlym", "Malayalam MN"); +pref("font.name-list.sans-serif.x-mlym", "Malayalam Sangam MN"); +pref("font.name-list.monospace.x-mlym", "Malayalam Sangam MN"); + +pref("font.name.serif.x-orya", "Oriya MN"); +pref("font.name.sans-serif.x-orya", "Oriya Sangam MN"); +pref("font.name.monospace.x-orya", "Oriya Sangam MN"); +pref("font.name-list.serif.x-orya", "Oriya MN"); +pref("font.name-list.sans-serif.x-orya", "Oriya Sangam MN"); +pref("font.name-list.monospace.x-orya", "Oriya Sangam MN"); + +// Pothana http://web.nickshanks.com/typography/telugu/ +pref("font.name.serif.x-telu", "Telugu MN"); +pref("font.name.sans-serif.x-telu", "Telugu Sangam MN"); +pref("font.name.monospace.x-telu", "Telugu Sangam MN"); +pref("font.name-list.serif.x-telu", "Telugu MN,Pothana"); +pref("font.name-list.sans-serif.x-telu", "Telugu Sangam MN,Pothana"); +pref("font.name-list.monospace.x-telu", "Telugu Sangam MN,Pothana"); + +// Kedage http://web.nickshanks.com/typography/kannada/ +pref("font.name.serif.x-knda", "Kannada MN"); +pref("font.name.sans-serif.x-knda", "Kannada Sangam MN"); +pref("font.name.monospace.x-knda", "Kannada Sangam MN"); +pref("font.name-list.serif.x-knda", "Kannada MN,Kedage"); +pref("font.name-list.sans-serif.x-knda", "Kannada Sangam MN,Kedage"); +pref("font.name-list.monospace.x-knda", "Kannada Sangam MN,Kedage"); + +pref("font.name.serif.x-sinh", "Sinhala MN"); +pref("font.name.sans-serif.x-sinh", "Sinhala Sangam MN"); +pref("font.name.monospace.x-sinh", "Sinhala Sangam MN"); +pref("font.name-list.serif.x-sinh", "Sinhala MN"); +pref("font.name-list.sans-serif.x-sinh", "Sinhala Sangam MN"); +pref("font.name-list.monospace.x-sinh", "Sinhala Sangam MN"); + +pref("font.name.serif.x-tamil", "InaiMathi"); +pref("font.name.sans-serif.x-tamil", "InaiMathi"); +pref("font.name.monospace.x-tamil", "InaiMathi"); +pref("font.name-list.serif.x-tamil", "InaiMathi"); +pref("font.name-list.sans-serif.x-tamil", "InaiMathi"); +pref("font.name-list.monospace.x-tamil", "InaiMathi"); + +// Kailasa ships with mac os x >= 10.5 +pref("font.name.serif.x-tibt", "Kailasa"); +pref("font.name.sans-serif.x-tibt", "Kailasa"); +pref("font.name.monospace.x-tibt", "Kailasa"); +pref("font.name-list.serif.x-tibt", "Kailasa"); +pref("font.name-list.sans-serif.x-tibt", "Kailasa"); +pref("font.name-list.monospace.x-tibt", "Kailasa"); + +pref("font.name.serif.x-unicode", "Times"); +pref("font.name.sans-serif.x-unicode", "Helvetica"); +pref("font.name.monospace.x-unicode", "Courier"); +pref("font.name.cursive.x-unicode", "Apple Chancery"); +pref("font.name.fantasy.x-unicode", "Papyrus"); +pref("font.name-list.serif.x-unicode", "Times"); +pref("font.name-list.sans-serif.x-unicode", "Helvetica"); +pref("font.name-list.monospace.x-unicode", "Courier"); +pref("font.name-list.cursive.x-unicode", "Apple Chancery"); +pref("font.name-list.fantasy.x-unicode", "Papyrus"); + +pref("font.name.serif.x-western", "Times"); +pref("font.name.sans-serif.x-western", "Helvetica"); +pref("font.name.monospace.x-western", "Courier"); +pref("font.name.cursive.x-western", "Apple Chancery"); +pref("font.name.fantasy.x-western", "Papyrus"); +pref("font.name-list.serif.x-western", "Times,Times New Roman"); +pref("font.name-list.sans-serif.x-western", "Helvetica,Arial"); +pref("font.name-list.monospace.x-western", "Courier,Courier New"); +pref("font.name-list.cursive.x-western", "Apple Chancery"); +pref("font.name-list.fantasy.x-western", "Papyrus"); + +pref("font.name.serif.zh-CN", "Times"); +pref("font.name.sans-serif.zh-CN", "Helvetica"); +pref("font.name.monospace.zh-CN", "Courier"); +pref("font.name.cursive.zh-CN", "Kaiti SC"); +pref("font.name-list.serif.zh-CN", "Times,STSong,Heiti SC"); +pref("font.name-list.sans-serif.zh-CN", "Helvetica,PingFang SC,STHeiti,Heiti SC"); +pref("font.name-list.monospace.zh-CN", "Courier,PingFang SC,STHeiti,Heiti SC"); + +pref("font.name.serif.zh-TW", "Times"); +pref("font.name.sans-serif.zh-TW", "Helvetica"); +pref("font.name.monospace.zh-TW", "Courier"); +pref("font.name.cursive.zh-TW", "Kaiti TC"); +pref("font.name-list.serif.zh-TW", "Times,LiSong Pro,Heiti TC"); +pref("font.name-list.sans-serif.zh-TW", "Helvetica,PingFang TC,Heiti TC,LiHei Pro"); +pref("font.name-list.monospace.zh-TW", "Courier,PingFang TC,Heiti TC,LiHei Pro"); + +pref("font.name.serif.zh-HK", "Times"); +pref("font.name.sans-serif.zh-HK", "Helvetica"); +pref("font.name.monospace.zh-HK", "Courier"); +pref("font.name.cursive.zh-HK", "Kaiti TC"); +pref("font.name-list.serif.zh-HK", "Times,LiSong Pro,Heiti TC"); +pref("font.name-list.sans-serif.zh-HK", "Helvetica,PingFang TC,Heiti TC,LiHei Pro"); +pref("font.name-list.monospace.zh-HK", "Courier,PingFang TC,Heiti TC,LiHei Pro"); + +// XP_MACOSX changes to default font sizes +pref("font.minimum-size.th", 10); +pref("font.size.variable.zh-CN", 15); +pref("font.size.variable.zh-HK", 15); +pref("font.size.variable.zh-TW", 15); + +pref("font.name.serif.x-math", "Latin Modern Math"); +// Apple's Symbol is Unicode so use it +pref("font.name-list.serif.x-math", "Latin Modern Math, XITS Math, Cambria Math, Libertinus Math, DejaVu Math TeX Gyre, TeX Gyre Bonum Math, TeX Gyre Pagella Math, TeX Gyre Schola, TeX Gyre Termes Math, STIX Math, Asana Math, STIXGeneral, DejaVu Serif, DejaVu Sans, Symbol, Times"); +pref("font.name.sans-serif.x-math", "Helvetica"); +pref("font.name.monospace.x-math", "Courier"); +pref("font.name.cursive.x-math", "Apple Chancery"); +pref("font.name.fantasy.x-math", "Papyrus"); + +// Individual font faces to be treated as independent families, +// listed as <Postscript name of face:Owning family name> +pref("font.single-face-list", "Osaka-Mono:Osaka"); + +// optimization hint for fonts with localized names to be read in at startup, otherwise read in at lookup miss +// names are canonical family names (typically English names) +pref("font.preload-names-list", "Hiragino Kaku Gothic ProN,Hiragino Mincho ProN,STSong"); + +// Override font-weight values for some problematic families Apple ships +// (see bug 931426). +// The name here is the font's PostScript name, which can be checked in +// the Font Book utility or other tools. +pref("font.weight-override.AppleSDGothicNeo-Thin", 100); // Ensure Thin < UltraLight < Light +pref("font.weight-override.AppleSDGothicNeo-UltraLight", 200); +pref("font.weight-override.AppleSDGothicNeo-Light", 300); +pref("font.weight-override.AppleSDGothicNeo-Heavy", 900); // Ensure Heavy > ExtraBold (800) + +pref("font.weight-override.Avenir-Book", 300); // Ensure Book < Roman (400) +pref("font.weight-override.Avenir-BookOblique", 300); +pref("font.weight-override.Avenir-MediumOblique", 500); // Harmonize MediumOblique with Medium +pref("font.weight-override.Avenir-Black", 900); // Ensure Black > Heavy (800) +pref("font.weight-override.Avenir-BlackOblique", 900); + +pref("font.weight-override.AvenirNext-MediumItalic", 500); // Harmonize MediumItalic with Medium +pref("font.weight-override.AvenirNextCondensed-MediumItalic", 500); + +pref("font.weight-override.HelveticaNeue-Light", 300); // Ensure Light > Thin (200) +pref("font.weight-override.HelveticaNeue-LightItalic", 300); +pref("font.weight-override.HelveticaNeue-MediumItalic", 500); // Harmonize MediumItalic with Medium + +// Override the Windows settings: no menu key, meta accelerator key. ctrl for general access key in HTML/XUL +// Use 17 for Ctrl, 18 for Option, 224 for Cmd, 0 for none +pref("ui.key.menuAccessKey", 0); +pref("ui.key.accelKey", 224); +// (pinkerton, joki, saari) IE5 for mac uses Control for access keys. The HTML4 spec +// suggests to use command on mac, but this really sucks (imagine someone having a "q" +// as an access key and not letting you quit the app!). As a result, we've made a +// command decision 1 day before tree lockdown to change it to the control key. +pref("ui.key.generalAccessKey", -1); + +// If generalAccessKey is -1, use the following two prefs instead. +// Use 0 for disabled, 1 for Shift, 2 for Ctrl, 4 for Alt, 8 for Meta (Cmd) +// (values can be combined, e.g. 3 for Ctrl+Shift) +pref("ui.key.chromeAccess", 2); +pref("ui.key.contentAccess", 6); + +// print_extra_margin enables platforms to specify an extra gap or margin +// around the content of the page for Print Preview only +pref("print.print_extra_margin", 90); // twips (90 twips is an eigth of an inch) + +// See bug 404131, topmost <panel> element wins to Dashboard on MacOSX. +pref("ui.panel.default_level_parent", false); + +pref("ui.plugin.cancel_composition_at_input_source_changed", false); + +pref("mousewheel.system_scroll_override_on_root_content.enabled", false); + +// Macbook touchpad two finger pixel scrolling +pref("mousewheel.enable_pixel_scrolling", true); + +# XP_MACOSX +#endif + +#ifndef XP_MACOSX #ifdef XP_UNIX // Handled differently under Mac/Windows pref("network.protocol-handler.warn-external.file", false); @@ -3714,6 +4077,7 @@ pref("gfx.font_rendering.fontconfig.max_generic_substitutions", 3); # XP_UNIX #endif +#endif #if OS_ARCH==AIX @@ -3853,6 +4217,9 @@ pref("canvas.poisondata", false); // WebGL prefs pref("gl.msaa-level", 2); pref("gl.require-hardware", false); +#ifdef XP_MACOSX +pref("gl.multithreaded", true); +#endif pref("gl.ignore-dx-interop2-blacklist", false); pref("webgl.force-enabled", false); @@ -3912,17 +4279,17 @@ pref("network.tcp.keepalive.enabled", true); pref("network.tcp.keepalive.idle_time", 600); // seconds; 10 mins // Default timeout for retransmission of unack'd keepalive probes. // Win and Linux only; not configurable on Mac. -#if defined(XP_UNIX) || defined(XP_WIN) +#if defined(XP_UNIX) && !defined(XP_MACOSX) || defined(XP_WIN) pref("network.tcp.keepalive.retry_interval", 1); // seconds #endif // Default maximum probe retransmissions. // Linux only; not configurable on Win and Mac; fixed at 10 and 8 respectively. -#if defined(XP_UNIX) +#if defined(XP_UNIX) && !defined(XP_MACOSX) pref("network.tcp.keepalive.probe_count", 4); #endif // Whether to disable acceleration for all widgets. -#if defined(XP_UNIX) +#if defined(XP_UNIX) && !defined(XP_MACOSX) // On Linux this is disabled by default for known issues with "free" drivers pref("layers.acceleration.enabled", false); #else @@ -3979,6 +4346,13 @@ pref("layers.tiles.adjust", true); // 0 -> full-tilt mode: Recomposite even if not transaction occured. pref("layers.offmainthreadcomposition.frame-rate", -1); +#ifdef XP_MACOSX +pref("layers.enable-tiles", true); +pref("layers.tile-width", 512); +pref("layers.tile-height", 512); +pref("layers.tiles.edge-padding", false); +#endif + // Whether to animate simple opacity and transforms on the compositor pref("layers.offmainthreadcomposition.async-animations", true); @@ -4022,6 +4396,11 @@ pref("layers.shared-buffer-provider.enabled", true); pref("layers.shared-buffer-provider.enabled", false); #endif +#ifdef XP_MACOSX +// cf. Bug 1324908 +pref("layers.shared-buffer-provider.enabled", false); +#endif + // Force all possible layers to be always active layers pref("layers.force-active", false); @@ -4178,7 +4557,11 @@ pref("dom.mozPermissionSettings.enabled", false); // W3C touch events // 0 - disabled, 1 - enabled, 2 - autodetect // Autodetection is currently only supported on Windows and GTK3 +#if defined(XP_MACOSX) +pref("dom.w3c_touch_events.enabled", 0); +#else pref("dom.w3c_touch_events.enabled", 2); +#endif // W3C draft pointer events pref("dom.w3c_pointer_events.enabled", true); @@ -4438,6 +4821,15 @@ pref("dom.udpsocket.enabled", false); // Disable before keyboard events and after keyboard events by default. pref("dom.beforeAfterKeyboardEvent.enabled", false); +#ifdef XP_MACOSX +#if defined(DEBUG) +// In debug builds we crash by default on insecure text input (when a +// password editor has focus but secure event input isn't enabled). The +// following pref, when turned on, disables this behavior. See bug 1188425. +pref("intl.allow-insecure-text-input", false); +#endif +#endif // XP_MACOSX + // Enable meta-viewport support in remote APZ-enabled frames. pref("dom.meta-viewport.enabled", false); diff --git a/mozglue/misc/StackWalk.cpp b/mozglue/misc/StackWalk.cpp index 0fa2250aec..7d853b075d 100644 --- a/mozglue/misc/StackWalk.cpp +++ b/mozglue/misc/StackWalk.cpp @@ -939,7 +939,7 @@ MozDescribeCodeAddress(void* aPC, MozCodeAddressDetails* aDetails) #endif -#if defined(XP_WIN) || defined (XP_LINUX) +#if defined(XP_WIN) || defined (XP_MACOSX) || defined (XP_LINUX) namespace mozilla { bool FramePointerStackWalk(MozWalkStackCallback aCallback, uint32_t aSkipFrames, @@ -963,8 +963,8 @@ FramePointerStackWalk(MozWalkStackCallback aCallback, uint32_t aSkipFrames, (uintptr_t(next) & 3)) { break; } -#if defined(__powerpc64__) - // powerpc64 linux +#if (defined(__ppc__) && defined(XP_MACOSX)) || defined(__powerpc64__) + // ppc mac or powerpc64 linux void* pc = *(bp + 2); bp += 3; #else // i386 or powerpc32 linux diff --git a/python/mozbuild/mozbuild/artifacts.py b/python/mozbuild/mozbuild/artifacts.py index 563fcb9ff0..02538938fb 100644 --- a/python/mozbuild/mozbuild/artifacts.py +++ b/python/mozbuild/mozbuild/artifacts.py @@ -818,6 +818,10 @@ class Artifacts(object): return ('linux64' if target_64bit else 'linux') + target_suffix if self._defines.get('XP_WIN', False): return ('win64' if target_64bit else 'win32') + target_suffix + if self._defines.get('XP_MACOSX', False): + # We only produce unified builds in automation, so the target_cpu + # check is not relevant. + return 'macosx64' + target_suffix raise Exception('Cannot determine default job for |mach artifact|!') def _pushheads_from_rev(self, rev, count): diff --git a/toolkit/components/apppicker/content/appPicker.js b/toolkit/components/apppicker/content/appPicker.js index 6922fce39f..21a007632b 100644 --- a/toolkit/components/apppicker/content/appPicker.js +++ b/toolkit/components/apppicker/content/appPicker.js @@ -119,6 +119,12 @@ AppPicker.prototype = return file.getVersionInfoField("FileDescription"); } catch (e) {} } +#elifdef XP_MACOSX + if (file instanceof Components.interfaces.nsILocalFileMac) { + try { + return file.bundleDisplayName; + } catch (e) {} + } #endif return file.leafName; }, @@ -177,6 +183,8 @@ AppPicker.prototype = var startLocation; #ifdef XP_WIN startLocation = "ProgF"; // Program Files +#elifdef XP_MACOSX + startLocation = "LocApp"; // Local Applications #else startLocation = "Home"; #endif diff --git a/toolkit/components/blocklist/nsBlocklistService.js b/toolkit/components/blocklist/nsBlocklistService.js index 188fdfb387..f016fe6cdc 100644 --- a/toolkit/components/blocklist/nsBlocklistService.js +++ b/toolkit/components/blocklist/nsBlocklistService.js @@ -114,6 +114,15 @@ XPCOMUtils.defineLazyGetter(this, "gABI", function() { LOG("BlockList Global gABI: XPCOM ABI unknown."); } +#ifdef XP_MACOSX + // Mac universal build should report a different ABI than either macppc + // or mactel. + let macutils = Cc["@mozilla.org/xpcom/mac-utils;1"]. + getService(Ci.nsIMacUtils); + + if (macutils.isUniversalBinary) + abi += "-u-" + macutils.architecturesInBinary; +#endif return abi; }); diff --git a/toolkit/components/downloads/nsDownloadManager.cpp b/toolkit/components/downloads/nsDownloadManager.cpp index bc01b9ae58..587c1ac8ab 100644 --- a/toolkit/components/downloads/nsDownloadManager.cpp +++ b/toolkit/components/downloads/nsDownloadManager.cpp @@ -57,6 +57,10 @@ #endif #endif +#ifdef XP_MACOSX +#include <CoreFoundation/CoreFoundation.h> +#endif + #ifdef MOZ_WIDGET_GTK #include <gtk/gtk.h> #endif @@ -1372,7 +1376,12 @@ nsDownloadManager::GetDefaultDownloadsDirectory(nsIFile **aResult) mBundle->GetStringFromName(u"downloadsFolder", getter_Copies(folderName)); -#if defined(XP_WIN) +#if defined (XP_MACOSX) + rv = dirService->Get(NS_OSX_DEFAULT_DOWNLOAD_DIR, + NS_GET_IID(nsIFile), + getter_AddRefs(downloadDir)); + NS_ENSURE_SUCCESS(rv, rv); +#elif defined(XP_WIN) rv = dirService->Get(NS_WIN_DEFAULT_DOWNLOAD_DIR, NS_GET_IID(nsIFile), getter_AddRefs(downloadDir)); @@ -2436,11 +2445,19 @@ nsDownloadManager::Observe(nsISupports *aSubject, nsCOMPtr<nsISupportsPRBool> cancelDownloads = do_QueryInterface(aSubject, &rv); NS_ENSURE_SUCCESS(rv, rv); +#ifndef XP_MACOSX ConfirmCancelDownloads(currDownloadCount, cancelDownloads, u"quitCancelDownloadsAlertTitle", u"quitCancelDownloadsAlertMsgMultiple", u"quitCancelDownloadsAlertMsg", u"dontQuitButtonWin"); +#else + ConfirmCancelDownloads(currDownloadCount, cancelDownloads, + u"quitCancelDownloadsAlertTitle", + u"quitCancelDownloadsAlertMsgMacMultiple", + u"quitCancelDownloadsAlertMsgMac", + u"dontQuitButtonMac"); +#endif } else if (strcmp(aTopic, "offline-requested") == 0 && currDownloadCount) { nsCOMPtr<nsISupportsPRBool> cancelDownloads = do_QueryInterface(aSubject, &rv); @@ -2730,7 +2747,7 @@ nsDownload::SetState(DownloadState aState) } } -#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) +#if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK) nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(mTarget); nsCOMPtr<nsIFile> file; nsAutoString path; @@ -2740,6 +2757,7 @@ nsDownload::SetState(DownloadState aState) file && NS_SUCCEEDED(file->GetPath(path))) { +#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) // On Windows and Gtk, add the download to the system's "recent documents" // list, with a pref to disable. { @@ -2777,6 +2795,18 @@ nsDownload::SetState(DownloadState aState) g_object_unref(gio_file); #endif } +#endif + +#ifdef XP_MACOSX + // On OS X, make the downloads stack bounce. + CFStringRef observedObject = ::CFStringCreateWithCString(kCFAllocatorDefault, + NS_ConvertUTF16toUTF8(path).get(), + kCFStringEncodingUTF8); + CFNotificationCenterRef center = ::CFNotificationCenterGetDistributedCenter(); + ::CFNotificationCenterPostNotification(center, CFSTR("com.apple.DownloadFileFinished"), + observedObject, nullptr, TRUE); + ::CFRelease(observedObject); +#endif } #ifdef XP_WIN @@ -3359,10 +3389,14 @@ nsDownload::OpenWithApplication() if (!prefs || NS_FAILED(prefs->GetBoolPref(PREF_BH_DELETETEMPFILEONEXIT, &deleteTempFileOnExit))) { // No prefservice or no pref set; use default value - // Some users have been very verbal about temp files being deleted on +#if !defined(XP_MACOSX) + // Mac users have been very verbal about temp files being deleted on // app exit - they don't like it - but we'll continue to do this on - // all platforms for now. + // other platforms for now. deleteTempFileOnExit = true; +#else + deleteTempFileOnExit = false; +#endif } // Always schedule files to be deleted at the end of the private browsing diff --git a/toolkit/components/jsdownloads/src/DownloadIntegration.jsm b/toolkit/components/jsdownloads/src/DownloadIntegration.jsm index 8b5c644987..22a6570dac 100644 --- a/toolkit/components/jsdownloads/src/DownloadIntegration.jsm +++ b/toolkit/components/jsdownloads/src/DownloadIntegration.jsm @@ -294,7 +294,9 @@ this.DownloadIntegration = { } let directoryPath = null; -#ifdef XP_WIN +#ifdef XP_MACOSX + directoryPath = this._getDirectory("DfltDwnld"); +#elifdef XP_WIN // For XP/2K, use My Documents/Downloads. Other version uses // the default Downloads directory. let version = parseFloat(Services.sysinfo.getProperty("version")); @@ -363,7 +365,11 @@ this.DownloadIntegration = { */ getTemporaryDownloadsDirectory: Task.async(function* () { let directoryPath = null; +#ifdef XP_MACOSX + directoryPath = yield this.getPreferredDownloadsDirectory(); +#else directoryPath = this._getDirectory("TmpD"); +#endif return directoryPath; }), diff --git a/toolkit/components/jsdownloads/src/DownloadPlatform.cpp b/toolkit/components/jsdownloads/src/DownloadPlatform.cpp index 14277e5bd4..66ad2b8fa8 100644 --- a/toolkit/components/jsdownloads/src/DownloadPlatform.cpp +++ b/toolkit/components/jsdownloads/src/DownloadPlatform.cpp @@ -25,6 +25,11 @@ #include "nsILocalFileWin.h" #endif +#ifdef XP_MACOSX +#include <CoreFoundation/CoreFoundation.h> +#include "../../../../xpcom/io/CocoaFileUtils.h" +#endif + #ifdef MOZ_WIDGET_GTK #include <gtk/gtk.h> #endif @@ -64,13 +69,39 @@ static void gio_set_metadata_done(GObject *source_obj, GAsyncResult *res, gpoint } #endif +#ifdef XP_MACOSX +// Caller is responsible for freeing any result (CF Create Rule) +CFURLRef CreateCFURLFromNSIURI(nsIURI *aURI) { + nsAutoCString spec; + if (aURI) { + aURI->GetSpec(spec); + } + + CFStringRef urlStr = ::CFStringCreateWithCString(kCFAllocatorDefault, + spec.get(), + kCFStringEncodingUTF8); + if (!urlStr) { + return NULL; + } + + CFURLRef url = ::CFURLCreateWithString(kCFAllocatorDefault, + urlStr, + NULL); + + ::CFRelease(urlStr); + + return url; +} +#endif + nsresult DownloadPlatform::DownloadDone(nsIURI* aSource, nsIURI* aReferrer, nsIFile* aTarget, const nsACString& aContentType, bool aIsPrivate) { -#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) +#if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK) nsAutoString path; if (aTarget && NS_SUCCEEDED(aTarget->GetPath(path))) { +#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) // On Windows and Gtk, add the download to the system's "recent documents" // list, with a pref to disable. { @@ -105,10 +136,53 @@ nsresult DownloadPlatform::DownloadDone(nsIURI* aSource, nsIURI* aReferrer, nsIF nullptr, gio_set_metadata_done, nullptr); g_object_unref(file_info); g_object_unref(gio_file); -#endif // MOZ_ENABLE_GIO +#endif } +#endif + +#ifdef XP_MACOSX + // On OS X, make the downloads stack bounce. + CFStringRef observedObject = ::CFStringCreateWithCString(kCFAllocatorDefault, + NS_ConvertUTF16toUTF8(path).get(), + kCFStringEncodingUTF8); + CFNotificationCenterRef center = ::CFNotificationCenterGetDistributedCenter(); + ::CFNotificationCenterPostNotification(center, CFSTR("com.apple.DownloadFileFinished"), + observedObject, nullptr, TRUE); + ::CFRelease(observedObject); + + // Add OS X origin and referrer file metadata + CFStringRef pathCFStr = NULL; + if (!path.IsEmpty()) { + pathCFStr = ::CFStringCreateWithCharacters(kCFAllocatorDefault, + (const UniChar*)path.get(), + path.Length()); + } + if (pathCFStr) { + bool isFromWeb = IsURLPossiblyFromWeb(aSource); + + CFURLRef sourceCFURL = CreateCFURLFromNSIURI(aSource); + CFURLRef referrerCFURL = CreateCFURLFromNSIURI(aReferrer); + + CocoaFileUtils::AddOriginMetadataToFile(pathCFStr, + sourceCFURL, + referrerCFURL); + CocoaFileUtils::AddQuarantineMetadataToFile(pathCFStr, + sourceCFURL, + referrerCFURL, + isFromWeb); + + ::CFRelease(pathCFStr); + if (sourceCFURL) { + ::CFRelease(sourceCFURL); + } + if (referrerCFURL) { + ::CFRelease(referrerCFURL); + } + } +#endif } -#endif // defined(XP_WIN) || defined(MOZ_WIDGET_GTK) + +#endif return NS_OK; } diff --git a/toolkit/components/jsdownloads/src/DownloadUIHelper.jsm b/toolkit/components/jsdownloads/src/DownloadUIHelper.jsm index 860a325d4b..3039525f5f 100644 --- a/toolkit/components/jsdownloads/src/DownloadUIHelper.jsm +++ b/toolkit/components/jsdownloads/src/DownloadUIHelper.jsm @@ -184,10 +184,17 @@ this.DownloadPrompter.prototype = { switch (aPromptType) { case this.ON_QUIT: title = s.quitCancelDownloadsAlertTitle; +#ifdef XP_MACOSX + message = aDownloadsCount > 1 + ? s.quitCancelDownloadsAlertMsgMacMultiple(aDownloadsCount) + : s.quitCancelDownloadsAlertMsgMac; + cancelButton = s.dontQuitButtonMac; +#else message = aDownloadsCount > 1 ? s.quitCancelDownloadsAlertMsgMultiple(aDownloadsCount) : s.quitCancelDownloadsAlertMsg; cancelButton = s.dontQuitButtonWin; +#endif break; case this.ON_OFFLINE: title = s.offlineCancelDownloadsAlertTitle; diff --git a/toolkit/components/jsdownloads/src/moz.build b/toolkit/components/jsdownloads/src/moz.build index 115435f641..5a08340ae2 100644 --- a/toolkit/components/jsdownloads/src/moz.build +++ b/toolkit/components/jsdownloads/src/moz.build @@ -18,11 +18,11 @@ EXTRA_JS_MODULES += [ 'DownloadList.jsm', 'Downloads.jsm', 'DownloadStore.jsm', - 'DownloadUIHelper.jsm', ] EXTRA_PP_JS_MODULES += [ 'DownloadIntegration.jsm', + 'DownloadUIHelper.jsm', ] FINAL_LIBRARY = 'xul' diff --git a/toolkit/components/passwordmgr/content/passwordManager.js b/toolkit/components/passwordmgr/content/passwordManager.js index 4db3e81b9a..2d71d05f64 100644 --- a/toolkit/components/passwordmgr/content/passwordManager.js +++ b/toolkit/components/passwordmgr/content/passwordManager.js @@ -479,7 +479,12 @@ function HandleSignonKeyPress(e) { return; } +#ifdef XP_MACOSX + if (e.keyCode == KeyboardEvent.DOM_VK_DELETE || + e.keyCode == KeyboardEvent.DOM_VK_BACK_SPACE) { +#else if (e.keyCode == KeyboardEvent.DOM_VK_DELETE) { +#endif DeleteSignon(); } } diff --git a/toolkit/components/passwordmgr/content/passwordManager.xul b/toolkit/components/passwordmgr/content/passwordManager.xul index b2713ae6c7..8590d96aca 100644 --- a/toolkit/components/passwordmgr/content/passwordManager.xul +++ b/toolkit/components/passwordmgr/content/passwordManager.xul @@ -1,4 +1,4 @@ -<?xml version="1.0"?> <!-- -*- Mode: XML; indent-tabs-mode: nil -*- --> +<?xml version="1.0"?> <!-- -*- Mode: SGML; indent-tabs-mode: nil -*- --> # 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/. @@ -126,8 +126,10 @@ <hbox align="end"> <hbox class="actionButtons" flex="1"> <spacer flex="1"/> +#ifndef XP_MACOSX <button oncommand="close();" icon="close" label="&closebutton.label;" accesskey="&closebutton.accesskey;"/> +#endif </hbox> </hbox> </window> diff --git a/toolkit/components/perfmonitoring/nsPerformanceStats.cpp b/toolkit/components/perfmonitoring/nsPerformanceStats.cpp index 15a021bbab..59d84ced15 100644 --- a/toolkit/components/perfmonitoring/nsPerformanceStats.cpp +++ b/toolkit/components/perfmonitoring/nsPerformanceStats.cpp @@ -35,7 +35,14 @@ #include <unistd.h> #endif // defined(XP_WIN) -#if defined(XP_UNIX) +#if defined(XP_MACOSX) +#include <mach/mach_init.h> +#include <mach/mach_interface.h> +#include <mach/mach_port.h> +#include <mach/mach_types.h> +#include <mach/message.h> +#include <mach/thread_info.h> +#elif defined(XP_UNIX) #include <sys/time.h> #include <sys/resource.h> #endif // defined(XP_UNIX) @@ -1232,7 +1239,30 @@ nsPerformanceStatsService::GetResources(uint64_t* userTime, MOZ_ASSERT(userTime); MOZ_ASSERT(systemTime); -#if defined(XP_UNIX) +#if defined(XP_MACOSX) + // On MacOS X, to get we per-thread data, we need to + // reach into the kernel. + + mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT; + thread_basic_info_data_t info; + mach_port_t port = mach_thread_self(); + kern_return_t err = + thread_info(/* [in] targeted thread*/ port, + /* [in] nature of information*/ THREAD_BASIC_INFO, + /* [out] thread information */ (thread_info_t)&info, + /* [inout] number of items */ &count); + + // We do not need ability to communicate with the thread, so + // let's release the port. + mach_port_deallocate(mach_task_self(), port); + + if (err != KERN_SUCCESS) + return NS_ERROR_FAILURE; + + *userTime = info.user_time.microseconds + info.user_time.seconds * 1000000; + *systemTime = info.system_time.microseconds + info.system_time.seconds * 1000000; + +#elif defined(XP_UNIX) struct rusage rusage; #if defined(RUSAGE_THREAD) // Under Linux, we can obtain per-thread statistics @@ -1276,7 +1306,7 @@ nsPerformanceStatsService::GetResources(uint64_t* userTime, // Convert 100 ns to 1 us. *userTime = userTimeInt.QuadPart / 10; -#endif // defined(XP_UNIX) || defined(XP_WIN) +#endif // defined(XP_MACOSX) || defined(XP_UNIX) || defined(XP_WIN) return NS_OK; } diff --git a/toolkit/components/places/PlacesUtils.jsm b/toolkit/components/places/PlacesUtils.jsm index ab753ba86b..259fb7aa7d 100644 --- a/toolkit/components/places/PlacesUtils.jsm +++ b/toolkit/components/places/PlacesUtils.jsm @@ -60,8 +60,14 @@ XPCOMUtils.defineLazyModuleGetter(this, "PlacesUIUtils", // refresh instead. const MIN_TRANSACTIONS_FOR_BATCH = 5; -// The transferable system converts "\r\n" to "\n" where needed. +// On Mac OSX, the transferable system converts "\r\n" to "\n\n", where +// we really just want "\n". On other platforms, the transferable system +// converts "\r\n" to "\n". +#ifdef XP_MACOSX +const NEWLINE = "\n"; +#else const NEWLINE = "\r\n"; +#endif function QI_node(aNode, aIID) { var result = null; diff --git a/toolkit/components/places/moz.build b/toolkit/components/places/moz.build index 4c6ce89565..fda73f761f 100644 --- a/toolkit/components/places/moz.build +++ b/toolkit/components/places/moz.build @@ -68,9 +68,10 @@ if CONFIG['MOZ_PLACES']: 'PlacesSearchAutocompleteProvider.jsm', 'PlacesSyncUtils.jsm', 'PlacesTransactions.jsm', - 'PlacesUtils.jsm', ] + EXTRA_PP_JS_MODULES += ['PlacesUtils.jsm'] + EXTRA_COMPONENTS += [ 'ColorAnalyzer.js', 'nsLivemarkService.js', diff --git a/toolkit/components/printing/jar.mn b/toolkit/components/printing/jar.mn index f77cf1c6aa..a0e9510304 100644 --- a/toolkit/components/printing/jar.mn +++ b/toolkit/components/printing/jar.mn @@ -6,9 +6,11 @@ toolkit.jar: content/global/printdialog.js (content/printdialog.js) content/global/printdialog.xul (content/printdialog.xul) #ifdef XP_UNIX +#ifndef XP_MACOSX content/global/printjoboptions.js (content/printjoboptions.js) content/global/printjoboptions.xul (content/printjoboptions.xul) #endif +#endif content/global/printPageSetup.js (content/printPageSetup.js) content/global/printPageSetup.xul (content/printPageSetup.xul) * content/global/printPreviewBindings.xml (content/printPreviewBindings.xml) diff --git a/toolkit/components/prompts/content/commonDialog.xul b/toolkit/components/prompts/content/commonDialog.xul index a7621ccdfb..990b26586b 100644 --- a/toolkit/components/prompts/content/commonDialog.xul +++ b/toolkit/components/prompts/content/commonDialog.xul @@ -3,6 +3,7 @@ - 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/. --> + <?xml-stylesheet href="chrome://global/skin/" type="text/css"?> <?xml-stylesheet href="chrome://global/content/commonDialog.css" type="text/css"?> <?xml-stylesheet href="chrome://global/skin/commonDialog.css" type="text/css"?> @@ -62,9 +63,18 @@ <hbox id="iconContainer" align="start"> <image id="info.icon" class="spaced"/> </hbox> - <vbox id="infoContainer" pack="center"> + <vbox id="infoContainer" +#ifndef XP_MACOSX + pack="center" +#endif + > + <!-- Only shown on OS X, since it has no dialog title --> <description id="info.title" +#ifndef XP_MACOSX hidden="true" +#else + style="margin-bottom: 1em" +#endif /> <description id="info.body" context="contentAreaContextMenu" noinitialfocus="true"/> </vbox> diff --git a/toolkit/components/prompts/content/tabprompts.xml b/toolkit/components/prompts/content/tabprompts.xml index 5355bb4cff..0ce13203c1 100644 --- a/toolkit/components/prompts/content/tabprompts.xml +++ b/toolkit/components/prompts/content/tabprompts.xml @@ -315,16 +315,27 @@ group="system" action="this.onKeyAction('default', event);"/> <handler event="keypress" keycode="VK_ESCAPE" group="system" action="this.onKeyAction('cancel', event);"/> +#ifdef XP_MACOSX + <handler event="keypress" key="." modifiers="meta" + group="system" action="this.onKeyAction('cancel', event);"/> +#endif <handler event="focus" phase="capturing"> let bnum = this.args.defaultButtonNum || 0; let defaultButton = this.ui["button" + bnum]; - // The default button is only marked as such when no other button has focus. - // XUL buttons will react to pressing enter as a command, so you can't trigger - // the default without tabbing to it or something that isn't a button. +#ifdef XP_MACOSX + // On OS X, the default button always stays marked as such (until + // the entire prompt blurs). + defaultButton.setAttribute("default", true); +#else + // On other platforms, the default button is only marked as such + // when no other button has focus. XUL buttons on not-OSX will + // react to pressing enter as a command, so you can't trigger the + // default without tabbing to it or something that isn't a button. let focusedDefault = (event.originalTarget == defaultButton); let someButtonFocused = event.originalTarget instanceof Ci.nsIDOMXULButtonElement; defaultButton.setAttribute("default", focusedDefault || !someButtonFocused); +#endif </handler> <handler event="blur"> // If focus shifted to somewhere else in the browser, don't make diff --git a/toolkit/components/prompts/jar.mn b/toolkit/components/prompts/jar.mn index 1b5da3f801..60ecbdcbc4 100644 --- a/toolkit/components/prompts/jar.mn +++ b/toolkit/components/prompts/jar.mn @@ -4,7 +4,7 @@ toolkit.jar: content/global/commonDialog.js (content/commonDialog.js) - content/global/commonDialog.xul (content/commonDialog.xul) +* content/global/commonDialog.xul (content/commonDialog.xul) content/global/commonDialog.css (content/commonDialog.css) content/global/selectDialog.js (content/selectDialog.js) content/global/selectDialog.xul (content/selectDialog.xul) diff --git a/toolkit/components/satchel/nsFormFillController.cpp b/toolkit/components/satchel/nsFormFillController.cpp index 880ca79b21..bebc60f521 100644 --- a/toolkit/components/satchel/nsFormFillController.cpp +++ b/toolkit/components/satchel/nsFormFillController.cpp @@ -1016,11 +1016,27 @@ nsFormFillController::KeyPress(nsIDOMEvent* aEvent) keyEvent->GetKeyCode(&k); switch (k) { case nsIDOMKeyEvent::DOM_VK_DELETE: +#ifndef XP_MACOSX mController->HandleDelete(&cancel); break; case nsIDOMKeyEvent::DOM_VK_BACK_SPACE: mController->HandleText(&unused); break; +#else + case nsIDOMKeyEvent::DOM_VK_BACK_SPACE: + { + bool isShift = false; + keyEvent->GetShiftKey(&isShift); + + if (isShift) { + mController->HandleDelete(&cancel); + } else { + mController->HandleText(&unused); + } + + break; + } +#endif case nsIDOMKeyEvent::DOM_VK_PAGE_UP: case nsIDOMKeyEvent::DOM_VK_PAGE_DOWN: { diff --git a/toolkit/components/startup/nsAppStartup.cpp b/toolkit/components/startup/nsAppStartup.cpp index 11a000270e..7f67323b7d 100644 --- a/toolkit/components/startup/nsAppStartup.cpp +++ b/toolkit/components/startup/nsAppStartup.cpp @@ -273,6 +273,10 @@ nsAppStartup::Run(void) // with a zombie process. if (!mShuttingDown && mConsiderQuitStopper != 0) { +#ifdef XP_MACOSX + EnterLastWindowClosingSurvivalArea(); +#endif + mRunning = true; nsresult rv = mAppShell->Run(); @@ -308,10 +312,45 @@ nsAppStartup::Quit(uint32_t aMode) // If we're considering quitting, we will only do so if: if (ferocity == eConsiderQuit) { +#ifdef XP_MACOSX + nsCOMPtr<nsIAppShellService> appShell + (do_GetService(NS_APPSHELLSERVICE_CONTRACTID)); + bool hasHiddenPrivateWindow = false; + if (appShell) { + appShell->GetHasHiddenPrivateWindow(&hasHiddenPrivateWindow); + } + int32_t suspiciousCount = hasHiddenPrivateWindow ? 2 : 1; +#endif + if (mConsiderQuitStopper == 0) { // there are no windows... ferocity = eAttemptQuit; } +#ifdef XP_MACOSX + else if (mConsiderQuitStopper == suspiciousCount) { + // ... or there is only a hiddenWindow left, and it's useless: + + // Failure shouldn't be fatal, but will abort quit attempt: + if (!appShell) + return NS_OK; + + bool usefulHiddenWindow; + appShell->GetApplicationProvidedHiddenWindow(&usefulHiddenWindow); + nsCOMPtr<nsIXULWindow> hiddenWindow; + appShell->GetHiddenWindow(getter_AddRefs(hiddenWindow)); + // If the remaining windows are useful, we won't quit: + nsCOMPtr<nsIXULWindow> hiddenPrivateWindow; + if (hasHiddenPrivateWindow) { + appShell->GetHiddenPrivateWindow(getter_AddRefs(hiddenPrivateWindow)); + if ((!hiddenWindow && !hiddenPrivateWindow) || usefulHiddenWindow) + return NS_OK; + } else if (!hiddenWindow || usefulHiddenWindow) { + return NS_OK; + } + + ferocity = eAttemptQuit; + } +#endif } nsCOMPtr<nsIObserverService> obsService; @@ -365,6 +404,10 @@ nsAppStartup::Quit(uint32_t aMode) if (!mAttemptingQuit) { mAttemptingQuit = true; +#ifdef XP_MACOSX + // now even the Mac wants to quit when the last window is closed + ExitLastWindowClosingSurvivalArea(); +#endif if (obsService) obsService->NotifyObservers(nullptr, "quit-application-granted", nullptr); } diff --git a/toolkit/components/thumbnails/PageThumbUtils.jsm b/toolkit/components/thumbnails/PageThumbUtils.jsm index f91b364800..fb5d67ddb5 100644 --- a/toolkit/components/thumbnails/PageThumbUtils.jsm +++ b/toolkit/components/thumbnails/PageThumbUtils.jsm @@ -71,6 +71,18 @@ this.PageThumbUtils = { let windowScale = aWindow ? aWindow.devicePixelRatio : systemScale; let scale = Math.max(systemScale, windowScale); +#ifdef XP_MACOSX + /** * + * On retina displays, we can sometimes go down this path + * without a window object. In those cases, force 2x scaling + * as the system scale doesn't represent the 2x scaling + * on OS X. + */ + if (!aWindow) { + scale = 2; + } +#endif + /** * * THESE VALUES ARE DEFINED IN newtab.css and hard coded. * If you change these values from the prefs, diff --git a/toolkit/components/thumbnails/moz.build b/toolkit/components/thumbnails/moz.build index 957bc7df0d..92ff2af946 100644 --- a/toolkit/components/thumbnails/moz.build +++ b/toolkit/components/thumbnails/moz.build @@ -11,11 +11,11 @@ EXTRA_COMPONENTS += [ EXTRA_JS_MODULES += [ 'PageThumbs.jsm', 'PageThumbsWorker.js', - 'PageThumbUtils.jsm', ] EXTRA_PP_JS_MODULES += [ 'BackgroundPageThumbs.jsm', + 'PageThumbUtils.jsm', ] JAR_MANIFESTS += ['jar.mn'] diff --git a/toolkit/components/viewsource/content/viewPartialSource.xul b/toolkit/components/viewsource/content/viewPartialSource.xul index c51744fd21..fdec367b1c 100644 --- a/toolkit/components/viewsource/content/viewPartialSource.xul +++ b/toolkit/components/viewsource/content/viewPartialSource.xul @@ -1,8 +1,8 @@ <?xml version="1.0"?> -<!-- -*- Mode: XML -*- - 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/. --> +# -*- Mode: HTML -*- +# 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/. <?xml-stylesheet href="chrome://global/skin/" type="text/css"?> <?xml-stylesheet href="chrome://global/content/viewSource.css" type="text/css"?> @@ -99,8 +99,10 @@ label="&savePageCmd.label;" accesskey="&savePageCmd.accesskey;"/> <menuitem command="cmd_pagesetup" id="menu_pageSetup" label="&pageSetupCmd.label;" accesskey="&pageSetupCmd.accesskey;"/> +#ifndef XP_MACOSX <menuitem command="cmd_printpreview" id="menu_printPreview" label="&printPreviewCmd.label;" accesskey="&printPreviewCmd.accesskey;"/> +#endif <menuitem key="key_print" command="cmd_print" id="menu_print" label="&printCmd.label;" accesskey="&printCmd.accesskey;"/> <menuseparator/> diff --git a/toolkit/components/viewsource/content/viewSource.xul b/toolkit/components/viewsource/content/viewSource.xul index 3ad45a9d9d..c6ca58234e 100644 --- a/toolkit/components/viewsource/content/viewSource.xul +++ b/toolkit/components/viewsource/content/viewSource.xul @@ -1,5 +1,5 @@ <?xml version="1.0"?> -# -*- Mode: XML -*- +# -*- Mode: HTML -*- # 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/. @@ -50,6 +50,10 @@ oncommand="document.getElementById('FindToolbar').onFindAgainCommand(false);"/> <command id="cmd_findPrevious" oncommand="document.getElementById('FindToolbar').onFindAgainCommand(true);"/> +#ifdef XP_MACOSX + <command id="cmd_findSelection" + oncommand="document.getElementById('FindToolbar').onFindSelectionCommand();"/> +#endif <command id="cmd_reload" oncommand="viewSourceChrome.reload();"/> <command id="cmd_goToLine" oncommand="viewSourceChrome.promptAndGoToLine();" disabled="true"/> <command id="cmd_highlightSyntax" oncommand="viewSourceChrome.toggleSyntaxHighlighting();"/> @@ -85,13 +89,21 @@ <key id="key_find" key="&findOnCmd.commandkey;" command="cmd_find" modifiers="accel"/> <key id="key_findAgain" key="&findAgainCmd.commandkey;" command="cmd_findAgain" modifiers="accel"/> <key id="key_findPrevious" key="&findAgainCmd.commandkey;" command="cmd_findPrevious" modifiers="accel,shift"/> +#ifdef XP_MACOSX + <key id="key_findSelection" key="&findSelectionCmd.commandkey;" command="cmd_findSelection" modifiers="accel"/> +#endif <key keycode="&findAgainCmd.commandkey2;" command="cmd_findAgain"/> <key keycode="&findAgainCmd.commandkey2;" command="cmd_findPrevious" modifiers="shift"/> <key keycode="VK_BACK" command="Browser:Back"/> <key keycode="VK_BACK" command="Browser:Forward" modifiers="shift"/> +#ifndef XP_MACOSX <key id="goBackKb" keycode="VK_LEFT" command="Browser:Back" modifiers="alt"/> <key id="goForwardKb" keycode="VK_RIGHT" command="Browser:Forward" modifiers="alt"/> +#else + <key id="goBackKb" keycode="VK_LEFT" command="Browser:Back" modifiers="accel" /> + <key id="goForwardKb" keycode="VK_RIGHT" command="Browser:Forward" modifiers="accel" /> +#endif #ifdef XP_UNIX <key id="goBackKb2" key="&goBackCmd.commandKey;" command="Browser:Back" modifiers="accel"/> <key id="goForwardKb2" key="&goForwardCmd.commandKey;" command="Browser:Forward" modifiers="accel"/> @@ -138,8 +150,10 @@ label="&savePageCmd.label;" accesskey="&savePageCmd.accesskey;"/> <menuitem command="cmd_pagesetup" id="menu_pageSetup" label="&pageSetupCmd.label;" accesskey="&pageSetupCmd.accesskey;"/> +#ifndef XP_MACOSX <menuitem command="cmd_printpreview" id="menu_printPreview" label="&printPreviewCmd.label;" accesskey="&printPreviewCmd.accesskey;"/> +#endif <menuitem key="key_print" command="cmd_print" id="menu_print" label="&printCmd.label;" accesskey="&printCmd.accesskey;"/> <menuseparator/> diff --git a/toolkit/components/viewsource/jar.mn b/toolkit/components/viewsource/jar.mn index 33818ae0db..00a1f19a46 100644 --- a/toolkit/components/viewsource/jar.mn +++ b/toolkit/components/viewsource/jar.mn @@ -7,6 +7,6 @@ toolkit.jar: content/global/viewSource.js (content/viewSource.js) * content/global/viewSource.xul (content/viewSource.xul) content/global/viewPartialSource.js (content/viewPartialSource.js) - content/global/viewPartialSource.xul (content/viewPartialSource.xul) +* content/global/viewPartialSource.xul (content/viewPartialSource.xul) content/global/viewSourceUtils.js (content/viewSourceUtils.js) content/global/viewSource-content.js (content/viewSource-content.js) diff --git a/toolkit/content/aboutProfiles.js b/toolkit/content/aboutProfiles.js index 0e548fd0ff..29c5f67ad7 100644 --- a/toolkit/content/aboutProfiles.js +++ b/toolkit/content/aboutProfiles.js @@ -131,6 +131,8 @@ function display(profileData) { let button = document.createElement('button'); #ifdef XP_WIN let string = 'winOpenDir2'; +#elifdef XP_MACOSX + let string = 'macOpenDir'; #else let string = 'openDir'; #endif diff --git a/toolkit/content/aboutSupport.xhtml b/toolkit/content/aboutSupport.xhtml index 4ae9927399..8afee18676 100644 --- a/toolkit/content/aboutSupport.xhtml +++ b/toolkit/content/aboutSupport.xhtml @@ -156,8 +156,12 @@ #ifdef XP_WIN &aboutSupport.appBasicsProfileDirWinMac; #else +#ifdef XP_MACOSX + &aboutSupport.appBasicsProfileDirWinMac; +#else &aboutSupport.appBasicsProfileDir; #endif +#endif </th> <td> @@ -165,8 +169,12 @@ #ifdef XP_WIN &aboutSupport.showWin2.label; #else +#ifdef XP_MACOSX + &aboutSupport.showMac.label; +#else &aboutSupport.showDir.label; #endif +#endif </button> </td> </tr> diff --git a/toolkit/content/customizeToolbar.js b/toolkit/content/customizeToolbar.js index 1775d9f52a..05151b905d 100644 --- a/toolkit/content/customizeToolbar.js +++ b/toolkit/content/customizeToolbar.js @@ -212,6 +212,10 @@ function wrapToolbarItems() { forEachCustomizableToolbar(function (toolbar) { Array.forEach(toolbar.childNodes, function (item) { +#ifdef XP_MACOSX + if (item.firstChild && item.firstChild.localName == "menubar") + return; +#endif if (isToolbarItem(item)) { let wrapper = wrapToolbarItem(item); cleanupItemForToolbar(item, wrapper); diff --git a/toolkit/content/dialogOverlay.xul b/toolkit/content/dialogOverlay.xul index 9d4d8b6138..09e00613e1 100644 --- a/toolkit/content/dialogOverlay.xul +++ b/toolkit/content/dialogOverlay.xul @@ -1,11 +1,11 @@ <?xml version="1.0"?> -<!-- -*- Mode: XML -*- - 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/. - - WARNING!!! This file is obsoleted by the dialog.xml widget ---> +# -*- Mode: HTML -*- +# 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/. +# +# WARNING!!! This file is obsoleted by the dialog.xml widget +# <!DOCTYPE overlay SYSTEM "chrome://global/locale/dialogOverlay.dtd"> @@ -14,6 +14,44 @@ <script type="application/javascript" src="chrome://global/content/dialogOverlay.js"/> +#ifdef XP_MACOSX +# + <hbox id="okCancelButtons"> + <spacer flex="1"/> + <button class="exit-dialog" id="Button3" label="" collapsed="true" oncommand="doButton3();"/> + <button class="exit-dialog" id="Button2" label="" collapsed="true" oncommand="doButton2();"/> + <button class="exit-dialog" id="cancel" label="&cancelButton.label;" oncommand="doCancelButton();"/> + <button class="right exit-dialog" id="ok" default="true" label="&okButton.label;" oncommand="doOKButton();"/> + </hbox> + + <hbox id="okCancelHelpButtons"> + <button class="exit-dialog" id="help" label="&helpButton.label;" oncommand="doHelpButton();"/> + <spacer flex="1"/> + <button class="exit-dialog" id="Button3" label="" collapsed="true" oncommand="doButton3();"/> + <button class="exit-dialog" id="Button2" label="" collapsed="true" oncommand="doButton2();"/> + <button class="exit-dialog" id="cancel" label="&cancelButton.label;" oncommand="doCancelButton();"/> + <button class="right exit-dialog" id="ok" default="true" label="&okButton.label;" oncommand="doOKButton();"/> + </hbox> + + <hbox id="okCancelButtonsRight"> + <spacer flex="1"/> + <button class="exit-dialog" id="Button3" label="" collapsed="true" oncommand="doButton3();"/> + <button class="exit-dialog" id="Button2" label="" collapsed="true" oncommand="doButton2();"/> + <button class="exit-dialog" id="cancel" label="&cancelButton.label;" oncommand="doCancelButton();"/> + <button class="right exit-dialog" id="ok" default="true" label="&okButton.label;" oncommand="doOKButton();"/> + </hbox> + + <hbox id="okCancelHelpButtonsRight"> + <button class="exit-dialog" id="help" label="&helpButton.label;" oncommand="doHelpButton();"/> + <spacer flex="1"/> + <button class="exit-dialog" id="Button3" label="" collapsed="true" oncommand="doButton3();"/> + <button class="exit-dialog" id="Button2" label="" collapsed="true" oncommand="doButton2();"/> + <button class="exit-dialog" id="cancel" label="&cancelButton.label;" oncommand="doCancelButton();"/> + <button class="right exit-dialog" id="ok" default="true" label="&okButton.label;" oncommand="doOKButton();"/> + </hbox> +# +#else +# <hbox id="okCancelButtons"> <spacer flex="1"/> <button class="right exit-dialog" id="ok" label="&okButton.label;" default="true" oncommand="doOKButton();"/> @@ -49,10 +87,15 @@ <button class="exit-dialog" id="cancel" label="&cancelButton.label;" oncommand="doCancelButton();"/> <button class="exit-dialog" id="help" label="&helpButton.label;" oncommand="doHelpButton();"/> </hbox> +#endif <keyset id="dialogKeys"> <key keycode="VK_RETURN" oncommand="if (!document.getElementById('ok').disabled) doOKButton();"/> <key keycode="VK_ESCAPE" oncommand="doCancelButton();"/> +#ifdef XP_MACOSX + <key key="." modifiers="meta" oncommand="doCancelButton();"/> +# +#endif </keyset> </overlay> diff --git a/toolkit/content/globalOverlay.js b/toolkit/content/globalOverlay.js index d5ee131916..d8467f0a12 100644 --- a/toolkit/content/globalOverlay.js +++ b/toolkit/content/globalOverlay.js @@ -4,6 +4,12 @@ function closeWindow(aClose, aPromptFunction) { +#ifdef XP_MACOSX + // Closing the last window doesn't quit the application on OS X. + if (typeof(aPromptFunction) == "function" && !aPromptFunction()) { + return false; + } +#else var windowCount = 0; var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"] .getService(Components.interfaces.nsIWindowMediator); @@ -23,6 +29,7 @@ function closeWindow(aClose, aPromptFunction) return false; if (windowCount != 1 && typeof(aPromptFunction) == "function" && !aPromptFunction()) return false; +#endif if (aClose) { window.close(); diff --git a/toolkit/content/jar.mn b/toolkit/content/jar.mn index 1f1c880397..6494645086 100644 --- a/toolkit/content/jar.mn +++ b/toolkit/content/jar.mn @@ -15,7 +15,7 @@ toolkit.jar: #ifdef MOZ_OFFICIAL_BRANDING * content/global/aboutRights.xhtml #else - content/global/aboutRights.xhtml (aboutRights-unbranded.xhtml) +* content/global/aboutRights.xhtml (aboutRights-unbranded.xhtml) #endif content/global/aboutNetworking.js content/global/aboutNetworking.xhtml @@ -38,7 +38,7 @@ toolkit.jar: * content/global/buildconfig.html * content/global/contentAreaUtils.js content/global/customizeToolbar.css - content/global/customizeToolbar.js +* content/global/customizeToolbar.js content/global/customizeToolbar.xul content/global/datepicker.xhtml content/global/editMenuOverlay.js @@ -47,7 +47,7 @@ toolkit.jar: * content/global/finddialog.xul content/global/findUtils.js content/global/filepicker.properties - content/global/globalOverlay.js +* content/global/globalOverlay.js content/global/mozilla.xhtml #ifdef MOZ_PHOENIX content/global/logopage.xhtml @@ -63,7 +63,7 @@ toolkit.jar: content/global/treeUtils.js content/global/viewZoomOverlay.js content/global/globalOverlay.xul - content/global/dialogOverlay.xul +* content/global/dialogOverlay.xul content/global/dialogOverlay.js content/global/inlineSpellCheckUI.js content/global/nsClipboard.js @@ -85,7 +85,7 @@ toolkit.jar: content/global/bindings/editor.xml (widgets/editor.xml) content/global/bindings/expander.xml (widgets/expander.xml) content/global/bindings/filefield.xml (widgets/filefield.xml) - content/global/bindings/findbar.xml (widgets/findbar.xml) +* content/global/bindings/findbar.xml (widgets/findbar.xml) content/global/bindings/general.xml (widgets/general.xml) content/global/bindings/groupbox.xml (widgets/groupbox.xml) content/global/bindings/listbox.xml (widgets/listbox.xml) @@ -114,10 +114,13 @@ toolkit.jar: content/global/bindings/timepicker.js (widgets/timepicker.js) content/global/bindings/toolbar.xml (widgets/toolbar.xml) content/global/bindings/toolbarbutton.xml (widgets/toolbarbutton.xml) - content/global/bindings/tree.xml (widgets/tree.xml) +* content/global/bindings/tree.xml (widgets/tree.xml) content/global/bindings/videocontrols.xml (widgets/videocontrols.xml) content/global/bindings/videocontrols.css (widgets/videocontrols.css) * content/global/bindings/wizard.xml (widgets/wizard.xml) +#ifdef XP_MACOSX + content/global/macWindowMenu.js +#endif content/global/svg/svgBindings.xml (/layout/svg/resources/content/svgBindings.xml) content/global/gmp-sources/openh264.json (gmp-sources/openh264.json) content/global/gmp-sources/widevinecdm.json (gmp-sources/widevinecdm.json) diff --git a/toolkit/content/license.html b/toolkit/content/license.html index 94d39959b2..0de306f36e 100644 --- a/toolkit/content/license.html +++ b/toolkit/content/license.html @@ -5341,7 +5341,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. </pre> -#if defined(XP_WIN) || defined(XP_LINUX) +#if defined(XP_WIN) || defined(XP_MACOSX) || defined(XP_LINUX) <hr> diff --git a/toolkit/content/macWindowMenu.inc b/toolkit/content/macWindowMenu.inc new file mode 100644 index 0000000000..c345ad8b7f --- /dev/null +++ b/toolkit/content/macWindowMenu.inc @@ -0,0 +1,40 @@ + <script type="application/javascript" src="chrome://global/content/macWindowMenu.js"/> + <commandset id="baseMenuCommandSet"> + <command id="minimizeWindow" + label="&minimizeWindow.label;" + oncommand="window.minimize();" /> + <command id="zoomWindow" + label="&zoomWindow.label;" + oncommand="zoomWindow();" /> + </commandset> + <keyset id="baseMenuKeyset"> + <key id="key_minimizeWindow" + command="minimizeWindow" + key="&minimizeWindow.key;" + modifiers="accel"/> + </keyset> + <menu id="windowMenu" + label="&windowMenu.label;" + datasources="rdf:window-mediator" ref="NC:WindowMediatorRoot" + onpopupshowing="macWindowMenuDidShow();" + hidden="false"> + <template> + <rule> + <menupopup> + <menuitem uri="rdf:*" + label="rdf:http://home.netscape.com/NC-rdf#Name" + type="radio" + name="windowList" + oncommand="ShowWindowFromResource(event.target)"/> + </menupopup> + </rule> + </template> + <menupopup id="windowPopup"> + <menuitem command="minimizeWindow" key="key_minimizeWindow"/> + <menuitem command="zoomWindow"/> + <!-- decomment when "BringAllToFront" is implemented + <menuseparator/> + <menuitem label="&bringAllToFront.label;" disabled="true"/> --> + <menuseparator id="sep-window-list"/> + </menupopup> + </menu> diff --git a/toolkit/content/macWindowMenu.js b/toolkit/content/macWindowMenu.js new file mode 100644 index 0000000000..46654c4f8a --- /dev/null +++ b/toolkit/content/macWindowMenu.js @@ -0,0 +1,51 @@ +// -*- indent-tabs-mode: nil; js-indent-level: 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/. */ + +function macWindowMenuDidShow() +{ + var windowManagerDS = + Components.classes['@mozilla.org/rdf/datasource;1?name=window-mediator'] + .getService(Components.interfaces.nsIWindowDataSource); + var sep = document.getElementById("sep-window-list"); + // Using double parens to avoid warning + while ((sep = sep.nextSibling)) { + var url = sep.getAttribute('id'); + var win = windowManagerDS.getWindowForResource(url); + if (win.document.documentElement.getAttribute("inwindowmenu") == "false") + sep.hidden = true; + else if (win == window) + sep.setAttribute("checked", "true"); + } +} + +function toOpenWindow( aWindow ) +{ + // deminiaturize the window, if it's in the Dock + if (aWindow.windowState == STATE_MINIMIZED) + aWindow.restore(); + aWindow.document.commandDispatcher.focusedWindow.focus(); +} + +function ShowWindowFromResource( node ) +{ + var windowManagerDS = + Components.classes['@mozilla.org/rdf/datasource;1?name=window-mediator'] + .getService(Components.interfaces.nsIWindowDataSource); + + var desiredWindow = null; + var url = node.getAttribute('id'); + desiredWindow = windowManagerDS.getWindowForResource( url ); + if (desiredWindow) + toOpenWindow(desiredWindow); +} + +function zoomWindow() +{ + if (window.windowState == STATE_NORMAL) + window.maximize(); + else + window.restore(); +} diff --git a/toolkit/content/widgets/dialog.xml b/toolkit/content/widgets/dialog.xml index aff1621965..d83570ac0f 100644 --- a/toolkit/content/widgets/dialog.xml +++ b/toolkit/content/widgets/dialog.xml @@ -422,11 +422,15 @@ if (!event.defaultPrevented) this.cancelDialog(); </handler> +#ifdef XP_MACOSX + <handler event="keypress" key="." modifiers="meta" phase="capturing" action="this.cancelDialog();"/> +#else <handler event="focus" phase="capturing"> var btn = this.getButton(this.defaultButton); if (btn) btn.setAttribute("default", event.originalTarget == btn || !(event.originalTarget instanceof Components.interfaces.nsIDOMXULButtonElement)); </handler> +#endif </handlers> </binding> diff --git a/toolkit/content/widgets/findbar.xml b/toolkit/content/widgets/findbar.xml index aae799554d..c312a6a25a 100644 --- a/toolkit/content/widgets/findbar.xml +++ b/toolkit/content/widgets/findbar.xml @@ -1232,6 +1232,39 @@ ]]></body> </method> +#ifdef XP_MACOSX + <!-- + - Fetches the currently selected text and sets that as the text to search + - next. This is a MacOS specific feature. + --> + <method name="onFindSelectionCommand"> + <body><![CDATA[ + let searchString = this.browser.finder.setSearchStringToSelection(); + if (searchString) + this._findField.value = searchString; + ]]></body> + </method> + + <method name="_onFindFieldFocus"> + <body><![CDATA[ + let prefsvc = this._prefsvc; + const kPref = "accessibility.typeaheadfind.prefillwithselection"; + if (this.prefillWithSelection && prefsvc.getBoolPref(kPref)) + return; + + let clipboardSearchString = this._browser.finder.clipboardSearchString; + if (clipboardSearchString && this._findField.value != clipboardSearchString && + !this._findField._willfullyDeleted) { + this._findField.value = clipboardSearchString; + this._findField._hadValue = true; + // Changing the search string makes the previous status invalid, so + // we better clear it here. + this._updateStatusUI(); + } + ]]></body> + </method> +#endif + <!-- - This handles all the result changes for both - type-ahead-find and highlighting. diff --git a/toolkit/content/widgets/optionsDialog.xml b/toolkit/content/widgets/optionsDialog.xml index efd20663e5..f0cdba62f2 100644 --- a/toolkit/content/widgets/optionsDialog.xml +++ b/toolkit/content/widgets/optionsDialog.xml @@ -11,6 +11,7 @@ <binding id="optionsDialog" extends="chrome://global/content/bindings/dialog.xml#dialog"> <content> +#ifndef XP_MACOSX <xul:hbox flex="1"> <xul:categoryBox anonid="prefsCategories"> <children/> @@ -20,6 +21,16 @@ <xul:iframe anonid="panelFrame" name="panelFrame" style="width: 0px;" flex="1"/> </xul:vbox> </xul:hbox> +#else + <xul:vbox flex="1"> + <xul:categoryBox anonid="prefsCategories"> + <children/> + </xul:categoryBox> + <xul:vbox flex="1"> + <xul:iframe anonid="panelFrame" name="panelFrame" style="width: 0px;" flex="1"/> + </xul:vbox> + </xul:vbox> +#endif </content> <implementation> diff --git a/toolkit/content/widgets/preferences.xml b/toolkit/content/widgets/preferences.xml index f7cb109488..11de032462 100644 --- a/toolkit/content/widgets/preferences.xml +++ b/toolkit/content/widgets/preferences.xml @@ -1146,7 +1146,11 @@ </handler> <handler event="keypress" +#ifdef XP_MACOSX + key="&openHelpMac.commandkey;" modifiers="accel" +#else keycode="&openHelp.commandkey;" +#endif phase="capturing"> <![CDATA[ var helpButton = this.getButton("help"); diff --git a/toolkit/content/widgets/tree.xml b/toolkit/content/widgets/tree.xml index 19a1fa7727..aa17172575 100644 --- a/toolkit/content/widgets/tree.xml +++ b/toolkit/content/widgets/tree.xml @@ -79,11 +79,11 @@ <property name="treeBoxObject" onget="return this.boxObject;" readonly="true"/> -<!-- contentView is obsolete (see bug 202391) --> +# contentView is obsolete (see bug 202391) <property name="contentView" onget="return this.view; /*.QueryInterface(Components.interfaces.nsITreeContentView)*/" readonly="true"/> -<!-- builderView is obsolete (see bug 202393) --> +# builderView is obsolete (see bug 202393) <property name="builderView" onget="return this.view; /*.QueryInterface(Components.interfaces.nsIXULTreeBuilder)*/" readonly="true"/> @@ -774,6 +774,7 @@ event.preventDefault(); } </handler> +#ifndef XP_MACOSX <!-- Use F2 key to enter text editing. --> <handler event="keydown" keycode="VK_F2"> <![CDATA[ @@ -785,6 +786,7 @@ event.preventDefault(); ]]> </handler> +#endif // XP_MACOSX <handler event="keydown" keycode="VK_ESCAPE"> <![CDATA[ diff --git a/toolkit/content/widgets/wizard.xml b/toolkit/content/widgets/wizard.xml index eb812f0652..3a8ec2cfef 100644 --- a/toolkit/content/widgets/wizard.xml +++ b/toolkit/content/widgets/wizard.xml @@ -465,6 +465,54 @@ </implementation> </binding> +#ifdef XP_MACOSX + <binding id="wizard-header" extends="chrome://global/content/bindings/wizard.xml#wizard-base"> + <content> + <xul:stack class="wizard-header-stack" flex="1"> + <xul:vbox class="wizard-header-box-1"> + <xul:vbox class="wizard-header-box-text"> + <xul:label class="wizard-header-label" xbl:inherits="xbl:text=label"/> + </xul:vbox> + </xul:vbox> + <xul:hbox class="wizard-header-box-icon"> + <xul:spacer flex="1"/> + <xul:image class="wizard-header-icon" xbl:inherits="src=iconsrc"/> + </xul:hbox> + </xul:stack> + </content> + </binding> + + <binding id="wizard-buttons" extends="chrome://global/content/bindings/wizard.xml#wizard-base"> + <content> + <xul:vbox flex="1"> + <xul:hbox class="wizard-buttons-btm"> + <xul:button class="wizard-button" dlgtype="extra1" hidden="true"/> + <xul:button class="wizard-button" dlgtype="extra2" hidden="true"/> + <xul:button label="&button-cancel-mac.label;" class="wizard-button" dlgtype="cancel"/> + <xul:spacer flex="1"/> + <xul:button label="&button-back-mac.label;" accesskey="&button-back-mac.accesskey;" + class="wizard-button wizard-nav-button" dlgtype="back"/> + <xul:button label="&button-next-mac.label;" accesskey="&button-next-mac.accesskey;" + class="wizard-button wizard-nav-button" dlgtype="next" + default="true" xbl:inherits="hidden=lastpage" /> + <xul:button label="&button-finish-mac.label;" class="wizard-button" + dlgtype="finish" default="true" xbl:inherits="hidden=hidefinishbutton" /> + </xul:hbox> + </xul:vbox> + </content> + + <implementation> + <method name="onPageChange"> + <body><![CDATA[ + this.setAttribute("hidefinishbutton", !(this.getAttribute("lastpage") == "true")); + ]]></body> + </method> + </implementation> + + </binding> + +#else + <binding id="wizard-header" extends="chrome://global/content/bindings/wizard.xml#wizard-base"> <content> <xul:hbox class="wizard-header-box-1" flex="1"> @@ -554,5 +602,6 @@ </property> </implementation> </binding> +#endif </bindings> diff --git a/toolkit/content/xul.css b/toolkit/content/xul.css index 7c16cab703..0aa0d3a217 100644 --- a/toolkit/content/xul.css +++ b/toolkit/content/xul.css @@ -243,6 +243,11 @@ caption { /******** draggable elements *********/ +%ifdef XP_MACOSX +titlebar, +toolbar:not([nowindowdrag="true"]):not([customizing="true"]), +statusbar:not([nowindowdrag="true"]), +%endif windowdragbox { -moz-window-dragging: drag; } @@ -283,6 +288,12 @@ toolbar[customizing="true"][hidden="true"] { display: -moz-box; } +%ifdef XP_MACOSX +toolbar[type="menubar"] { + min-height: 0 !important; + border: 0 !important; +} +%else toolbar[type="menubar"][autohide="true"] { -moz-binding: url("chrome://global/content/bindings/toolbar.xml#toolbar-menubar-autohide"); overflow: hidden; @@ -294,6 +305,7 @@ toolbar[type="menubar"][autohide="true"][inactive="true"]:not([customizing="true -moz-appearance: none !important; border-style: none !important; } +%endif %ifdef MOZ_WIDGET_GTK window[shellshowingmenubar="true"] menubar, @@ -487,9 +499,15 @@ panel[arrowposition="start_after"]:-moz-locale-dir(rtl) { %endif +%ifdef XP_MACOSX +.statusbar-resizerpanel { + display: none; +} +%else window[sizemode="maximized"] statusbarpanel.statusbar-resizerpanel { visibility: collapse; } +%endif /******** grid **********/ @@ -1000,6 +1018,9 @@ autorepeatbutton { statusbar { -moz-binding: url("chrome://global/content/bindings/general.xml#statusbar"); +%ifdef XP_MACOSX + padding-right: 14px; +%endif } statusbarpanel { diff --git a/toolkit/modules/AppConstants.jsm b/toolkit/modules/AppConstants.jsm index 40a630a445..ba94f4a3fc 100644 --- a/toolkit/modules/AppConstants.jsm +++ b/toolkit/modules/AppConstants.jsm @@ -105,6 +105,8 @@ this.AppConstants = Object.freeze({ "linux", #elif XP_WIN "win", +#elif XP_MACOSX + "macosx", #elif XP_LINUX "linux", #else diff --git a/toolkit/modules/LightweightThemeConsumer.jsm b/toolkit/modules/LightweightThemeConsumer.jsm index 9419fdcf23..4010a9ff22 100644 --- a/toolkit/modules/LightweightThemeConsumer.jsm +++ b/toolkit/modules/LightweightThemeConsumer.jsm @@ -147,6 +147,29 @@ LightweightThemeConsumer.prototype = { footer.removeAttribute("lwthemefooter"); } +#if defined(XP_MACOSX) && defined(MOZ_CAN_DRAW_IN_TITLEBAR) + // On OS X, we extend the lightweight theme into the titlebar, which means setting + // the chromemargin attribute. Some XUL applications already draw in the titlebar, + // so we need to save the chromemargin value before we overwrite it with the value + // that lets us draw in the titlebar. We stash this value on the root attribute so + // that XUL applications have the ability to invalidate the saved value. + if (stateChanging) { + if (!root.hasAttribute("chromemargin-nonlwtheme")) { + root.setAttribute("chromemargin-nonlwtheme", root.getAttribute("chromemargin")); + } + + if (active) { + root.setAttribute("chromemargin", "0,-1,-1,-1"); + } else { + let defaultChromemargin = root.getAttribute("chromemargin-nonlwtheme"); + if (defaultChromemargin) { + root.setAttribute("chromemargin", defaultChromemargin); + } else { + root.removeAttribute("chromemargin"); + } + } + } +#endif Services.obs.notifyObservers(this._win, "lightweight-theme-window-updated", JSON.stringify(aData)); } diff --git a/toolkit/modules/UpdateUtils.jsm b/toolkit/modules/UpdateUtils.jsm index 5e3a2e100a..5acf395d3d 100644 --- a/toolkit/modules/UpdateUtils.jsm +++ b/toolkit/modules/UpdateUtils.jsm @@ -168,6 +168,17 @@ XPCOMUtils.defineLazyGetter(UpdateUtils, "ABI", function() { Cu.reportError("XPCOM ABI unknown"); } +#ifdef XP_MACOSX + // Mac universal build should report a different ABI than either macppc + // or mactel. + let macutils = Cc["@mozilla.org/xpcom/mac-utils;1"]. + getService(Ci.nsIMacUtils); + + if (macutils.isUniversalBinary) { + abi += "-u-" + macutils.architecturesInBinary; + } +#endif + return abi; }); diff --git a/toolkit/modules/WindowDraggingUtils.jsm b/toolkit/modules/WindowDraggingUtils.jsm index 5be8814de1..a7986c8b4a 100644 --- a/toolkit/modules/WindowDraggingUtils.jsm +++ b/toolkit/modules/WindowDraggingUtils.jsm @@ -2,7 +2,7 @@ * 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/. */ -#if defined(XP_WIN) +#if defined(XP_WIN) || defined(XP_MACOSX) const HAVE_CSS_WINDOW_DRAG_SUPPORT = true; #else const HAVE_CSS_WINDOW_DRAG_SUPPORT = false; diff --git a/toolkit/modules/moz.build b/toolkit/modules/moz.build index 836fd66b36..8509eb7cd3 100644 --- a/toolkit/modules/moz.build +++ b/toolkit/modules/moz.build @@ -103,7 +103,7 @@ EXTRA_PP_JS_MODULES += [ ] -EXTRA_JS_MODULES += [ +EXTRA_PP_JS_MODULES += [ 'LightweightThemeConsumer.jsm', ] diff --git a/toolkit/mozapps/downloads/content/downloads.xul b/toolkit/mozapps/downloads/content/downloads.xul index b5ca87a0c2..5ca9eec2d4 100644 --- a/toolkit/mozapps/downloads/content/downloads.xul +++ b/toolkit/mozapps/downloads/content/downloads.xul @@ -1,13 +1,15 @@ <?xml version="1.0"?> -# -*- Mode: XML; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- # 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/. #ifdef XP_UNIX +#ifndef XP_MACOSX #define XP_GNOME 1 #endif +#endif <?xml-stylesheet href="chrome://global/skin/" type="text/css"?> <?xml-stylesheet href="chrome://mozapps/content/downloads/downloads.css"?> @@ -50,6 +52,9 @@ <key keycode="VK_RETURN" oncommand="doDefaultForSelected();"/> <key id="key_pauseResume" key=" " oncommand="performCommand('cmd_pauseResume');"/> <key id="key_removeFromList" keycode="VK_DELETE" oncommand="performCommand('cmd_removeFromList');"/> +#ifdef XP_MACOSX + <key id="key_removeFromList2" keycode="VK_BACK" oncommand="performCommand('cmd_removeFromList');"/> +#endif <key id="key_close" key="&cmd.close.commandKey;" oncommand="closeWindow(true);" modifiers="accel"/> #ifdef XP_GNOME <key id="key_close2" key="&cmd.close2Unix.commandKey;" oncommand="closeWindow(true);" modifiers="accel,shift"/> @@ -95,8 +100,13 @@ oncommand="performCommand('cmd_open');" cmd="cmd_open"/> <menuitem id="menuitem_show" +#ifdef XP_MACOSX + label="&cmd.showMac.label;" + accesskey="&cmd.showMac.accesskey;" +#else label="&cmd.show.label;" accesskey="&cmd.show.accesskey;" +#endif oncommand="performCommand('cmd_show');" cmd="cmd_show"/> diff --git a/toolkit/mozapps/downloads/content/unknownContentType.xul b/toolkit/mozapps/downloads/content/unknownContentType.xul index 42d356e9f9..af8b7b016a 100644 --- a/toolkit/mozapps/downloads/content/unknownContentType.xul +++ b/toolkit/mozapps/downloads/content/unknownContentType.xul @@ -1,5 +1,5 @@ <?xml version="1.0"?> -# -*- Mode: XML; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- # 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/. @@ -68,7 +68,11 @@ <hbox id="openHandlerBox" flex="1" align="center"/> <hbox flex="1" align="center"> <button id="chooseButton" oncommand="dialog.chooseApp();" +#ifdef XP_MACOSX + label="&chooseHandlerMac.label;" accesskey="&chooseHandlerMac.accesskey;"/> +#else label="&chooseHandler.label;" accesskey="&chooseHandler.accesskey;"/> +#endif </hbox> </deck> </hbox> diff --git a/toolkit/mozapps/downloads/nsHelperAppDlg.js b/toolkit/mozapps/downloads/nsHelperAppDlg.js index 0e5cfdaf0e..90d38c90b0 100644 --- a/toolkit/mozapps/downloads/nsHelperAppDlg.js +++ b/toolkit/mozapps/downloads/nsHelperAppDlg.js @@ -675,7 +675,11 @@ nsUnknownContentTypeDialog.prototype = { // getPath: getPath: function (aFile) { +#ifdef XP_MACOSX + return aFile.leafName || aFile.path; +#else return aFile.path; +#endif }, // initAppAndSaveToDiskValues: @@ -983,6 +987,12 @@ nsUnknownContentTypeDialog.prototype = { return file.getVersionInfoField("FileDescription"); } catch (e) {} } +#elifdef XP_MACOSX + if (file instanceof Components.interfaces.nsILocalFileMac) { + try { + return file.bundleDisplayName; + } catch (e) {} + } #endif return file.leafName; diff --git a/toolkit/mozapps/extensions/GMPUtils.jsm b/toolkit/mozapps/extensions/GMPUtils.jsm index 593fc3c8da..3c691610d5 100644 --- a/toolkit/mozapps/extensions/GMPUtils.jsm +++ b/toolkit/mozapps/extensions/GMPUtils.jsm @@ -39,6 +39,11 @@ this.GMPUtils = { * The plugin to check. */ isPluginHidden: function(aPlugin) { + if (this._is32bitModeMacOS()) { + // GMPs are hidden on MacOS when running in 32 bit mode. + // See bug 1291537. + return true; + } if (!aPlugin.isEME) { return false; } @@ -66,7 +71,7 @@ this.GMPUtils = { } if (aPlugin.id == WIDEVINE_ID) { -#if defined(XP_WIN) || defined(XP_LINUX) +#if defined(XP_WIN) || defined(XP_LINUX) || defined(XP_MACOSX) // The Widevine plugin is available for Windows versions Vista and later, // Mac OSX, and Linux. return true; @@ -78,6 +83,14 @@ this.GMPUtils = { return true; }, + _is32bitModeMacOS: function() { +#ifdef XP_MACOSX + return Services.appinfo.XPCOMABI.split("-")[0] == "x86"; +#else + return false; +#endif + }, + /** * Checks whether or not a given plugin is visible in the addons manager * UI and the "enable DRM" notification box. This can be used to test diff --git a/toolkit/mozapps/extensions/content/extensions.js b/toolkit/mozapps/extensions/content/extensions.js index fe84bc4602..2ca3898f17 100644 --- a/toolkit/mozapps/extensions/content/extensions.js +++ b/toolkit/mozapps/extensions/content/extensions.js @@ -1878,7 +1878,11 @@ var gHeader = { // XXXunf Temporary until bug 371900 is fixed. let key = document.getElementById("focusSearch").getAttribute("key"); +#ifdef XP_MACOSX + let keyModifier = aEvent.metaKey; +#else let keyModifier = aEvent.ctrlKey; +#endif if (String.fromCharCode(aEvent.charCode) == key && keyModifier) { this.focusSearchBox(); return; diff --git a/toolkit/mozapps/extensions/content/update.xul b/toolkit/mozapps/extensions/content/update.xul index 9f5f35196e..094651fa5f 100644 --- a/toolkit/mozapps/extensions/content/update.xul +++ b/toolkit/mozapps/extensions/content/update.xul @@ -1,9 +1,9 @@ <?xml version="1.0"?> -<!-- -*- Mode: XML; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- --> -<!-- 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/. --> +# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +# 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/. <?xml-stylesheet href="chrome://global/skin/" type="text/css"?> <?xml-stylesheet href="chrome://mozapps/skin/extensions/update.css" type="text/css"?> @@ -100,7 +100,11 @@ oncommand="gUpdateWizard.shouldAutoCheck = this.checked;"/> </vbox> <separator flex="1"/> +#ifndef XP_MACOSX <label>&clickFinish.label;</label> +#else + <label>&clickFinish.labelMac;</label> +#endif <separator class="thin"/> </wizardpage> @@ -140,7 +144,11 @@ <description flex="1">&installerrors.intro.label;</description> </hbox> <separator flex="1"/> +#ifndef XP_MACOSX <label>&clickFinish.label;</label> +#else + <label>&clickFinish.labelMac;</label> +#endif <separator class="thin"/> </wizardpage> @@ -153,7 +161,11 @@ <description flex="1">&adminDisabled.warning.label;</description> </hbox> <separator flex="1"/> +#ifndef XP_MACOSX <label>&clickFinish.label;</label> +#else + <label>&clickFinish.labelMac;</label> +#endif <separator class="thin"/> </wizardpage> @@ -172,7 +184,11 @@ oncommand="gUpdateWizard.shouldAutoCheck = this.checked;"/> </vbox> <separator flex="1"/> +#ifndef XP_MACOSX <label>&clickFinish.label;</label> +#else + <label>&clickFinish.labelMac;</label> +#endif <separator class="thin"/> </wizardpage> diff --git a/toolkit/mozapps/extensions/jar.mn b/toolkit/mozapps/extensions/jar.mn index 878be4df13..e95d93ca02 100644 --- a/toolkit/mozapps/extensions/jar.mn +++ b/toolkit/mozapps/extensions/jar.mn @@ -21,7 +21,7 @@ toolkit.jar: content/mozapps/extensions/selectAddons.xml (content/selectAddons.xml) content/mozapps/extensions/selectAddons.js (content/selectAddons.js) content/mozapps/extensions/selectAddons.css (content/selectAddons.css) - content/mozapps/extensions/update.xul (content/update.xul) +* content/mozapps/extensions/update.xul (content/update.xul) content/mozapps/extensions/update.js (content/update.js) content/mozapps/extensions/eula.xul (content/eula.xul) content/mozapps/extensions/eula.js (content/eula.js) diff --git a/toolkit/mozapps/update/common/updatecommon.cpp b/toolkit/mozapps/update/common/updatecommon.cpp index 17a57eae38..aff7d72602 100644 --- a/toolkit/mozapps/update/common/updatecommon.cpp +++ b/toolkit/mozapps/update/common/updatecommon.cpp @@ -41,6 +41,8 @@ void UpdateLog::Init(NS_tchar* sourcePath, // updater process if the elevated updater process has written the log. DeleteFileW(mDstFilePath); } +#elif XP_MACOSX + logFP = NS_tfopen(mDstFilePath, NS_T("w")); #else // On platforms that have an updates directory in the installation directory // (e.g. platforms other than Windows and Mac) the update log is written to @@ -59,7 +61,7 @@ void UpdateLog::Finish() return; } -#if !defined(XP_WIN) +#if !defined(XP_WIN) && !defined(XP_MACOSX) const int blockSize = 1024; char buffer[blockSize]; fflush(logFP); diff --git a/toolkit/mozapps/update/common/updatedefines.h b/toolkit/mozapps/update/common/updatedefines.h index 0db182219a..49fbde6f2f 100644 --- a/toolkit/mozapps/update/common/updatedefines.h +++ b/toolkit/mozapps/update/common/updatedefines.h @@ -100,6 +100,10 @@ static inline int mywcsprintf(WCHAR* dest, size_t count, const WCHAR* fmt, ...) #endif # include <dirent.h> +#ifdef XP_MACOSX +# include <sys/time.h> +#endif + # define LOG_S "%s" # define NS_T(str) str # define NS_SLASH NS_T('/') diff --git a/toolkit/mozapps/update/nsUpdateService.js b/toolkit/mozapps/update/nsUpdateService.js index 9bea453dbb..ce9be2c512 100644 --- a/toolkit/mozapps/update/nsUpdateService.js +++ b/toolkit/mozapps/update/nsUpdateService.js @@ -315,6 +315,36 @@ function areDirectoryEntriesWriteable(aDir) { } /** + * OSX only function to determine if the user requires elevation to be able to + * write to the application bundle. + * + * @return true if elevation is required, false otherwise + */ +function getElevationRequired() { +#ifdef XP_MACOSX + try { + // Recursively check that the application bundle (and its descendants) can + // be written to. + LOG("getElevationRequired - recursively testing write access on " + + getInstallDirRoot().path); + if (!getInstallDirRoot().isWritable() || + !areDirectoryEntriesWriteable(getInstallDirRoot())) { + LOG("getElevationRequired - unable to write to application bundle, " + + "elevation required"); + return true; + } + } catch (ex) { + LOG("getElevationRequired - unable to write to application bundle, " + + "elevation required. Exception: " + ex); + return true; + } + LOG("getElevationRequired - able to write to application bundle, elevation " + + "not required"); +#endif + return false; +} + +/** * Determines whether or not an update can be applied. This is always true on * Windows when the service is used. Also, this is always true on OSX because we * offer users the option to perform an elevated update when necessary. @@ -322,6 +352,7 @@ function areDirectoryEntriesWriteable(aDir) { * @return true if an update can be applied, false otherwise */ function getCanApplyUpdates() { +#ifndef XP_MACOSX try { let updateTestFile = getUpdateFile([FILE_UPDATE_TEST]); LOG("getCanApplyUpdates - testing write access " + updateTestFile.path); @@ -400,6 +431,7 @@ function getCanApplyUpdates() { // No write privileges to install directory return false; } +#endif // !XP_MACOSX LOG("getCanApplyUpdates - able to apply updates"); return true; @@ -412,17 +444,28 @@ function getCanApplyUpdates() { * @return true if updates can be staged for this session. */ XPCOMUtils.defineLazyGetter(this, "gCanStageUpdatesSession", function aus_gCSUS() { + if (getElevationRequired()) { + LOG("gCanStageUpdatesSession - unable to stage updates because elevation " + + "is required."); + return false; + } + try { let updateTestFile; +#ifdef XP_MACOSX + updateTestFile = getUpdateFile([FILE_UPDATE_TEST]); +#else updateTestFile = getInstallDirRoot(); updateTestFile.append(FILE_UPDATE_TEST); +#endif LOG("gCanStageUpdatesSession - testing write access " + updateTestFile.path); testWriteAccess(updateTestFile, true); - // On all platforms, we need to test the parent directory as well, - // as we need to be able to move files in that directory during the +#ifndef XP_MACOSX + // On all platforms except Mac, we need to test the parent directory as + // well, as we need to be able to move files in that directory during the // replacing step. updateTestFile = getInstallDirRoot().parent; updateTestFile.append(FILE_UPDATE_TEST); @@ -431,6 +474,7 @@ XPCOMUtils.defineLazyGetter(this, "gCanStageUpdatesSession", function aus_gCSUS( updateTestFile.createUnique(Ci.nsILocalFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); updateTestFile.remove(false); +#endif // !XP_MACOSX } catch (e) { LOG("gCanStageUpdatesSession - unable to stage updates. Exception: " + e); @@ -549,6 +593,10 @@ function getAppBaseDir() { */ function getInstallDirRoot() { let dir = getAppBaseDir(); +#ifdef XP_MACOSX + // On Mac, we store the Updated.app directory inside the bundle directory. + dir = dir.parent.parent; +#endif return dir; } @@ -832,7 +880,31 @@ function handleUpdateFailure(update, errorCode) { cancelations++; Services.prefs.setIntPref(PREF_APP_UPDATE_CANCELATIONS, cancelations); +#ifdef XP_MACOSX + let osxCancelations = Services.prefs.getIntPref(PREF_APP_UPDATE_CANCELATIONS_OSX, 0); + osxCancelations++; + Services.prefs.setIntPref(PREF_APP_UPDATE_CANCELATIONS_OSX, + osxCancelations); + let maxCancels = Services.prefs.getIntPref( + PREF_APP_UPDATE_CANCELATIONS_OSX_MAX, + DEFAULT_CANCELATIONS_OSX_MAX); + // Prevent the preference from setting a value greater than 5. + maxCancels = Math.min(maxCancels, 5); + if (osxCancelations >= maxCancels) { + cleanupActiveUpdate(); + } else { + writeStatusFile(getUpdatesDir(), + update.state = STATE_PENDING_ELEVATE); + } + update.statusText = gUpdateBundle.GetStringFromName("elevationFailure"); + update.QueryInterface(Ci.nsIWritablePropertyBag); + update.setProperty("patchingFailed", "elevationFailure"); + let prompter = Cc["@mozilla.org/updates/update-prompt;1"]. + createInstance(Ci.nsIUpdatePrompt); + prompter.showUpdateError(update); +#else writeStatusFile(getUpdatesDir(), update.state = STATE_PENDING); +#endif return true; } @@ -1778,6 +1850,58 @@ UpdateService.prototype = { }); let update = minorUpdate || majorUpdate; +#ifdef XP_MACOSX + if (update) { + if (getElevationRequired()) { + let installAttemptVersion = Services.prefs.getCharPref( + PREF_APP_UPDATE_ELEVATE_VERSION, + ""); + if (vc.compare(installAttemptVersion, update.appVersion) != 0) { + Services.prefs.setCharPref(PREF_APP_UPDATE_ELEVATE_VERSION, + update.appVersion); + if (Services.prefs.prefHasUserValue( + PREF_APP_UPDATE_CANCELATIONS_OSX)) { + Services.prefs.clearUserPref(PREF_APP_UPDATE_CANCELATIONS_OSX); + } + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_ELEVATE_NEVER)) { + Services.prefs.clearUserPref(PREF_APP_UPDATE_ELEVATE_NEVER); + } + } else { + let numCancels = Services.prefs.getIntPref(PREF_APP_UPDATE_CANCELATIONS_OSX, 0); + let rejectedVersion = Services.prefs.getCharPref(PREF_APP_UPDATE_ELEVATE_NEVER, ""); + let maxCancels = Services.prefs.getIntPref(PREF_APP_UPDATE_CANCELATIONS_OSX_MAX, + DEFAULT_CANCELATIONS_OSX_MAX); + if (numCancels >= maxCancels) { + LOG("UpdateService:selectUpdate - the user requires elevation to " + + "install this update, but the user has exceeded the max " + + "number of elevation attempts."); + update.elevationFailure = true; + } else if (vc.compare(rejectedVersion, update.appVersion) == 0) { + LOG("UpdateService:selectUpdate - the user requires elevation to " + + "install this update, but elevation is disabled for this " + + "version."); + update.elevationFailure = true; + } else { + LOG("UpdateService:selectUpdate - the user requires elevation to " + + "install the update."); + } + } + } else { + // Clear elevation-related prefs since they no longer apply (the user + // may have gained write access to the Firefox directory or an update + // was executed with a different profile). + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_ELEVATE_VERSION)) { + Services.prefs.clearUserPref(PREF_APP_UPDATE_ELEVATE_VERSION); + } + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_CANCELATIONS_OSX)) { + Services.prefs.clearUserPref(PREF_APP_UPDATE_CANCELATIONS_OSX); + } + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_ELEVATE_NEVER)) { + Services.prefs.clearUserPref(PREF_APP_UPDATE_ELEVATE_NEVER); + } + } + } +#endif return update; }, @@ -1895,8 +2019,7 @@ UpdateService.prototype = { * See nsIUpdateService.idl */ get elevationRequired() { - /** Mac Stub, but keeping this for now to not break the API **/ - return false; + return getElevationRequired(); }, /** @@ -3147,7 +3270,11 @@ Downloader.prototype = { "max fail: " + maxFail + ", " + "retryTimeout: " + retryTimeout); if (Components.isSuccessCode(status)) { if (this._verifyDownload()) { - state = STATE_PENDING; + if (getElevationRequired()) { + state = STATE_PENDING_ELEVATE; + } else { + state = STATE_PENDING; + } if (this.background) { shouldShowPrompt = !getCanStageUpdates(); } diff --git a/toolkit/mozapps/update/updater/progressui.h b/toolkit/mozapps/update/updater/progressui.h index 6dc20e06bc..5462815dee 100644 --- a/toolkit/mozapps/update/updater/progressui.h +++ b/toolkit/mozapps/update/updater/progressui.h @@ -24,6 +24,9 @@ int InitProgressUI(int *argc, NS_tchar ***argv); // Called on the main thread at startup int ShowProgressUI(bool indeterminate = false, bool initUIStrings = true); int InitProgressUIStrings(); +#elif defined(XP_MACOSX) + // Called on the main thread at startup + int ShowProgressUI(bool indeterminate = false); #else // Called on the main thread at startup int ShowProgressUI(); diff --git a/toolkit/mozapps/update/updater/updater.cpp b/toolkit/mozapps/update/updater/updater.cpp index 13d829243f..f5f71935dc 100644 --- a/toolkit/mozapps/update/updater/updater.cpp +++ b/toolkit/mozapps/update/updater/updater.cpp @@ -53,6 +53,9 @@ #include <algorithm> #include "updatecommon.h" +#ifdef XP_MACOSX +#include "updaterfileutils_osx.h" +#endif // XP_MACOSX #include "mozilla/Compiler.h" #include "mozilla/Types.h" @@ -72,6 +75,23 @@ #define PARENT_WAIT 10000 #endif +#if defined(XP_MACOSX) +// These functions are defined in launchchild_osx.mm +void CleanupElevatedMacUpdate(bool aFailureOccurred); +bool IsOwnedByGroupAdmin(const char* aAppBundle); +bool IsRecursivelyWritable(const char* aPath); +void LaunchChild(int argc, const char** argv); +void LaunchMacPostProcess(const char* aAppBundle); +bool ObtainUpdaterArguments(int* argc, char*** argv); +bool ServeElevatedUpdate(int argc, const char** argv); +void SetGroupOwnershipAndPermissions(const char* aAppBundle); +struct UpdateServerThreadArgs +{ + int argc; + const NS_tchar** argv; +}; +#endif + #ifndef _O_BINARY # define _O_BINARY 0 #endif @@ -86,13 +106,14 @@ // We want to use execv to invoke the callback executable on platforms where // we were launched using execv. See nsUpdateDriver.cpp. -#if defined(XP_UNIX) +#if defined(XP_UNIX) && !defined(XP_MACOSX) #define USE_EXECV #endif # define MAYBE_USE_HARD_LINKS 0 -#if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(XP_WIN) +#if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(XP_WIN) && \ + !defined(XP_MACOSX) #include "nss.h" #include "prerror.h" #endif @@ -1675,6 +1696,21 @@ PatchFile::Execute() AutoFile ofile(ensure_open(mFile.get(), shouldTruncate ? NS_T("wb+") : NS_T("rb+"), ss.st_mode)); +#elif defined(XP_MACOSX) + AutoFile ofile(ensure_open(mFile.get(), NS_T("wb+"), ss.st_mode)); + // Modified code from FileUtils.cpp + fstore_t store = {F_ALLOCATECONTIG, F_PEOFPOSMODE, 0, header.dlen}; + // Try to get a continous chunk of disk space + rv = fcntl(fileno((FILE *)ofile), F_PREALLOCATE, &store); + if (rv == -1) { + // OK, perhaps we are too fragmented, allocate non-continuous + store.fst_flags = F_ALLOCATEALL; + rv = fcntl(fileno((FILE *)ofile), F_PREALLOCATE, &store); + } + + if (rv != -1) { + ftruncate(fileno((FILE *)ofile), header.dlen); + } #else AutoFile ofile(ensure_open(mFile.get(), NS_T("wb+"), ss.st_mode)); #endif @@ -2055,6 +2091,8 @@ LaunchCallbackApp(const NS_tchar *workingDir, #if defined(USE_EXECV) execv(argv[0], argv); +#elif defined(XP_MACOSX) + LaunchChild(argc, (const char**)argv); #elif defined(XP_WIN) WinLaunchChild(argv[0], argc, argv, nullptr); #else @@ -2170,15 +2208,19 @@ CopyInstallDirToDestDir() // These files should not be copied over to the updated app #ifdef XP_WIN #define SKIPLIST_COUNT 3 +#elif XP_MACOSX +#define SKIPLIST_COUNT 0 #else #define SKIPLIST_COUNT 2 #endif copy_recursive_skiplist<SKIPLIST_COUNT> skiplist; +#ifndef XP_MACOSX skiplist.append(0, gInstallDirPath, NS_T("updated")); skiplist.append(1, gInstallDirPath, NS_T("updates/0")); #ifdef XP_WIN skiplist.append(2, gInstallDirPath, NS_T("updated.update_in_progress.lock")); #endif +#endif return ensure_copy_recursive(gInstallDirPath, gWorkingDirPath, skiplist); } @@ -2197,7 +2239,11 @@ ProcessReplaceRequest() // 2. Move newDir to destDir. In case of failure, revert step 1 and abort. // 3. Delete tmpDir (or defer it to the next reboot). -#if XP_WIN +#ifdef XP_MACOSX + NS_tchar destDir[MAXPATHLEN]; + NS_tsnprintf(destDir, sizeof(destDir)/sizeof(destDir[0]), + NS_T("%s/Contents"), gInstallDirPath); +#elif XP_WIN // Windows preserves the case of the file/directory names. We use the // GetLongPathName API in order to get the correct case for the directory // name, so that if the user has used a different case when launching the @@ -2217,8 +2263,13 @@ ProcessReplaceRequest() NS_tchar newDir[MAXPATHLEN]; NS_tsnprintf(newDir, sizeof(newDir)/sizeof(newDir[0]), +#ifdef XP_MACOSX + NS_T("%s/Contents"), + gWorkingDirPath); +#else NS_T("%s.bak/updated"), gInstallDirPath); +#endif // First try to remove the possibly existing temp directory, because if this // directory exists, we will fail to rename destDir. @@ -2256,6 +2307,14 @@ ProcessReplaceRequest() LOG(("Begin moving newDir (" LOG_S ") to destDir (" LOG_S ")", newDir, destDir)); rv = rename_file(newDir, destDir, true); +#ifdef XP_MACOSX + if (rv) { + LOG(("Moving failed. Begin copying newDir (" LOG_S ") to destDir (" LOG_S ")", + newDir, destDir)); + copy_recursive_skiplist<0> skiplist; + rv = ensure_copy_recursive(newDir, destDir, skiplist); + } +#endif if (rv) { LOG(("Moving newDir to destDir failed, err: %d", rv)); LOG(("Now, try to move tmpDir back to destDir")); @@ -2269,7 +2328,7 @@ ProcessReplaceRequest() return rv; } -#if !defined(XP_WIN) +#if !defined(XP_WIN) && !defined(XP_MACOSX) // Platforms that have their updates directory in the installation directory // need to have the last-update.log and backup-update.log files moved from the // old installation directory to the new installation directory. @@ -2303,6 +2362,15 @@ ProcessReplaceRequest() #endif } +#ifdef XP_MACOSX + // On OS X, we we need to remove the staging directory after its Contents + // directory has been moved. + NS_tchar updatedAppDir[MAXPATHLEN]; + NS_tsnprintf(updatedAppDir, sizeof(updatedAppDir)/sizeof(updatedAppDir[0]), + NS_T("%s/Updated.app"), gPatchDirPath); + ensure_remove_recursive(updatedAppDir); +#endif + gSucceeded = true; return 0; @@ -2412,7 +2480,11 @@ UpdateThreadFunc(void *param) NS_tchar updateSettingsPath[MAX_TEXT_LEN]; NS_tsnprintf(updateSettingsPath, sizeof(updateSettingsPath) / sizeof(updateSettingsPath[0]), +#ifdef XP_MACOSX + NS_T("%s/Contents/Resources/update-settings.ini"), +#else NS_T("%s/update-settings.ini"), +#endif gWorkingDirPath); MARChannelStringTable MARStrings; if (ReadMARChannelIDs(updateSettingsPath, &MARStrings) != OK) { @@ -2484,6 +2556,15 @@ UpdateThreadFunc(void *param) if (rv) { LOG(("failed: %d", rv)); } else { +#ifdef XP_MACOSX + // If the update was successful we need to update the timestamp on the + // top-level Mac OS X bundle directory so that Mac OS X's Launch Services + // picks up any major changes when the bundle is updated. + if (!sStagedUpdate && utimes(gInstallDirPath, nullptr) != 0) { + LOG(("Couldn't set access/modification time on application bundle.")); + } +#endif + LOG(("succeeded")); } WriteStatusFile(rv); @@ -2493,11 +2574,34 @@ UpdateThreadFunc(void *param) QuitProgressUI(); } +#ifdef XP_MACOSX +static void +ServeElevatedUpdateThreadFunc(void* param) +{ + UpdateServerThreadArgs* threadArgs = (UpdateServerThreadArgs*)param; + gSucceeded = ServeElevatedUpdate(threadArgs->argc, threadArgs->argv); + if (!gSucceeded) { + WriteStatusFile(ELEVATION_CANCELED); + } + QuitProgressUI(); +} + +void freeArguments(int argc, char** argv) +{ + for (int i = 0; i < argc; i++) { + free(argv[i]); + } + free(argv); +} +#endif + int LaunchCallbackAndPostProcessApps(int argc, NS_tchar** argv, int callbackIndex #ifdef XP_WIN , const WCHAR* elevatedLockFilePath , HANDLE updateLockFileHandle +#elif XP_MACOSX + , bool isElevated #endif ) { @@ -2509,11 +2613,19 @@ int LaunchCallbackAndPostProcessApps(int argc, NS_tchar** argv, } } EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 0); +#elif XP_MACOSX + if (!isElevated) { + if (gSucceeded) { + LaunchMacPostProcess(gInstallDirPath); + } #endif LaunchCallbackApp(argv[5], argc - callbackIndex, argv + callbackIndex); +#ifdef XP_MACOSX + } // if (!isElevated) +#endif /* XP_MACOSX */ } return 0; } @@ -2525,7 +2637,20 @@ int NS_main(int argc, NS_tchar **argv) // argument prior to callbackIndex is the working directory. const int callbackIndex = 6; -#if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(XP_WIN) +#ifdef XP_MACOSX + bool isElevated = + strstr(argv[0], "/Library/PrivilegedHelperTools/org.mozilla.updater") != 0; + if (isElevated) { + if (!ObtainUpdaterArguments(&argc, &argv)) { + // Won't actually get here because ObtainUpdaterArguments will terminate + // the current process on failure. + return 1; + } + } +#endif + +#if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(XP_WIN) && \ + !defined(XP_MACOSX) // On Windows and Mac we rely on native APIs to do verifications so we don't // need to initialize NSS at all there. // Otherwise, minimize the amount of NSS we depend on by avoiding all the NSS @@ -2538,7 +2663,13 @@ int NS_main(int argc, NS_tchar **argv) } #endif - InitProgressUI(&argc, &argv); +#ifdef XP_MACOSX + if (!isElevated) { +#endif + InitProgressUI(&argc, &argv); +#ifdef XP_MACOSX + } +#endif // To process an update the updater command line must at a minimum have the // directory path containing the updater.mar file to process as the first @@ -2556,6 +2687,12 @@ int NS_main(int argc, NS_tchar **argv) // launched. if (argc < 4) { fprintf(stderr, "Usage: updater patch-dir install-dir apply-to-dir [wait-pid [callback-working-dir callback-path args...]]\n"); +#ifdef XP_MACOSX + if (isElevated) { + freeArguments(argc, argv); + CleanupElevatedMacUpdate(true); + } +#endif return 1; } @@ -2564,6 +2701,12 @@ int NS_main(int argc, NS_tchar **argv) // directory is invalid don't write the status file. fprintf(stderr, "The patch directory path is not valid for this " \ "application (" LOG_S ")\n", argv[1]); +#ifdef XP_MACOSX + if (isElevated) { + freeArguments(argc, argv); + CleanupElevatedMacUpdate(true); + } +#endif return 1; } // The directory containing the update information. @@ -2573,6 +2716,12 @@ int NS_main(int argc, NS_tchar **argv) WriteStatusFile(INVALID_INSTALL_DIR_PATH_ERROR); fprintf(stderr, "The install directory path is not valid for this " \ "application (" LOG_S ")\n", argv[2]); +#ifdef XP_MACOSX + if (isElevated) { + freeArguments(argc, argv); + CleanupElevatedMacUpdate(true); + } +#endif return 1; } // The directory we're going to update to. @@ -2635,6 +2784,12 @@ int NS_main(int argc, NS_tchar **argv) WriteStatusFile(INVALID_WORKING_DIR_PATH_ERROR); fprintf(stderr, "The working directory path is not valid for this " \ "application (" LOG_S ")\n", argv[3]); +#ifdef XP_MACOSX + if (isElevated) { + freeArguments(argc, argv); + CleanupElevatedMacUpdate(true); + } +#endif return 1; } // The directory we're going to update to. @@ -2653,6 +2808,12 @@ int NS_main(int argc, NS_tchar **argv) WriteStatusFile(INVALID_CALLBACK_PATH_ERROR); fprintf(stderr, "The callback file path is not valid for this " \ "application (" LOG_S ")\n", argv[callbackIndex]); +#ifdef XP_MACOSX + if (isElevated) { + freeArguments(argc, argv); + CleanupElevatedMacUpdate(true); + } +#endif return 1; } @@ -2663,10 +2824,37 @@ int NS_main(int argc, NS_tchar **argv) WriteStatusFile(INVALID_CALLBACK_DIR_ERROR); fprintf(stderr, "The callback file must be located in the " \ "installation directory (" LOG_S ")\n", argv[callbackIndex]); +#ifdef XP_MACOSX + if (isElevated) { + freeArguments(argc, argv); + CleanupElevatedMacUpdate(true); + } +#endif return 1; } } +#ifdef XP_MACOSX + if (!isElevated && !IsRecursivelyWritable(argv[2])) { + // If the app directory isn't recursively writeable, an elevated update is + // required. + UpdateServerThreadArgs threadArgs; + threadArgs.argc = argc; + threadArgs.argv = const_cast<const NS_tchar**>(argv); + + Thread t1; + if (t1.Run(ServeElevatedUpdateThreadFunc, &threadArgs) == 0) { + // Show an indeterminate progress bar while an elevated update is in + // progress. + ShowProgressUI(true); + } + t1.Join(); + + LaunchCallbackAndPostProcessApps(argc, argv, callbackIndex, false); + return gSucceeded ? 0 : 1; + } +#endif + if (EnvHasValue("MOZ_OS_UPDATE")) { sIsOSUpdate = true; putenv(const_cast<char*>("MOZ_OS_UPDATE=")); @@ -2676,6 +2864,12 @@ int NS_main(int argc, NS_tchar **argv) if (!WriteStatusFile("applying")) { LOG(("failed setting status to 'applying'")); +#ifdef XP_MACOSX + if (isElevated) { + freeArguments(argc, argv); + CleanupElevatedMacUpdate(true); + } +#endif return 1; } @@ -2912,6 +3106,12 @@ int NS_main(int argc, NS_tchar **argv) // Try to create the destination directory if it doesn't exist int rv = NS_tmkdir(gWorkingDirPath, 0755); if (rv != OK && errno != EEXIST) { +#ifdef XP_MACOSX + if (isElevated) { + freeArguments(argc, argv); + CleanupElevatedMacUpdate(true); + } +#endif return 1; } } @@ -3152,7 +3352,11 @@ int NS_main(int argc, NS_tchar **argv) // is an elevated process on OSX. Thread t; if (t.Run(UpdateThreadFunc, nullptr) == 0) { - if (!sStagedUpdate && !sReplaceRequest) { + if (!sStagedUpdate && !sReplaceRequest +#ifdef XP_MACOSX + && !isElevated +#endif + ) { ShowProgressUI(); } } @@ -3189,12 +3393,66 @@ int NS_main(int argc, NS_tchar **argv) } #endif /* XP_WIN */ +#ifdef XP_MACOSX + // When the update is successful remove the precomplete file in the root of + // the application bundle and move the distribution directory from + // Contents/MacOS to Contents/Resources and if both exist delete the + // directory under Contents/MacOS (see Bug 1068439). + if (gSucceeded && !sStagedUpdate) { + NS_tchar oldPrecomplete[MAXPATHLEN]; + NS_tsnprintf(oldPrecomplete, sizeof(oldPrecomplete)/sizeof(oldPrecomplete[0]), + NS_T("%s/precomplete"), gInstallDirPath); + NS_tremove(oldPrecomplete); + + NS_tchar oldDistDir[MAXPATHLEN]; + NS_tsnprintf(oldDistDir, sizeof(oldDistDir)/sizeof(oldDistDir[0]), + NS_T("%s/Contents/MacOS/distribution"), gInstallDirPath); + int rv = NS_taccess(oldDistDir, F_OK); + if (!rv) { + NS_tchar newDistDir[MAXPATHLEN]; + NS_tsnprintf(newDistDir, sizeof(newDistDir)/sizeof(newDistDir[0]), + NS_T("%s/Contents/Resources/distribution"), gInstallDirPath); + rv = NS_taccess(newDistDir, F_OK); + if (!rv) { + LOG(("New distribution directory already exists... removing old " \ + "distribution directory: " LOG_S, oldDistDir)); + rv = ensure_remove_recursive(oldDistDir); + if (rv) { + LOG(("Removing old distribution directory failed - err: %d", rv)); + } + } else { + LOG(("Moving old distribution directory to new location. src: " LOG_S \ + ", dst:" LOG_S, oldDistDir, newDistDir)); + rv = rename_file(oldDistDir, newDistDir, true); + if (rv) { + LOG(("Moving old distribution directory to new location failed - " \ + "err: %d", rv)); + } + } + } + } + + if (isElevated) { + SetGroupOwnershipAndPermissions(gInstallDirPath); + freeArguments(argc, argv); + CleanupElevatedMacUpdate(false); + } else if (IsOwnedByGroupAdmin(gInstallDirPath)) { + // If the group ownership of the Firefox .app bundle was set to the "admin" + // group during a previous elevated update, we need to ensure that all files + // in the bundle have group ownership of "admin" as well as write permission + // for the group to not break updates in the future. + SetGroupOwnershipAndPermissions(gInstallDirPath); + } +#endif /* XP_MACOSX */ + LogFinish(); int retVal = LaunchCallbackAndPostProcessApps(argc, argv, callbackIndex #ifdef XP_WIN , elevatedLockFilePath , updateLockFileHandle +#elif XP_MACOSX + , isElevated #endif ); @@ -3650,8 +3908,13 @@ int AddPreCompleteActions(ActionList *list) return OK; } +#ifdef XP_MACOSX + mozilla::UniquePtr<NS_tchar[]> manifestPath(get_full_path( + NS_T("Contents/Resources/precomplete"))); +#else mozilla::UniquePtr<NS_tchar[]> manifestPath(get_full_path( NS_T("precomplete"))); +#endif NS_tchar *rb = GetManifestContents(manifestPath.get()); if (rb == nullptr) { diff --git a/toolkit/profile/content/createProfileWizard.js b/toolkit/profile/content/createProfileWizard.js index f378f36769..aa87eacd71 100644 --- a/toolkit/profile/content/createProfileWizard.js +++ b/toolkit/profile/content/createProfileWizard.js @@ -116,7 +116,11 @@ function checkCurrentInput(currentInput) if (!errorMessage) { finishText.className = ""; +#ifdef XP_MACOSX + finishText.firstChild.data = gProfileManagerBundle.getString("profileFinishTextMac"); +#else finishText.firstChild.data = gProfileManagerBundle.getString("profileFinishText"); +#endif canAdvance = true; } else { diff --git a/toolkit/profile/content/createProfileWizard.xul b/toolkit/profile/content/createProfileWizard.xul index c7e0702a62..eab1a93414 100644 --- a/toolkit/profile/content/createProfileWizard.xul +++ b/toolkit/profile/content/createProfileWizard.xul @@ -31,11 +31,15 @@ <description>&profileCreationExplanation_2.text;</description> <description>&profileCreationExplanation_3.text;</description> <spacer flex="1"/> +#ifdef XP_MACOSX + <description>&profileCreationExplanation_4Mac.text;</description> +#else #ifdef XP_UNIX <description>&profileCreationExplanation_4Gnome.text;</description> #else <description>&profileCreationExplanation_4.text;</description> #endif +#endif </wizardpage> <wizardpage id="createProfile" onpageshow="initSecondWizardPage();"> diff --git a/toolkit/profile/content/profileSelection.js b/toolkit/profile/content/profileSelection.js index 9fb77dfcd0..05ef6f5edb 100644 --- a/toolkit/profile/content/profileSelection.js +++ b/toolkit/profile/content/profileSelection.js @@ -134,7 +134,9 @@ function onProfilesKey(aEvent) switch ( aEvent.keyCode ) { case KeyEvent.DOM_VK_BACK_SPACE: +#ifndef XP_MACOSX break; +#endif case KeyEvent.DOM_VK_DELETE: ConfirmDelete(); break; diff --git a/toolkit/profile/jar.mn b/toolkit/profile/jar.mn index 9b7c22266e..1c4afac4ca 100644 --- a/toolkit/profile/jar.mn +++ b/toolkit/profile/jar.mn @@ -3,7 +3,7 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. toolkit.jar: - content/mozapps/profile/createProfileWizard.js (content/createProfileWizard.js) +* content/mozapps/profile/createProfileWizard.js (content/createProfileWizard.js) * content/mozapps/profile/createProfileWizard.xul (content/createProfileWizard.xul) - content/mozapps/profile/profileSelection.js (content/profileSelection.js) +* content/mozapps/profile/profileSelection.js (content/profileSelection.js) content/mozapps/profile/profileSelection.xul (content/profileSelection.xul) diff --git a/toolkit/profile/nsProfileLock.cpp b/toolkit/profile/nsProfileLock.cpp index 654fbcd465..d75b6082d3 100644 --- a/toolkit/profile/nsProfileLock.cpp +++ b/toolkit/profile/nsProfileLock.cpp @@ -13,6 +13,11 @@ #include "nsAutoPtr.h" #endif +#if defined(XP_MACOSX) +#include <Carbon/Carbon.h> +#include <CoreFoundation/CoreFoundation.h> +#endif + #ifdef XP_UNIX #include <unistd.h> #include <fcntl.h> @@ -421,7 +426,10 @@ nsresult nsProfileLock::GetReplacedLockTime(PRTime *aResult) { nsresult nsProfileLock::Lock(nsIFile* aProfileDir, nsIProfileUnlocker* *aUnlocker) { -#if defined (XP_UNIX) +#if defined (XP_MACOSX) + NS_NAMED_LITERAL_STRING(LOCKFILE_NAME, ".parentlock"); + NS_NAMED_LITERAL_STRING(OLD_LOCKFILE_NAME, "parent.lock"); +#elif defined (XP_UNIX) NS_NAMED_LITERAL_STRING(OLD_LOCKFILE_NAME, "lock"); NS_NAMED_LITERAL_STRING(LOCKFILE_NAME, ".parentlock"); #else @@ -450,7 +458,67 @@ nsresult nsProfileLock::Lock(nsIFile* aProfileDir, if (NS_FAILED(rv)) return rv; -#if defined(XP_UNIX) +#if defined(XP_MACOSX) + // First, try locking using fcntl. It is more reliable on + // a local machine, but may not be supported by an NFS server. + + rv = LockWithFcntl(lockFile); + if (NS_FAILED(rv) && (rv != NS_ERROR_FILE_ACCESS_DENIED)) + { + // If that failed for any reason other than NS_ERROR_FILE_ACCESS_DENIED, + // assume we tried an NFS that does not support it. Now, try with symlink. + rv = LockWithSymlink(lockFile, false); + } + + if (NS_SUCCEEDED(rv)) + { + // Check for the old-style lock used by pre-mozilla 1.3 builds. + // Those builds used an earlier check to prevent the application + // from launching if another instance was already running. Because + // of that, we don't need to create an old-style lock as well. + struct LockProcessInfo + { + ProcessSerialNumber psn; + unsigned long launchDate; + }; + + PRFileDesc *fd = nullptr; + int32_t ioBytes; + ProcessInfoRec processInfo; + LockProcessInfo lockProcessInfo; + + rv = lockFile->SetLeafName(OLD_LOCKFILE_NAME); + if (NS_FAILED(rv)) + return rv; + rv = lockFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fd); + if (NS_SUCCEEDED(rv)) + { + ioBytes = PR_Read(fd, &lockProcessInfo, sizeof(LockProcessInfo)); + PR_Close(fd); + + if (ioBytes == sizeof(LockProcessInfo)) + { +#ifdef __LP64__ + processInfo.processAppRef = nullptr; +#else + processInfo.processAppSpec = nullptr; +#endif + processInfo.processName = nullptr; + processInfo.processInfoLength = sizeof(ProcessInfoRec); + if (::GetProcessInformation(&lockProcessInfo.psn, &processInfo) == noErr && + processInfo.processLaunchDate == lockProcessInfo.launchDate) + { + return NS_ERROR_FILE_ACCESS_DENIED; + } + } + else + { + NS_WARNING("Could not read lock file - ignoring lock"); + } + } + rv = NS_OK; // Don't propagate error from OpenNSPRFileDesc. + } +#elif defined(XP_UNIX) // Get the old lockfile name nsCOMPtr<nsIFile> oldLockFile; rv = aProfileDir->Clone(getter_AddRefs(oldLockFile)); diff --git a/toolkit/profile/nsToolkitProfileService.cpp b/toolkit/profile/nsToolkitProfileService.cpp index 3380246da1..2fe51b2853 100644 --- a/toolkit/profile/nsToolkitProfileService.cpp +++ b/toolkit/profile/nsToolkitProfileService.cpp @@ -26,6 +26,11 @@ #include "nsIFile.h" #include "nsISimpleEnumerator.h" +#ifdef XP_MACOSX +#include <CoreFoundation/CoreFoundation.h> +#include "nsILocalFileMac.h" +#endif + #include "nsAppDirectoryServiceDefs.h" #include "nsXULAppAPI.h" @@ -1020,7 +1025,33 @@ NS_NewToolkitProfileService(nsIToolkitProfileService* *aResult) nsresult XRE_GetFileFromPath(const char *aPath, nsIFile* *aResult) { -#if defined(XP_UNIX) +#if defined(XP_MACOSX) + int32_t pathLen = strlen(aPath); + if (pathLen > MAXPATHLEN) + return NS_ERROR_INVALID_ARG; + + CFURLRef fullPath = + CFURLCreateFromFileSystemRepresentation(nullptr, (const UInt8 *) aPath, + pathLen, true); + if (!fullPath) + return NS_ERROR_FAILURE; + + nsCOMPtr<nsIFile> lf; + nsresult rv = NS_NewNativeLocalFile(EmptyCString(), true, + getter_AddRefs(lf)); + if (NS_SUCCEEDED(rv)) { + nsCOMPtr<nsILocalFileMac> lfMac = do_QueryInterface(lf, &rv); + if (NS_SUCCEEDED(rv)) { + rv = lfMac->InitWithCFURL(fullPath); + if (NS_SUCCEEDED(rv)) { + lf.forget(aResult); + } + } + } + CFRelease(fullPath); + return rv; + +#elif defined(XP_UNIX) char fullPath[MAXPATHLEN]; if (!realpath(aPath, fullPath)) diff --git a/toolkit/themes/shared/aboutReader.css b/toolkit/themes/shared/aboutReader.css index c6cd959277..1bfbd0309d 100644 --- a/toolkit/themes/shared/aboutReader.css +++ b/toolkit/themes/shared/aboutReader.css @@ -388,7 +388,19 @@ body:not(.loaded) .toolbar:-moz-locale-dir(rtl) { } /* Font sizes are different per-platform, so we need custom CSS to line them up. */ -%ifdef XP_WIN +%ifdef XP_MACOSX +.font-type-buttons > .sans-serif-button > .name { + margin-top: 10px; +} + +.font-type-buttons > .sans-serif-button > .description { + margin-top: -4px; +} + +.font-type-buttons > .serif-button > .name { + font-size: 63px; +} +%elifdef XP_WIN .font-type-buttons > .sans-serif-button > .name { margin-top: 2px; } diff --git a/toolkit/themes/shared/jar.inc.mn b/toolkit/themes/shared/jar.inc.mn index 08f3250dcc..3755688279 100644 --- a/toolkit/themes/shared/jar.inc.mn +++ b/toolkit/themes/shared/jar.inc.mn @@ -62,7 +62,7 @@ toolkit.jar: skin/classic/global/media/TopLevelVideoDocument.css (../../shared/media/TopLevelVideoDocument.css) skin/classic/global/media/imagedoc-lightnoise.png (../../shared/media/imagedoc-lightnoise.png) skin/classic/global/media/imagedoc-darknoise.png (../../shared/media/imagedoc-darknoise.png) - skin/classic/global/media/videocontrols.css (../../shared/media/videocontrols.css) +* skin/classic/global/media/videocontrols.css (../../shared/media/videocontrols.css) skin/classic/global/media/pauseButton.png (../../shared/media/pauseButton.png) skin/classic/global/media/pauseButton@2x.png (../../shared/media/pauseButton@2x.png) skin/classic/global/media/playButton.png (../../shared/media/playButton.png) diff --git a/toolkit/themes/shared/media/videocontrols.css b/toolkit/themes/shared/media/videocontrols.css index 690762062b..a40d77fe3a 100644 --- a/toolkit/themes/shared/media/videocontrols.css +++ b/toolkit/themes/shared/media/videocontrols.css @@ -165,9 +165,15 @@ font-size: 11px; } +%ifdef XP_MACOSX +.durationLabel { + padding-top: 2px; /* center vertically with scrubber bar */ +} +%else .durationLabel { padding-top: 0; /* center vertically with scrubber bar */ } +%endif .positionLabel { display: none; @@ -253,9 +259,15 @@ padding-top: 7px; } +%ifdef XP_MACOSX +.timeLabel { + padding-top: 7px; /* center vertically with scrubber bar */ +} +%else .timeLabel { padding-top: 5px; /* center vertically with scrubber bar */ } +%endif .statusOverlay { -moz-box-align: center; diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index b15335ade3..274631aac8 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -31,6 +31,16 @@ #include "EventTracer.h" #endif +#ifdef XP_MACOSX +#include "nsVersionComparator.h" +#include "MacLaunchHelper.h" +#include "MacApplicationDelegate.h" +#include "MacAutoreleasePool.h" +// these are needed for sysctl +#include <sys/types.h> +#include <sys/sysctl.h> +#endif + #include "prmem.h" #include "prnetdb.h" #include "prprf.h" @@ -144,6 +154,11 @@ #include "WinUtils.h" #endif +#ifdef XP_MACOSX +#include "nsILocalFileMac.h" +#include "nsCommandLineServiceMac.h" +#endif + // for X remote support #ifdef MOZ_ENABLE_XREMOTE #include "XRemoteClient.h" @@ -159,6 +174,10 @@ #include <malloc.h> #endif +#if defined (XP_MACOSX) +#include <Carbon/Carbon.h> +#endif + #ifdef DEBUG #include "mozilla/Logging.h" #endif @@ -1072,6 +1091,12 @@ ScopedXPCOMStartup::~ScopedXPCOMStartup() NS_IF_RELEASE(gNativeAppSupport); if (mServiceManager) { +#ifdef XP_MACOSX + // On OS X, we need a pool to catch cocoa objects that are autoreleased + // during teardown. + mozilla::MacAutoreleasePool pool; +#endif + nsCOMPtr<nsIAppStartup> appStartup (do_GetService(NS_APPSTARTUP_CONTRACTID)); if (appStartup) appStartup->DestroyHiddenWindow(); @@ -1457,6 +1482,10 @@ static nsresult LaunchChild(nsINativeAppSupport* aNative, SaveToEnv("MOZ_LAUNCHED_CHILD=1"); +#if defined(XP_MACOSX) + CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv, true); + LaunchChildMac(gRestartArgc, gRestartArgv); +#else nsCOMPtr<nsIFile> lf; nsresult rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf)); if (NS_FAILED(rv)) @@ -1491,6 +1520,7 @@ static nsresult LaunchChild(nsINativeAppSupport* aNative, return NS_ERROR_FAILURE; #endif // XP_UNIX #endif // WP_WIN +#endif // WP_MACOSX return NS_ERROR_LAUNCHED_CHILD_PROCESS; } @@ -1559,9 +1589,15 @@ ProfileLockedDialog(nsIFile* aProfileDir, nsIFile* aProfileLocalDir, const char16_t* params[] = {appName.get(), appName.get()}; nsXPIDLString killMessage; +#ifndef XP_MACOSX sb->FormatStringFromName(aUnlocker ? u"restartMessageUnlocker" : u"restartMessageNoUnlocker", params, 2, getter_Copies(killMessage)); +#else + sb->FormatStringFromName(aUnlocker ? u"restartMessageUnlockerMac" + : u"restartMessageNoUnlockerMac", + params, 2, getter_Copies(killMessage)); +#endif nsXPIDLString killTitle; sb->FormatStringFromName(u"restartTitle", @@ -1705,6 +1741,10 @@ ShowProfileManager(nsIToolkitProfileService* aProfileSvc, rv = xpcom.SetWindowCreator(aNative); NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); +#ifdef XP_MACOSX + CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv, true); +#endif + #ifdef XP_WIN // we don't have to wait here because profile manager window will pump // and DDE message will be handled @@ -2810,6 +2850,13 @@ XREMain::XRE_mainInit(bool* aExitFlag) if (NS_FAILED(rv)) return 2; +#ifdef XP_MACOSX + nsCOMPtr<nsIFile> parent; + greDir->GetParent(getter_AddRefs(parent)); + greDir = parent.forget(); + greDir->AppendNative(NS_LITERAL_CSTRING("Resources")); +#endif + greDir.forget(&mAppData->xreDirectory); } @@ -2843,6 +2890,40 @@ XREMain::XRE_mainInit(bool* aExitFlag) if (NS_FAILED(rv)) return 1; +#ifdef XP_MACOSX + // Set up ability to respond to system (Apple) events. This must occur before + // ProcessUpdates to ensure that links clicked in external applications aren't + // lost when updates are pending. + SetupMacApplicationDelegate(); + + if (EnvHasValue("MOZ_LAUNCHED_CHILD")) { + // This is needed, on relaunch, to force the OS to use the "Cocoa Dock + // API". Otherwise the call to ReceiveNextEvent() below will make it + // use the "Carbon Dock API". For more info see bmo bug 377166. + EnsureUseCocoaDockAPI(); + + // When the app relaunches, the original process exits. This causes + // the dock tile to stop bouncing, lose the "running" triangle, and + // if the tile does not permanently reside in the Dock, even disappear. + // This can be confusing to the user, who is expecting the app to launch. + // Calling ReceiveNextEvent without requesting any event is enough to + // cause a dock tile for the child process to appear. + const EventTypeSpec kFakeEventList[] = { { INT_MAX, INT_MAX } }; + EventRef event; + ::ReceiveNextEvent(GetEventTypeCount(kFakeEventList), kFakeEventList, + kEventDurationNoWait, false, &event); + } + + if (CheckArg("foreground")) { + // The original process communicates that it was in the foreground by + // adding this argument. This new process, which is taking over for + // the old one, should make itself the active application. + ProcessSerialNumber psn; + if (::GetCurrentProcess(&psn) == noErr) + ::SetFrontProcess(&psn); + } +#endif + SaveToEnv("MOZ_LAUNCHED_CHILD="); gRestartArgc = gArgc; @@ -2893,6 +2974,12 @@ XREMain::XRE_mainInit(bool* aExitFlag) } #endif +#ifdef XP_MACOSX + if ((GetCurrentEventKeyModifiers() & optionKey) && + !EnvHasValue("MOZ_DISABLE_SAFE_MODE_KEY")) + gSafeMode = true; +#endif + #ifdef XP_WIN { // Add CPU microcode version to the crash report as "CPUMicrocodeVersion". @@ -3666,6 +3753,19 @@ XREMain::XRE_mainRun() g_unsetenv ("DESKTOP_STARTUP_ID"); #endif +#ifdef XP_MACOSX + // we re-initialize the command-line service and do appleevents munging + // after we are sure that we're not restarting + cmdLine = do_CreateInstance("@mozilla.org/toolkit/command-line;1"); + NS_ENSURE_TRUE(cmdLine, NS_ERROR_FAILURE); + + CommandLineServiceMac::SetupMacCommandLine(gArgc, gArgv, false); + + rv = cmdLine->Init(gArgc, gArgv, + workingDir, nsICommandLine::STATE_INITIAL_LAUNCH); + NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); +#endif + nsCOMPtr<nsIObserverService> obsService = mozilla::services::GetObserverService(); if (obsService) diff --git a/toolkit/xre/nsEmbedFunctions.cpp b/toolkit/xre/nsEmbedFunctions.cpp index 841ea2a2d0..109782b5f8 100644 --- a/toolkit/xre/nsEmbedFunctions.cpp +++ b/toolkit/xre/nsEmbedFunctions.cpp @@ -39,6 +39,10 @@ #include "nsXREDirProvider.h" #include "mozilla/Omnijar.h" +#if defined(XP_MACOSX) +#include "nsVersionComparator.h" +#include "chrome/common/mach_ipc_mac.h" +#endif #include "nsX11ErrorHandler.h" #include "nsGDKErrorHandler.h" #include "base/at_exit.h" @@ -280,6 +284,81 @@ XRE_InitChildProcess(int aArgc, PROFILER_LABEL("Startup", "XRE_InitChildProcess", js::ProfileEntry::Category::OTHER); + // Complete 'task_t' exchange for Mac OS X. This structure has the same size + // regardless of architecture so we don't have any cross-arch issues here. +#ifdef XP_MACOSX + if (aArgc < 1) + return NS_ERROR_FAILURE; + const char* const mach_port_name = aArgv[--aArgc]; + + const int kTimeoutMs = 1000; + + MachSendMessage child_message(0); + if (!child_message.AddDescriptor(MachMsgPortDescriptor(mach_task_self()))) { + NS_WARNING("child AddDescriptor(mach_task_self()) failed."); + return NS_ERROR_FAILURE; + } + + ReceivePort child_recv_port; + mach_port_t raw_child_recv_port = child_recv_port.GetPort(); + if (!child_message.AddDescriptor(MachMsgPortDescriptor(raw_child_recv_port))) { + NS_WARNING("Adding descriptor to message failed"); + return NS_ERROR_FAILURE; + } + + ReceivePort* ports_out_receiver = new ReceivePort(); + if (!child_message.AddDescriptor(MachMsgPortDescriptor(ports_out_receiver->GetPort()))) { + NS_WARNING("Adding descriptor to message failed"); + return NS_ERROR_FAILURE; + } + + ReceivePort* ports_in_receiver = new ReceivePort(); + if (!child_message.AddDescriptor(MachMsgPortDescriptor(ports_in_receiver->GetPort()))) { + NS_WARNING("Adding descriptor to message failed"); + return NS_ERROR_FAILURE; + } + + MachPortSender child_sender(mach_port_name); + kern_return_t err = child_sender.SendMessage(child_message, kTimeoutMs); + if (err != KERN_SUCCESS) { + NS_WARNING("child SendMessage() failed"); + return NS_ERROR_FAILURE; + } + + MachReceiveMessage parent_message; + err = child_recv_port.WaitForMessage(&parent_message, kTimeoutMs); + if (err != KERN_SUCCESS) { + NS_WARNING("child WaitForMessage() failed"); + return NS_ERROR_FAILURE; + } + + if (parent_message.GetTranslatedPort(0) == MACH_PORT_NULL) { + NS_WARNING("child GetTranslatedPort(0) failed"); + return NS_ERROR_FAILURE; + } + + err = task_set_bootstrap_port(mach_task_self(), + parent_message.GetTranslatedPort(0)); + + if (parent_message.GetTranslatedPort(1) == MACH_PORT_NULL) { + NS_WARNING("child GetTranslatedPort(1) failed"); + return NS_ERROR_FAILURE; + } + MachPortSender* ports_out_sender = new MachPortSender(parent_message.GetTranslatedPort(1)); + + if (parent_message.GetTranslatedPort(2) == MACH_PORT_NULL) { + NS_WARNING("child GetTranslatedPort(2) failed"); + return NS_ERROR_FAILURE; + } + MachPortSender* ports_in_sender = new MachPortSender(parent_message.GetTranslatedPort(2)); + + if (err != KERN_SUCCESS) { + NS_WARNING("child task_set_bootstrap_port() failed"); + return NS_ERROR_FAILURE; + } + +#endif + SetupErrorHandling(aArgv[0]); gArgv = aArgv; @@ -325,6 +404,11 @@ XRE_InitChildProcess(int aArgc, base::ProcessId parentPID = strtol(parentPIDString, &end, 10); MOZ_ASSERT(!*end, "invalid parent PID"); +#ifdef XP_MACOSX + mozilla::ipc::SharedMemoryBasic::SetupMachMemory(parentPID, ports_in_receiver, ports_in_sender, + ports_out_sender, ports_out_receiver, true); +#endif + #if defined(XP_WIN) // On Win7+, register the application user model id passed in by // parent. This insures windows created by the container properly @@ -456,6 +540,11 @@ XRE_InitChildProcess(int aArgc, // scope and being deleted process->CleanUp(); mozilla::Omnijar::CleanUp(); + +#if defined(XP_MACOSX) + // Everybody should be done using shared memory by now. + mozilla::ipc::SharedMemoryBasic::Shutdown(); +#endif } } @@ -571,6 +660,47 @@ XRE_RunAppShell() { nsCOMPtr<nsIAppShell> appShell(do_GetService(kAppShellCID)); NS_ENSURE_TRUE(appShell, NS_ERROR_FAILURE); +#if defined(XP_MACOSX) + { + // In content processes that want XPCOM (and hence want + // AppShell), we usually run our hybrid event loop through + // MessagePump::Run(), by way of nsBaseAppShell::Run(). The + // Cocoa nsAppShell impl, however, implements its own Run() + // that's unaware of MessagePump. That's all rather suboptimal, + // but oddly enough not a problem... usually. + // + // The problem with this setup comes during startup. + // XPCOM-in-subprocesses depends on IPC, e.g. to init the pref + // service, so we have to init IPC first. But, IPC also + // indirectly kinda-depends on XPCOM, because MessagePump + // schedules work from off-main threads (e.g. IO thread) by + // using NS_DispatchToMainThread(). If the IO thread receives a + // Message from the parent before nsThreadManager is + // initialized, then DispatchToMainThread() will fail, although + // MessagePump will remember the task. This race condition + // isn't a problem when appShell->Run() ends up in + // MessagePump::Run(), because MessagePump will immediate see it + // has work to do. It *is* a problem when we end up in [NSApp + // run], because it's not aware that MessagePump has work that + // needs to be processed; that was supposed to be signaled by + // nsIRunnable(s). + // + // So instead of hacking Cocoa nsAppShell or rewriting the + // event-loop system, we compromise here by processing any tasks + // that might have been enqueued on MessagePump, *before* + // MessagePump::ScheduleWork was able to successfully + // DispatchToMainThread(). + MessageLoop* loop = MessageLoop::current(); + bool couldNest = loop->NestableTasksAllowed(); + + loop->SetNestableTasksAllowed(true); + RefPtr<Runnable> task = new MessageLoop::QuitTask(); + loop->PostTask(task.forget()); + loop->Run(); + + loop->SetNestableTasksAllowed(couldNest); + } +#endif // XP_MACOSX return appShell->Run(); } @@ -589,6 +719,16 @@ XRE_ShutdownChildProcess() // (4) ProcessChild joins the IO thread // (5) exit() MessageLoop::current()->Quit(); +#if defined(XP_MACOSX) + nsCOMPtr<nsIAppShell> appShell(do_GetService(kAppShellCID)); + if (appShell) { + // On Mac, we might be only above nsAppShell::Run(), not + // MessagePump::Run(). See XRE_RunAppShell(). To account for + // that case, we fire off an Exit() here. If we were indeed + // above MessagePump::Run(), this Exit() is just superfluous. + appShell->Exit(); + } +#endif // XP_MACOSX } namespace { diff --git a/toolkit/xre/nsSigHandlers.cpp b/toolkit/xre/nsSigHandlers.cpp index 68d909848c..11648e45ac 100644 --- a/toolkit/xre/nsSigHandlers.cpp +++ b/toolkit/xre/nsSigHandlers.cpp @@ -154,6 +154,22 @@ static void fpehandler(int signum, siginfo_t *si, void *context) NS_DebugBreak(NS_DEBUG_ABORT, "Divide by zero", nullptr, __FILE__, __LINE__); } +#ifdef XP_MACOSX + ucontext_t *uc = (ucontext_t *)context; + +#if defined(__i386__) || defined(__amd64__) + _STRUCT_FP_CONTROL *ctrl = &uc->uc_mcontext->__fs.__fpu_fcw; + ctrl->__invalid = ctrl->__denorm = ctrl->__zdiv = ctrl->__ovrfl = ctrl->__undfl = ctrl->__precis = 1; + + _STRUCT_FP_STATUS *status = &uc->uc_mcontext->__fs.__fpu_fsw; + status->__invalid = status->__denorm = status->__zdiv = status->__ovrfl = status->__undfl = + status->__precis = status->__stkflt = status->__errsumm = 0; + + uint32_t *mxcsr = &uc->uc_mcontext->__fs.__fpu_mxcsr; + *mxcsr |= SSE_EXCEPTION_MASK; /* disable all SSE exceptions */ + *mxcsr &= ~SSE_STATUS_FLAGS; /* clear all pending SSE exceptions */ +#endif +#endif #if defined(LINUX) ucontext_t *uc = (ucontext_t *)context; diff --git a/toolkit/xre/nsUpdateDriver.cpp b/toolkit/xre/nsUpdateDriver.cpp index 812818788c..4994458852 100644 --- a/toolkit/xre/nsUpdateDriver.cpp +++ b/toolkit/xre/nsUpdateDriver.cpp @@ -1,4 +1,5 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ /* 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/. */ @@ -26,6 +27,13 @@ #include "nsPrintfCString.h" #include "mozilla/DebugOnly.h" +#ifdef XP_MACOSX +#include "nsILocalFileMac.h" +#include "nsCommandLineServiceMac.h" +#include "MacLaunchHelper.h" +#include "updaterfileutils_osx.h" +#endif + #if defined(XP_WIN) # include <direct.h> # include <process.h> @@ -53,11 +61,16 @@ GetUpdateLog() #ifdef XP_WIN #define UPDATER_BIN "updater.exe" +#elif XP_MACOSX +#define UPDATER_BIN "org.mozilla.updater" #else #define UPDATER_BIN "updater" #endif #define UPDATER_INI "updater.ini" -#if defined(XP_UNIX) +#ifdef XP_MACOSX +#define UPDATER_APP "updater.app" +#endif +#if defined(XP_UNIX) && !defined(XP_MACOSX) #define UPDATER_PNG "updater.png" #endif @@ -96,7 +109,18 @@ static nsresult GetInstallDirPath(nsIFile *appDir, nsACString& installDirPath) { nsresult rv; -#if XP_WIN +#ifdef XP_MACOSX + nsCOMPtr<nsIFile> parentDir1, parentDir2; + rv = appDir->GetParent(getter_AddRefs(parentDir1)); + if (NS_FAILED(rv)) { + return rv; + } + rv = parentDir1->GetParent(getter_AddRefs(parentDir2)); + if (NS_FAILED(rv)) { + return rv; + } + rv = parentDir2->GetNativePath(installDirPath); +#elif XP_WIN nsAutoString installDirPathW; rv = appDir->GetPath(installDirPathW); if (NS_FAILED(rv)) { @@ -112,6 +136,35 @@ GetInstallDirPath(nsIFile *appDir, nsACString& installDirPath) return NS_OK; } +#if defined(XP_MACOSX) +// This is a copy of OS X's XRE_GetBinaryPath from nsAppRunner.cpp with the +// gBinaryPath check removed so that the updater can reload the stub executable +// instead of xulrunner-bin. See bug 349737. +static nsresult +GetXULRunnerStubPath(const char* argv0, nsIFile* *aResult) +{ + // Works even if we're not bundled. + CFBundleRef appBundle = ::CFBundleGetMainBundle(); + if (!appBundle) + return NS_ERROR_FAILURE; + + CFURLRef bundleURL = ::CFBundleCopyExecutableURL(appBundle); + if (!bundleURL) + return NS_ERROR_FAILURE; + + nsCOMPtr<nsILocalFileMac> lfm; + nsresult rv = NS_NewLocalFileWithCFURL(bundleURL, true, getter_AddRefs(lfm)); + + ::CFRelease(bundleURL); + + if (NS_FAILED(rv)) + return rv; + + lfm.forget(aResult); + return NS_OK; +} +#endif /* XP_MACOSX */ + static bool GetFile(nsIFile *dir, const nsCSubstring &name, nsCOMPtr<nsIFile> &result) { @@ -271,10 +324,16 @@ CopyUpdaterIntoUpdateDir(nsIFile *greDir, nsIFile *appDir, nsIFile *updateDir, nsCOMPtr<nsIFile> &updater) { // Copy the updater application from the GRE and the updater ini from the app +#if defined(XP_MACOSX) + if (!CopyFileIntoUpdateDir(appDir, NS_LITERAL_CSTRING(UPDATER_APP), updateDir)) + return false; + CopyFileIntoUpdateDir(greDir, NS_LITERAL_CSTRING(UPDATER_INI), updateDir); +#else if (!CopyFileIntoUpdateDir(greDir, NS_LITERAL_CSTRING(UPDATER_BIN), updateDir)) return false; CopyFileIntoUpdateDir(appDir, NS_LITERAL_CSTRING(UPDATER_INI), updateDir); -#if defined(XP_UNIX) +#endif +#if defined(XP_UNIX) && !defined(XP_MACOSX) nsCOMPtr<nsIFile> iconDir; appDir->Clone(getter_AddRefs(iconDir)); iconDir->AppendNative(NS_LITERAL_CSTRING("icons")); @@ -285,6 +344,16 @@ CopyUpdaterIntoUpdateDir(nsIFile *greDir, nsIFile *appDir, nsIFile *updateDir, nsresult rv = updateDir->Clone(getter_AddRefs(updater)); if (NS_FAILED(rv)) return false; +#if defined(XP_MACOSX) + rv = updater->AppendNative(NS_LITERAL_CSTRING(UPDATER_APP)); + nsresult tmp = updater->AppendNative(NS_LITERAL_CSTRING("Contents")); + if (NS_FAILED(tmp)) { + rv = tmp; + } + tmp = updater->AppendNative(NS_LITERAL_CSTRING("MacOS")); + if (NS_FAILED(tmp) || NS_FAILED(rv)) + return false; +#endif rv = updater->AppendNative(NS_LITERAL_CSTRING(UPDATER_BIN)); return NS_SUCCEEDED(rv); } @@ -295,7 +364,8 @@ CopyUpdaterIntoUpdateDir(nsIFile *greDir, nsIFile *appDir, nsIFile *updateDir, * * @param pathToAppend A new library path to prepend to LD_LIBRARY_PATH */ -#if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(XP_WIN) +#if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(XP_WIN) && \ + !defined(XP_MACOSX) #include "prprf.h" #define PATH_SEPARATOR ":" #define LD_LIBRARY_PATH_ENVVAR_NAME "LD_LIBRARY_PATH" @@ -372,7 +442,13 @@ SwitchToUpdatedApp(nsIFile *greDir, nsIFile *updateDir, // to restart the running application. nsCOMPtr<nsIFile> appFile; +#if defined(XP_MACOSX) + // On OS X we need to pass the location of the xulrunner-stub executable + // rather than xulrunner-bin. See bug 349737. + GetXULRunnerStubPath(appArgv[0], getter_AddRefs(appFile)); +#else XRE_GetBinaryPath(appArgv[0], getter_AddRefs(appFile)); +#endif if (!appFile) return; @@ -424,7 +500,11 @@ SwitchToUpdatedApp(nsIFile *greDir, nsIFile *updateDir, // Get the directory where the update will be staged. nsAutoCString applyToDir; nsCOMPtr<nsIFile> updatedDir; +#ifdef XP_MACOSX + if (!GetFile(updateDir, NS_LITERAL_CSTRING("Updated.app"), updatedDir)) { +#else if (!GetFile(appDir, NS_LITERAL_CSTRING("updated"), updatedDir)) { +#endif return; } #ifdef XP_WIN @@ -468,7 +548,7 @@ SwitchToUpdatedApp(nsIFile *greDir, nsIFile *updateDir, // Construct the PID argument for this process. We start the updater using // execv on all Unix platforms except Mac, so on those platforms we pass 0 // instead of a good PID to signal the updater not to try and wait for us. -#if defined(XP_UNIX) +#if defined(XP_UNIX) & !defined(XP_MACOSX) nsAutoCString pid("0"); #else nsAutoCString pid; @@ -508,13 +588,14 @@ SwitchToUpdatedApp(nsIFile *greDir, nsIFile *updateDir, if (gSafeMode) { PR_SetEnv("MOZ_SAFE_MODE_RESTART=1"); } -#if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(XP_WIN) +#if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(XP_WIN) && \ + !defined(XP_MACOSX) AppendToLibPath(installDirPath.get()); #endif LOG(("spawning updater process for replacing [%s]\n", updaterPath.get())); -#if defined(XP_UNIX) +#if defined(XP_UNIX) & !defined(XP_MACOSX) exit(execv(updaterPath.get(), argv)); #elif defined(XP_WIN) // Switch the application using updater.exe @@ -522,6 +603,10 @@ SwitchToUpdatedApp(nsIFile *greDir, nsIFile *updateDir, return; } _exit(0); +#elif defined(XP_MACOSX) + CommandLineServiceMac::SetupMacCommandLine(argc, argv, true); + LaunchChildMac(argc, argv); + exit(0); #else PR_CreateProcessDetached(updaterPath.get(), argv, nullptr, nullptr); exit(0); @@ -567,7 +652,13 @@ ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsIFile *statusFile, // to restart the running application. nsCOMPtr<nsIFile> appFile; +#if defined(XP_MACOSX) + // On OS X we need to pass the location of the xulrunner-stub executable + // rather than xulrunner-bin. See bug 349737. + GetXULRunnerStubPath(appArgv[0], getter_AddRefs(appFile)); +#else XRE_GetBinaryPath(appArgv[0], getter_AddRefs(appFile)); +#endif if (!appFile) return; @@ -623,7 +714,11 @@ ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsIFile *statusFile, if (restart && !isOSUpdate) { applyToDir.Assign(installDirPath); } else { +#ifdef XP_MACOSX + if (!GetFile(updateDir, NS_LITERAL_CSTRING("Updated.app"), updatedDir)) { +#else if (!GetFile(appDir, NS_LITERAL_CSTRING("updated"), updatedDir)) { +#endif return; } #ifdef XP_WIN @@ -678,7 +773,7 @@ ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsIFile *statusFile, // Signal the updater application that it should stage the update. pid.AssignASCII("-1"); } else { -#if defined(XP_UNIX) +#if defined(XP_UNIX) & !defined(XP_MACOSX) pid.AssignASCII("0"); #else pid.AppendInt((int32_t) getpid()); @@ -714,7 +809,8 @@ ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsIFile *statusFile, if (gSafeMode) { PR_SetEnv("MOZ_SAFE_MODE_RESTART=1"); } -#if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(XP_WIN) +#if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(XP_WIN) && \ + !defined(XP_MACOSX) AppendToLibPath(installDirPath.get()); #endif @@ -724,10 +820,10 @@ ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsIFile *statusFile, LOG(("spawning updater process [%s]\n", updaterPath.get())); -#if defined(XP_UNIX) - // We use execv to spawn the updater process on all UNIX-like systems. - // Windows has execv, but it is a faked implementation that doesn't really - // replace the current process. +#if defined(XP_UNIX) && !defined(XP_MACOSX) + // We use execv to spawn the updater process on all UNIX systems except Mac OSX + // since it is known to cause problems on the Mac. Windows has execv, but it + // is a faked implementation that doesn't really replace the current process. // Instead it spawns a new process, so we gain nothing from using execv on // Windows. if (restart) { @@ -749,6 +845,24 @@ ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsIFile *statusFile, // We are going to process an update so we should exit now _exit(0); } +#elif defined(XP_MACOSX) + CommandLineServiceMac::SetupMacCommandLine(argc, argv, restart); + // We need to detect whether elevation is required for this update. This can + // occur when an admin user installs the application, but another admin + // user attempts to update (see bug 394984). + if (restart && !IsRecursivelyWritable(installDirPath.get())) { + if (!LaunchElevatedUpdate(argc, argv, outpid)) { + LOG(("Failed to launch elevated update!")); + exit(1); + } + exit(0); + } else { + if (restart) { + LaunchChildMac(argc, argv); + exit(0); + } + LaunchChildMac(argc, argv, outpid); + } #else *outpid = PR_CreateProcess(updaterPath.get(), argv, nullptr, nullptr); if (restart) { @@ -769,6 +883,9 @@ ProcessHasTerminated(ProcessType pt) } CloseHandle(pt); return true; +#elif defined(XP_MACOSX) + // We're waiting for the process to terminate in LaunchChildMac. + return true; #elif defined(XP_UNIX) int exitStatus; pid_t exited = waitpid(pt, &exitStatus, WNOHANG); diff --git a/toolkit/xre/nsXREDirProvider.cpp b/toolkit/xre/nsXREDirProvider.cpp index fdeee8d0f9..e38cc4f35b 100644 --- a/toolkit/xre/nsXREDirProvider.cpp +++ b/toolkit/xre/nsXREDirProvider.cpp @@ -48,11 +48,19 @@ #include <windows.h> #include <shlobj.h> #endif +#ifdef XP_MACOSX +#include "nsILocalFileMac.h" +// for chflags() +#include <sys/stat.h> +#include <unistd.h> +#endif #ifdef XP_UNIX #include <ctype.h> #endif -#if defined(XP_WIN) +#if defined(XP_MACOSX) +#define APP_REGISTRY_NAME "Application Registry" +#elif defined(XP_WIN) #define APP_REGISTRY_NAME "registry.dat" #else #define APP_REGISTRY_NAME "appreg" @@ -100,6 +108,9 @@ nsXREDirProvider::Initialize(nsIFile *aXULAppDir, mXULAppDir = aXULAppDir; mGREDir = aGREDir; mGREDir->Clone(getter_AddRefs(mGREBinDir)); +#ifdef XP_MACOSX + mGREBinDir->SetNativeLeafName(NS_LITERAL_CSTRING("MacOS")); +#endif if (!mProfileDir) { nsCOMPtr<nsIDirectoryServiceProvider> app(do_QueryInterface(mAppProvider)); @@ -129,6 +140,30 @@ nsXREDirProvider::SetProfile(nsIFile* aDir, nsIFile* aLocalDir) if (NS_FAILED(rv)) return rv; +#ifdef XP_MACOSX + bool same; + if (NS_SUCCEEDED(aDir->Equals(aLocalDir, &same)) && !same) { + // Ensure that the cache directory is not indexed by Spotlight + // (bug 718910). At least on OS X, the cache directory (under + // ~/Library/Caches/) is always the "local" user profile + // directory. This is confusing, since *both* user profile + // directories are "local" (they both exist under the user's + // home directory). But this usage dates back at least as far + // as the patch for bug 291033, where "local" seems to mean + // "suitable for temporary storage". Don't hide the cache + // directory if by some chance it and the "non-local" profile + // directory are the same -- there are bad side effects from + // hiding a profile directory under /Library/Application Support/ + // (see bug 801883). + nsAutoCString cacheDir; + if (NS_SUCCEEDED(aLocalDir->GetNativePath(cacheDir))) { + if (chflags(cacheDir.get(), UF_HIDDEN)) { + NS_WARNING("Failed to set Cache directory to HIDDEN."); + } + } + } +#endif + mProfileDir = aDir; mProfileLocalDir = aLocalDir; return NS_OK; @@ -163,7 +198,7 @@ nsXREDirProvider::GetUserProfilesRootDir(nsIFile** aResult, aProfileName, aAppName, aVendorName); if (NS_SUCCEEDED(rv)) { -#if !defined(XP_UNIX) +#if !defined(XP_UNIX) || defined(XP_MACOSX) rv = file->AppendNative(NS_LITERAL_CSTRING("Profiles")); #endif // We must create the profile directory here if it does not exist. @@ -188,7 +223,7 @@ nsXREDirProvider::GetUserProfilesLocalDir(nsIFile** aResult, aProfileName, aAppName, aVendorName); if (NS_SUCCEEDED(rv)) { -#if !defined(XP_UNIX) +#if !defined(XP_UNIX) || defined(XP_MACOSX) rv = file->AppendNative(NS_LITERAL_CSTRING("Profiles")); #endif // We must create the profile directory here if it does not exist. @@ -201,7 +236,7 @@ nsXREDirProvider::GetUserProfilesLocalDir(nsIFile** aResult, return NS_OK; } -#if defined(XP_UNIX) +#if defined(XP_UNIX) || defined(XP_MACOSX) /** * Get the directory that is the parent of the system-wide directories * for extensions and native-messaing manifests. @@ -215,6 +250,12 @@ GetSystemParentDirectory(nsIFile** aFile) { nsresult rv; nsCOMPtr<nsIFile> localDir; +#if defined(XP_MACOSX) + rv = GetOSXFolderType(kOnSystemDisk, kApplicationSupportFolderType, getter_AddRefs(localDir)); + if (NS_SUCCEEDED(rv)) { + rv = localDir->AppendNative(NS_LITERAL_CSTRING("Mozilla")); + } +#else NS_NAMED_LITERAL_CSTRING(dirname, #ifdef HAVE_USR_LIB64_DIR "/usr/lib64/mozilla" @@ -225,6 +266,7 @@ GetSystemParentDirectory(nsIFile** aFile) #endif ); rv = NS_NewNativeLocalFile(dirname, false, getter_AddRefs(localDir)); +#endif if (NS_SUCCEEDED(rv)) { localDir.forget(aFile); @@ -308,14 +350,18 @@ nsXREDirProvider::GetFile(const char* aProperty, bool* aPersistent, !strcmp(aProperty, XRE_USER_APP_DATA_DIR)) { rv = GetUserAppDataDirectory(getter_AddRefs(file)); } -#if defined(XP_UNIX) +#if defined(XP_UNIX) || defined(XP_MACOSX) else if (!strcmp(aProperty, XRE_SYS_NATIVE_MESSAGING_MANIFESTS)) { nsCOMPtr<nsIFile> localDir; rv = ::GetSystemParentDirectory(getter_AddRefs(localDir)); if (NS_SUCCEEDED(rv)) { NS_NAMED_LITERAL_CSTRING(dirname, +#if defined(XP_MACOSX) + "NativeMessagingHosts" +#else "native-messaging-hosts" +#endif ); rv = localDir->AppendNative(dirname); if (NS_SUCCEEDED(rv)) { @@ -327,10 +373,17 @@ nsXREDirProvider::GetFile(const char* aProperty, bool* aPersistent, nsCOMPtr<nsIFile> localDir; rv = GetUserDataDirectoryHome(getter_AddRefs(localDir), false); if (NS_SUCCEEDED(rv)) { +#if defined(XP_MACOSX) + rv = localDir->AppendNative(NS_LITERAL_CSTRING("Mozilla")); + if (NS_SUCCEEDED(rv)) { + rv = localDir->AppendNative(NS_LITERAL_CSTRING("NativeMessagingHosts")); + } +#else rv = localDir->AppendNative(NS_LITERAL_CSTRING(".mozilla")); if (NS_SUCCEEDED(rv)) { rv = localDir->AppendNative(NS_LITERAL_CSTRING("native-messaging-hosts")); } +#endif } if (NS_SUCCEEDED(rv)) { localDir.swap(file); @@ -372,7 +425,7 @@ nsXREDirProvider::GetFile(const char* aProperty, bool* aPersistent, return mAppProvider->GetFile(NS_APP_PROFILE_DIR_STARTUP, aPersistent, aFile); } -#if defined(XP_UNIX) +#if defined(XP_UNIX) || defined(XP_MACOSX) else if (!strcmp(aProperty, XRE_SYS_LOCAL_EXTENSION_PARENT_DIR)) { #ifdef ENABLE_SYSTEM_EXTENSION_DIRS return GetSystemExtensionsDirectory(aFile); @@ -381,7 +434,7 @@ nsXREDirProvider::GetFile(const char* aProperty, bool* aPersistent, #endif } #endif -#if defined(XP_UNIX) +#if defined(XP_UNIX) && !defined(XP_MACOSX) else if (!strcmp(aProperty, XRE_SYS_SHARE_EXTENSION_PARENT_DIR)) { #ifdef ENABLE_SYSTEM_EXTENSION_DIRS #if defined(__OpenBSD__) || defined(__FreeBSD__) @@ -1050,7 +1103,42 @@ nsXREDirProvider::GetUpdateRootDir(nsIFile* *aResult) rv = appFile->GetParent(getter_AddRefs(updRoot)); NS_ENSURE_SUCCESS(rv, rv); -#if XP_WIN +#ifdef XP_MACOSX + nsCOMPtr<nsIFile> appRootDirFile; + nsCOMPtr<nsIFile> localDir; + nsAutoString appDirPath; + if (NS_FAILED(appFile->GetParent(getter_AddRefs(appRootDirFile))) || + NS_FAILED(appRootDirFile->GetPath(appDirPath)) || + NS_FAILED(GetUserDataDirectoryHome(getter_AddRefs(localDir), true))) { + return NS_ERROR_FAILURE; + } + + int32_t dotIndex = appDirPath.RFind(".app"); + if (dotIndex == kNotFound) { + dotIndex = appDirPath.Length(); + } + appDirPath = Substring(appDirPath, 1, dotIndex - 1); + + bool hasVendor = gAppData->vendor && strlen(gAppData->vendor) != 0; + if (hasVendor || gAppData->name) { + if (NS_FAILED(localDir->AppendNative(nsDependentCString(hasVendor ? + gAppData->vendor : + gAppData->name)))) { + return NS_ERROR_FAILURE; + } + } else if (NS_FAILED(localDir->AppendNative(NS_LITERAL_CSTRING("Mozilla")))) { + return NS_ERROR_FAILURE; + } + + if (NS_FAILED(localDir->Append(NS_LITERAL_STRING("updates"))) || + NS_FAILED(localDir->AppendRelativePath(appDirPath))) { + return NS_ERROR_FAILURE; + } + + localDir.forget(aResult); + return NS_OK; + +#elif XP_WIN nsAutoString pathHash; bool pathHashResult = false; bool hasVendor = gAppData->vendor && strlen(gAppData->vendor) != 0; @@ -1192,7 +1280,32 @@ nsXREDirProvider::GetUserDataDirectoryHome(nsIFile** aFile, bool aLocal) nsresult rv; nsCOMPtr<nsIFile> localDir; -#if defined(XP_WIN) +#if defined(XP_MACOSX) + FSRef fsRef; + OSType folderType; + if (aLocal) { + folderType = kCachedDataFolderType; + } else { +#ifdef MOZ_THUNDERBIRD + folderType = kDomainLibraryFolderType; +#else + folderType = kApplicationSupportFolderType; +#endif + } + OSErr err = ::FSFindFolder(kUserDomain, folderType, kCreateFolder, &fsRef); + NS_ENSURE_FALSE(err, NS_ERROR_FAILURE); + + rv = NS_NewNativeLocalFile(EmptyCString(), true, getter_AddRefs(localDir)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsILocalFileMac> dirFileMac = do_QueryInterface(localDir); + NS_ENSURE_TRUE(dirFileMac, NS_ERROR_UNEXPECTED); + + rv = dirFileMac->InitWithFSRef(&fsRef); + NS_ENSURE_SUCCESS(rv, rv); + + localDir = do_QueryInterface(dirFileMac, &rv); +#elif defined(XP_WIN) nsString path; if (aLocal) { rv = GetShellFolderPath(CSIDL_LOCAL_APPDATA, path); @@ -1255,7 +1368,7 @@ nsXREDirProvider::GetSysUserExtensionsDirectory(nsIFile** aFile) return NS_OK; } -#if defined(XP_UNIX) +#if defined(XP_UNIX) || defined(XP_MACOSX) nsresult nsXREDirProvider::GetSystemExtensionsDirectory(nsIFile** aFile) { @@ -1265,7 +1378,11 @@ nsXREDirProvider::GetSystemExtensionsDirectory(nsIFile** aFile) rv = GetSystemParentDirectory(getter_AddRefs(localDir)); if (NS_SUCCEEDED(rv)) { NS_NAMED_LITERAL_CSTRING(sExtensions, +#if defined(XP_MACOSX) + "Extensions" +#else "extensions" +#endif ); rv = localDir->AppendNative(sExtensions); @@ -1332,7 +1449,7 @@ nsXREDirProvider::AppendSysUserExtensionPath(nsIFile* aFile) nsresult rv; -#if defined(XP_WIN) +#if defined (XP_MACOSX) || defined(XP_WIN) static const char* const sXR = "Mozilla"; rv = aFile->AppendNative(nsDependentCString(sXR)); @@ -1391,7 +1508,19 @@ nsXREDirProvider::AppendProfilePath(nsIFile* aFile, nsresult rv; -#if defined(XP_WIN) +#if defined (XP_MACOSX) + if (!profile.IsEmpty()) { + rv = AppendProfileString(aFile, profile.get()); + } + else { + // Note that MacOS ignores the vendor when creating the profile hierarchy - + // all application preferences directories live alongside one another in + // ~/Library/Application Support/ + rv = aFile->AppendNative(appName); + } + NS_ENSURE_SUCCESS(rv, rv); + +#elif defined(XP_WIN) if (!profile.IsEmpty()) { rv = AppendProfileString(aFile, profile.get()); } diff --git a/toolkit/xre/nsXREDirProvider.h b/toolkit/xre/nsXREDirProvider.h index 014317e641..655f664e6d 100644 --- a/toolkit/xre/nsXREDirProvider.h +++ b/toolkit/xre/nsXREDirProvider.h @@ -102,7 +102,7 @@ protected: nsresult GetFilesInternal(const char* aProperty, nsISimpleEnumerator** aResult); static nsresult GetUserDataDirectoryHome(nsIFile* *aFile, bool aLocal); static nsresult GetSysUserExtensionsDirectory(nsIFile* *aFile); -#if defined(XP_UNIX) +#if defined(XP_UNIX) || defined(XP_MACOSX) static nsresult GetSystemExtensionsDirectory(nsIFile** aFile); #endif static nsresult EnsureDirectoryExists(nsIFile* aDirectory); diff --git a/tools/fuzzing/libfuzzer/harness/LibFuzzerTestHarness.h b/tools/fuzzing/libfuzzer/harness/LibFuzzerTestHarness.h index 70321a5748..6ac2344e31 100644 --- a/tools/fuzzing/libfuzzer/harness/LibFuzzerTestHarness.h +++ b/tools/fuzzing/libfuzzer/harness/LibFuzzerTestHarness.h @@ -193,6 +193,14 @@ static class ScopedXPCOM : public nsIDirectoryServiceProvider2 } greD->Clone(getter_AddRefs(mGREBinD)); +#ifdef XP_MACOSX + nsAutoCString leafName; + mGREBinD->GetNativeLeafName(leafName); + if (leafName.Equals("Resources")) { + mGREBinD->SetNativeLeafName(NS_LITERAL_CSTRING("MacOS")); + } +#endif + nsCOMPtr<nsIFile> copy = mGREBinD; return copy.forget(); } diff --git a/tools/profiler/tasktracer/GeckoTaskTracer.cpp b/tools/profiler/tasktracer/GeckoTaskTracer.cpp index aefcb274ec..36d1bffc38 100644 --- a/tools/profiler/tasktracer/GeckoTaskTracer.cpp +++ b/tools/profiler/tasktracer/GeckoTaskTracer.cpp @@ -1,4 +1,5 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ /* 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/. */ @@ -25,6 +26,10 @@ #include <unistd.h> #include <sys/syscall.h> #define gettid() static_cast<pid_t>(syscall(SYS_gettid)) +#elif defined(XP_MACOSX) +#include <unistd.h> +#include <sys/syscall.h> +#define gettid() static_cast<pid_t>(syscall(SYS_thread_selfid)) #elif defined(LINUX) #include <sys/types.h> pid_t gettid(); diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp index dc7d200041..7d5592f948 100644 --- a/uriloader/exthandler/nsExternalHelperAppService.cpp +++ b/uriloader/exthandler/nsExternalHelperAppService.cpp @@ -63,6 +63,10 @@ #include "nsIObserverService.h" // so we can be a profile change observer #include "nsIPropertyBag2.h" // for the 64-bit content length +#ifdef XP_MACOSX +#include "nsILocalFileMac.h" +#endif + #include "nsIPluginHost.h" // XXX needed for ext->type mapping (bug 233289) #include "nsPluginHost.h" #include "nsEscape.h" @@ -271,7 +275,50 @@ static nsresult GetDownloadDirectory(nsIFile **_directory, bool aSkipChecks = false) { nsCOMPtr<nsIFile> dir; - // On all supported platforms, we default to the system's temporary directory. +#ifdef XP_MACOSX + // On OS X, we first try to get the users download location, if it's set. + switch (Preferences::GetInt(NS_PREF_DOWNLOAD_FOLDERLIST, -1)) { + case NS_FOLDER_VALUE_DESKTOP: + (void) NS_GetSpecialDirectory(NS_OS_DESKTOP_DIR, getter_AddRefs(dir)); + break; + case NS_FOLDER_VALUE_CUSTOM: + { + Preferences::GetComplex(NS_PREF_DOWNLOAD_DIR, + NS_GET_IID(nsIFile), + getter_AddRefs(dir)); + if (!dir) break; + + // If we're not checking for availability we're done. + if (aSkipChecks) { + dir.forget(_directory); + return NS_OK; + } + + // We have the directory, and now we need to make sure it exists + bool dirExists = false; + (void) dir->Exists(&dirExists); + if (dirExists) break; + + nsresult rv = dir->Create(nsIFile::DIRECTORY_TYPE, 0755); + if (NS_FAILED(rv)) { + dir = nullptr; + break; + } + } + break; + case NS_FOLDER_VALUE_DOWNLOADS: + // This is just the OS default location, so fall out + break; + } + + if (!dir) { + // If not, we default to the OS X default download location. + nsresult rv = NS_GetSpecialDirectory(NS_OSX_DEFAULT_DOWNLOAD_DIR, + getter_AddRefs(dir)); + NS_ENSURE_SUCCESS(rv, rv); + } +#else + // On all other platforms, we default to the systems temporary directory. nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(dir)); NS_ENSURE_SUCCESS(rv, rv); @@ -345,6 +392,7 @@ static nsresult GetDownloadDirectory(nsIFile **_directory, } #endif +#endif NS_ASSERTION(dir, "Somehow we didn't get a download directory!"); dir.forget(_directory); @@ -416,7 +464,11 @@ struct nsExtraMimeTypeEntry { const char* mDescription; }; +#ifdef XP_MACOSX +#define MAC_TYPE(x) x +#else #define MAC_TYPE(x) 0 +#endif /** * This table lists all of the 'extra' content types that we can deduce from particular @@ -427,7 +479,11 @@ struct nsExtraMimeTypeEntry { */ static const nsExtraMimeTypeEntry extraMimeEntries[] = { +#if defined(XP_MACOSX) // don't define .bin on the mac...use internet config to look that up... + { APPLICATION_OCTET_STREAM, "exe,com", "Binary File" }, +#else { APPLICATION_OCTET_STREAM, "exe,com,bin", "Binary File" }, +#endif { APPLICATION_GZIP2, "gz", "gzip" }, { "application/x-arj", "arj", "ARJ file" }, { "application/rtf", "rtf", "Rich Text Format File" }, diff --git a/uriloader/exthandler/nsLocalHandlerApp.h b/uriloader/exthandler/nsLocalHandlerApp.h index 2e6ba6d8c3..30b410ce32 100644 --- a/uriloader/exthandler/nsLocalHandlerApp.h +++ b/uriloader/exthandler/nsLocalHandlerApp.h @@ -46,8 +46,15 @@ protected: nsresult LaunchWithIProcess(const nsCString &aArg); }; -// Any platforms that need a platform-specific class instead of just +// any platforms that need a platform-specific class instead of just // using nsLocalHandlerApp need to add an include and a typedef here. +#ifdef XP_MACOSX +# ifndef NSLOCALHANDLERAPPMAC_H_ +# include "mac/nsLocalHandlerAppMac.h" +typedef nsLocalHandlerAppMac PlatformLocalHandlerApp_t; +# endif +#else typedef nsLocalHandlerApp PlatformLocalHandlerApp_t; +#endif #endif // __nsLocalHandlerAppImpl_h__ diff --git a/view/nsView.cpp b/view/nsView.cpp index 79fd7cf075..8f509cadeb 100644 --- a/view/nsView.cpp +++ b/view/nsView.cpp @@ -241,8 +241,8 @@ LayoutDeviceIntRect nsView::CalcWidgetBounds(nsWindowType aType) LayoutDeviceIntRect newBounds = LayoutDeviceIntRect::FromUnknownRect(viewBounds.ToNearestPixels(p2a)); -#if (MOZ_WIDGET_GTK == 3) - // GTK 3 rounds widget coordinates to the nearest global "display +#if defined(XP_MACOSX) || (MOZ_WIDGET_GTK == 3) + // cocoa and GTK round widget coordinates to the nearest global "display // pixel" integer value. So we avoid fractional display pixel values by // rounding to the nearest value that won't yield a fractional display pixel. nsIWidget* widget = parentWidget ? parentWidget : mWindow.get(); diff --git a/view/nsViewManager.cpp b/view/nsViewManager.cpp index b6a6e25ef2..e41f005b25 100644 --- a/view/nsViewManager.cpp +++ b/view/nsViewManager.cpp @@ -598,7 +598,10 @@ nsViewManager::InvalidateWidgetArea(nsView *aWidgetView, "Only plugin or popup widgets can be children!"); // We do not need to invalidate in plugin widgets, but we should - // exclude them from the invalidation region. + // exclude them from the invalidation region IF we're not on + // Mac. On Mac we need to draw under plugin widgets, because + // plugin widgets are basically invisible +#ifndef XP_MACOSX // GetBounds should compensate for chrome on a toplevel widget LayoutDeviceIntRect bounds = childWidget->GetBounds(); @@ -610,6 +613,7 @@ nsViewManager::InvalidateWidgetArea(nsView *aWidgetView, children.Or(children, rr - aWidgetView->ViewToWidgetOffset()); children.SimplifyInward(20); } +#endif } } } diff --git a/widget/CompositorWidget.h b/widget/CompositorWidget.h index 829255b62d..eb657ba7f3 100644 --- a/widget/CompositorWidget.h +++ b/widget/CompositorWidget.h @@ -54,7 +54,11 @@ class CompositorWidgetChild; class WidgetRenderingContext { -/** Mac Stub **/ +public: +#ifdef XP_MACOSX + WidgetRenderingContext() : mLayerManager(nullptr) {} + layers::LayerManagerComposite* mLayerManager; +#endif }; /** diff --git a/widget/GfxInfoBase.cpp b/widget/GfxInfoBase.cpp index ae0878c757..ed47355367 100644 --- a/widget/GfxInfoBase.cpp +++ b/widget/GfxInfoBase.cpp @@ -1,3 +1,4 @@ +/* vim: se cin sw=2 ts=2 et : */ /* -*- 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 @@ -645,6 +646,13 @@ MatchingOperatingSystems(OperatingSystem aBlockedOS, OperatingSystem aSystemOS) } #endif +#if defined (XP_MACOSX) + if (aBlockedOS == OperatingSystem::OSX) { + // We do want even "unknown" aSystemOS to fall under "all OS X" + return true; + } +#endif + return aSystemOS == aBlockedOS; } diff --git a/widget/NativeKeyToDOMCodeName.h b/widget/NativeKeyToDOMCodeName.h index 05bcd3babb..74f2ed1f47 100644 --- a/widget/NativeKeyToDOMCodeName.h +++ b/widget/NativeKeyToDOMCodeName.h @@ -27,6 +27,12 @@ #define CODE_MAP_WIN(aCPPCodeName, aNativeKey) \ NS_NATIVE_KEY_TO_DOM_CODE_NAME_INDEX(aNativeKey, \ CODE_NAME_INDEX_##aCPPCodeName) +#elif defined(XP_MACOSX) +#undef CODE_MAP_MAC +// aNativeKey is key code starting with kVK_. +#define CODE_MAP_MAC(aCPPCodeName, aNativeKey) \ + NS_NATIVE_KEY_TO_DOM_CODE_NAME_INDEX(aNativeKey, \ + CODE_NAME_INDEX_##aCPPCodeName) #elif defined(MOZ_WIDGET_GTK) #undef CODE_MAP_X11 // aNativeKey is hardware_keycode of GDKEvent or nativeScanCode of QKeyEvent. diff --git a/widget/NativeKeyToDOMKeyName.h b/widget/NativeKeyToDOMKeyName.h index 45400e9564..25dafff6f3 100644 --- a/widget/NativeKeyToDOMKeyName.h +++ b/widget/NativeKeyToDOMKeyName.h @@ -61,6 +61,10 @@ #else #error Any NS_*_TO_DOM_KEY_NAME_INDEX() is not defined. #endif // #if defined(NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX) ... +#elif defined(XP_MACOSX) +#undef KEY_MAP_COCOA +#define KEY_MAP_COCOA(aCPPKeyName, aNativeKey) \ + NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, KEY_NAME_INDEX_##aCPPKeyName) #elif defined(MOZ_WIDGET_GTK) #undef KEY_MAP_GTK #define KEY_MAP_GTK(aCPPKeyName, aNativeKey) \ diff --git a/widget/TextEvents.h b/widget/TextEvents.h index 736effeeab..6c29341144 100644 --- a/widget/TextEvents.h +++ b/widget/TextEvents.h @@ -111,6 +111,10 @@ protected: , mLocation(nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD) , mAccessKeyForwardedToChild(false) , mUniqueId(0) +#ifdef XP_MACOSX + , mNativeModifierFlags(0) + , mNativeKeyCode(0) +#endif // #ifdef XP_MACOSX , mKeyNameIndex(mozilla::KEY_NAME_INDEX_Unidentified) , mCodeNameIndex(CODE_NAME_INDEX_UNKNOWN) , mInputMethodAppState(eNotHandled) @@ -136,6 +140,10 @@ public: , mLocation(nsIDOMKeyEvent::DOM_KEY_LOCATION_STANDARD) , mAccessKeyForwardedToChild(false) , mUniqueId(0) +#ifdef XP_MACOSX + , mNativeModifierFlags(0) + , mNativeKeyCode(0) +#endif // #ifdef XP_MACOSX , mKeyNameIndex(mozilla::KEY_NAME_INDEX_Unidentified) , mCodeNameIndex(CODE_NAME_INDEX_UNKNOWN) , mInputMethodAppState(eNotHandled) @@ -196,6 +204,15 @@ public: // CODE_NAME_INDEX_USE_STRING. nsString mCodeValue; +#ifdef XP_MACOSX + // Values given by a native NSEvent, for use with Cocoa NPAPI plugins. + nsString mNativeCharacters; + nsString mNativeCharactersIgnoringModifiers; + // If this is non-empty, create a text event for plugins instead of a + // keyboard event. + nsString mPluginTextEventString; +#endif // #ifdef XP_MACOSX + // OS-specific native event can optionally be preserved void* mNativeKeyEvent; // A DOM keyCode value or 0. If a keypress event whose mCharCode is 0, this @@ -223,6 +240,12 @@ public: // over long periods. uint32_t mUniqueId; +#ifdef XP_MACOSX + // Values given by a native NSEvent, for use with Cocoa NPAPI plugins. + uint32_t mNativeModifierFlags; + uint16_t mNativeKeyCode; +#endif // #ifdef XP_MACOSX + // DOM KeyboardEvent.key KeyNameIndex mKeyNameIndex; // DOM KeyboardEvent.code @@ -374,6 +397,14 @@ public: // is destroyed. mNativeKeyEvent = nullptr; mUniqueId = aEvent.mUniqueId; +#ifdef XP_MACOSX + mNativeKeyCode = aEvent.mNativeKeyCode; + mNativeModifierFlags = aEvent.mNativeModifierFlags; + mNativeCharacters.Assign(aEvent.mNativeCharacters); + mNativeCharactersIgnoringModifiers. + Assign(aEvent.mNativeCharactersIgnoringModifiers); + mPluginTextEventString.Assign(aEvent.mPluginTextEventString); +#endif mInputMethodAppState = aEvent.mInputMethodAppState; mIsSynthesizedByTIP = aEvent.mIsSynthesizedByTIP; } diff --git a/widget/WidgetEventImpl.cpp b/widget/WidgetEventImpl.cpp index 1302c3e948..59c80672b1 100644 --- a/widget/WidgetEventImpl.cpp +++ b/widget/WidgetEventImpl.cpp @@ -479,7 +479,11 @@ WidgetInputEvent::AccelModifier() sAccelModifier = MODIFIER_CONTROL; break; default: +#ifdef XP_MACOSX + sAccelModifier = MODIFIER_META; +#else sAccelModifier = MODIFIER_CONTROL; +#endif break; } } diff --git a/widget/nsBaseWidget.cpp b/widget/nsBaseWidget.cpp index 23859383c2..d3cdf72cfc 100644 --- a/widget/nsBaseWidget.cpp +++ b/widget/nsBaseWidget.cpp @@ -84,6 +84,10 @@ static void debug_RegisterPrefCallbacks(); static int32_t gNumWidgets; #endif +#ifdef XP_MACOSX +#include "nsCocoaFeatures.h" +#endif + #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) static nsRefPtrHashtable<nsVoidPtrHashKey, nsIWidget>* sPluginWidgetList; #endif @@ -171,7 +175,7 @@ nsBaseWidget::nsBaseWidget() , mUpdateCursor(true) , mUseAttachedEvents(false) , mIMEHasFocus(false) -#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) +#if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK) , mAccessibilityInUseFlag(false) #endif { @@ -641,8 +645,15 @@ void nsBaseWidget::AddChild(nsIWidget* aChild) void nsBaseWidget::RemoveChild(nsIWidget* aChild) { #ifdef DEBUG +#ifdef XP_MACOSX + // nsCocoaWindow doesn't implement GetParent, so in that case parent will be + // null and we'll just have to do without this assertion. + nsIWidget* parent = aChild->GetParent(); + NS_ASSERTION(!parent || parent == this, "Not one of our kids!"); +#else MOZ_RELEASE_ASSERT(aChild->GetParent() == this, "Not one of our kids!"); #endif +#endif if (mLastChild == aChild) { mLastChild = mLastChild->GetPrevSibling(); @@ -1371,8 +1382,12 @@ void nsBaseWidget::CreateCompositor(int aWidth, int aHeight) mLayerManager = lm.forget(); // Only track compositors for top-level windows, since other window types - // may use the basic compositor. + // may use the basic compositor. Except on the OS X - see bug 1306383 +#if defined(XP_MACOSX) + bool getCompositorFromThisWindow = true; +#else bool getCompositorFromThisWindow = (mWindowType == eWindowType_toplevel); +#endif if (getCompositorFromThisWindow) { gfxPlatform::GetPlatform()->NotifyCompositorCreated(mLayerManager->GetCompositorBackendType()); @@ -1870,7 +1885,7 @@ nsBaseWidget::ZoomToRect(const uint32_t& aPresShellId, #ifdef ACCESSIBILITY -#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) +#if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK) // defined in nsAppRunner.cpp extern const char* kAccessibilityLastRunDatePref; @@ -1899,7 +1914,7 @@ nsBaseWidget::GetRootAccessible() // make sure it's not created at unsafe times. nsAccessibilityService* accService = GetOrCreateAccService(); if (accService) { -#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) +#if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK) if (!mAccessibilityInUseFlag) { mAccessibilityInUseFlag = true; uint32_t now = PRTimeToSeconds(PR_Now()); diff --git a/widget/nsBaseWidget.h b/widget/nsBaseWidget.h index 4065a7f1e8..bbc6b72383 100644 --- a/widget/nsBaseWidget.h +++ b/widget/nsBaseWidget.h @@ -677,7 +677,7 @@ protected: bool mUpdateCursor; bool mUseAttachedEvents; bool mIMEHasFocus; -#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) +#if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK) bool mAccessibilityInUseFlag; #endif static nsIRollupListener* gRollupListener; diff --git a/widget/nsGUIEventIPC.h b/widget/nsGUIEventIPC.h index bf03652440..e45189bb10 100644 --- a/widget/nsGUIEventIPC.h +++ b/widget/nsGUIEventIPC.h @@ -431,6 +431,13 @@ struct ParamTraits<mozilla::WidgetKeyboardEvent> WriteParam(aMsg, static_cast<paramType::InputMethodAppStateType> (aParam.mInputMethodAppState)); +#ifdef XP_MACOSX + WriteParam(aMsg, aParam.mNativeKeyCode); + WriteParam(aMsg, aParam.mNativeModifierFlags); + WriteParam(aMsg, aParam.mNativeCharacters); + WriteParam(aMsg, aParam.mNativeCharactersIgnoringModifiers); + WriteParam(aMsg, aParam.mPluginTextEventString); +#endif // An OS-specific native event might be attached in |mNativeKeyEvent|, but // that cannot be copied across process boundaries. } @@ -458,6 +465,13 @@ struct ParamTraits<mozilla::WidgetKeyboardEvent> ReadParam(aMsg, aIter, &aResult->mUniqueId) && ReadParam(aMsg, aIter, &aResult->mIsSynthesizedByTIP) && ReadParam(aMsg, aIter, &inputMethodAppState) +#ifdef XP_MACOSX + && ReadParam(aMsg, aIter, &aResult->mNativeKeyCode) + && ReadParam(aMsg, aIter, &aResult->mNativeModifierFlags) + && ReadParam(aMsg, aIter, &aResult->mNativeCharacters) + && ReadParam(aMsg, aIter, &aResult->mNativeCharactersIgnoringModifiers) + && ReadParam(aMsg, aIter, &aResult->mPluginTextEventString) +#endif ) { aResult->mKeyNameIndex = static_cast<mozilla::KeyNameIndex>(keyNameIndex); diff --git a/widget/nsIWidget.h b/widget/nsIWidget.h index 716ed85c45..8e28c24da5 100644 --- a/widget/nsIWidget.h +++ b/widget/nsIWidget.h @@ -115,6 +115,10 @@ typedef void* nsNativeWidget; // IME context. Note that the result is only valid in the process. So, // XP code should use nsIWidget::GetNativeIMEContext() instead of using this. #define NS_RAW_NATIVE_IME_CONTEXT 14 +#ifdef XP_MACOSX +#define NS_NATIVE_PLUGIN_PORT_QD 100 +#define NS_NATIVE_PLUGIN_PORT_CG 101 +#endif #ifdef XP_WIN #define NS_NATIVE_TSF_THREAD_MGR 100 #define NS_NATIVE_TSF_CATEGORY_MGR 101 diff --git a/widget/nsNativeTheme.cpp b/widget/nsNativeTheme.cpp index 35c5a84f75..a5bd85fafa 100644 --- a/widget/nsNativeTheme.cpp +++ b/widget/nsNativeTheme.cpp @@ -99,13 +99,25 @@ nsNativeTheme::GetContentState(nsIFrame* aFrame, uint8_t aWidgetType) flags |= NS_EVENT_STATE_FOCUS; } - // On Windows, only draw focus rings if they should be shown. This + // On Windows and Mac, only draw focus rings if they should be shown. This // means that focus rings are only shown once the keyboard has been used to // focus something in the window. +#if defined(XP_MACOSX) + // Mac always draws focus rings for textboxes and lists. + if (aWidgetType == NS_THEME_NUMBER_INPUT || + aWidgetType == NS_THEME_TEXTFIELD || + aWidgetType == NS_THEME_TEXTFIELD_MULTILINE || + aWidgetType == NS_THEME_SEARCHFIELD || + aWidgetType == NS_THEME_LISTBOX) { + return flags; + } +#endif #if defined(XP_WIN) // On Windows, focused buttons are always drawn as such by the native theme. if (aWidgetType == NS_THEME_BUTTON) return flags; +#endif +#if defined(XP_MACOSX) || defined(XP_WIN) nsIDocument* doc = aFrame->GetContent()->OwnerDoc(); nsPIDOMWindowOuter* window = doc->GetWindow(); if (window && !window->ShouldShowFocusRing()) diff --git a/xpfe/appshell/nsAppShellService.cpp b/xpfe/appshell/nsAppShellService.cpp index 427428fdf9..569b743fa6 100644 --- a/xpfe/appshell/nsAppShellService.cpp +++ b/xpfe/appshell/nsAppShellService.cpp @@ -112,8 +112,20 @@ nsAppShellService::CreateHiddenWindowHelper(bool aIsPrivate) nsresult rv; int32_t initialHeight = 100, initialWidth = 100; +#ifdef XP_MACOSX + uint32_t chromeMask = 0; + nsAdoptingCString prefVal = + Preferences::GetCString("browser.hiddenWindowChromeURL"); + const char* hiddenWindowURL = prefVal.get() ? prefVal.get() : DEFAULT_HIDDENWINDOW_URL; + if (aIsPrivate) { + hiddenWindowURL = DEFAULT_HIDDENWINDOW_URL; + } else { + mApplicationProvidedHiddenWindow = prefVal.get() ? true : false; + } +#else static const char hiddenWindowURL[] = DEFAULT_HIDDENWINDOW_URL; uint32_t chromeMask = nsIWebBrowserChrome::CHROME_ALL; +#endif nsCOMPtr<nsIURI> url; rv = NS_NewURI(getter_AddRefs(url), hiddenWindowURL); @@ -543,12 +555,26 @@ nsAppShellService::CalculateWindowZLevel(nsIXULWindow *aParent, else if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_LOWERED) zLevel = nsIXULWindow::loweredZ; +#ifdef XP_MACOSX + /* Platforms on which modal windows are always application-modal, not + window-modal (that's just the Mac, right?) want modal windows to + be stacked on top of everyone else. + + On Mac OS X, bind modality to parent window instead of app (ala Mac OS 9) + */ + uint32_t modalDepMask = nsIWebBrowserChrome::CHROME_MODAL | + nsIWebBrowserChrome::CHROME_DEPENDENT; + if (aParent && (aChromeMask & modalDepMask)) { + aParent->GetZLevel(&zLevel); + } +#else /* Platforms with native support for dependent windows (that's everyone but pre-Mac OS X, right?) know how to stack dependent windows. On these platforms, give the dependent window the same level as its parent, so we won't try to override the normal platform behaviour. */ if ((aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT) && aParent) aParent->GetZLevel(&zLevel); +#endif return zLevel; } @@ -635,6 +661,23 @@ nsAppShellService::JustCreateTopWindow(nsIXULWindow *aParent, if (aChromeMask & nsIWebBrowserChrome::CHROME_MAC_SUPPRESS_ANIMATION) widgetInitData.mIsAnimationSuppressed = true; +#ifdef XP_MACOSX + // Mac OS X sheet support + // Adding CHROME_OPENAS_CHROME to sheetMask makes modal windows opened from + // nsGlobalWindow::ShowModalDialog() be dialogs (not sheets), while modal + // windows opened from nsPromptService::DoDialog() still are sheets. This + // fixes bmo bug 395465 (see nsCocoaWindow::StandardCreate() and + // nsCocoaWindow::SetModal()). + uint32_t sheetMask = nsIWebBrowserChrome::CHROME_OPENAS_DIALOG | + nsIWebBrowserChrome::CHROME_MODAL | + nsIWebBrowserChrome::CHROME_OPENAS_CHROME; + if (parent && + (parent != mHiddenWindow && parent != mHiddenPrivateWindow) && + ((aChromeMask & sheetMask) == sheetMask)) { + widgetInitData.mWindowType = eWindowType_sheet; + } +#endif + #if defined(XP_WIN) if (widgetInitData.mWindowType == eWindowType_toplevel || widgetInitData.mWindowType == eWindowType_dialog) diff --git a/xpfe/appshell/nsContentTreeOwner.cpp b/xpfe/appshell/nsContentTreeOwner.cpp index c916f74d0e..8e9a065a9c 100644 --- a/xpfe/appshell/nsContentTreeOwner.cpp +++ b/xpfe/appshell/nsContentTreeOwner.cpp @@ -40,6 +40,9 @@ #include "nsIScriptObjectPrincipal.h" #include "nsIURI.h" #include "nsIDocument.h" +#if defined(XP_MACOSX) +#include "nsThreadUtils.h" +#endif #include "mozilla/Preferences.h" #include "mozilla/dom/Element.h" @@ -903,6 +906,28 @@ nsContentTreeOwner::ProvideWindow(mozIDOMWindowProxy* aParent, // nsContentTreeOwner: Accessors //***************************************************************************** +#if defined(XP_MACOSX) +class nsContentTitleSettingEvent : public Runnable +{ +public: + nsContentTitleSettingEvent(dom::Element* dse, const nsAString& wtm) + : mElement(dse), + mTitleDefault(wtm) {} + + NS_IMETHOD Run() override + { + ErrorResult rv; + mElement->SetAttribute(NS_LITERAL_STRING("titledefault"), mTitleDefault, rv); + mElement->RemoveAttribute(NS_LITERAL_STRING("titlemodifier"), rv); + return NS_OK; + } + +private: + nsCOMPtr<dom::Element> mElement; + nsString mTitleDefault; +}; +#endif + void nsContentTreeOwner::XULWindow(nsXULWindow* aXULWindow) { mXULWindow = aXULWindow; @@ -921,6 +946,18 @@ void nsContentTreeOwner::XULWindow(nsXULWindow* aXULWindow) docShellElement->GetAttribute(NS_LITERAL_STRING("titledefault"), mTitleDefault); docShellElement->GetAttribute(NS_LITERAL_STRING("titlemodifier"), mWindowTitleModifier); docShellElement->GetAttribute(NS_LITERAL_STRING("titlepreface"), mTitlePreface); + +#if defined(XP_MACOSX) + // On OS X, treat the titlemodifier like it's the titledefault, and don't ever append + // the separator + appname. + if (mTitleDefault.IsEmpty()) { + NS_DispatchToCurrentThread( + new nsContentTitleSettingEvent(docShellElement, + mWindowTitleModifier)); + mTitleDefault = mWindowTitleModifier; + mWindowTitleModifier.Truncate(); + } +#endif docShellElement->GetAttribute(NS_LITERAL_STRING("titlemenuseparator"), mTitleSeparator); } } diff --git a/xpfe/appshell/nsWebShellWindow.cpp b/xpfe/appshell/nsWebShellWindow.cpp index 7ec39a9cdf..2893e78682 100644 --- a/xpfe/appshell/nsWebShellWindow.cpp +++ b/xpfe/appshell/nsWebShellWindow.cpp @@ -73,7 +73,7 @@ #include "nsPIWindowRoot.h" -#if defined(MOZ_WIDGET_GTK) +#if defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK) #include "nsINativeMenuService.h" #define USE_NATIVE_MENUS #endif diff --git a/xpfe/appshell/nsXULWindow.cpp b/xpfe/appshell/nsXULWindow.cpp index 45403b2b0a..5850850651 100644 --- a/xpfe/appshell/nsXULWindow.cpp +++ b/xpfe/appshell/nsXULWindow.cpp @@ -1,4 +1,5 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 ci et: */ /* 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/. */ @@ -1039,7 +1040,7 @@ void nsXULWindow::OnChromeLoaded() bool positionSet = !mIgnoreXULPosition; nsCOMPtr<nsIXULWindow> parentWindow(do_QueryReferent(mParentWindow)); -#if defined(XP_UNIX) +#if defined(XP_UNIX) && !defined(XP_MACOSX) // don't override WM placement on unix for independent, top-level windows // (however, we think the benefits of intelligent dependent window placement // trump that override.) |