Source code
Revision control
Copy as Markdown
Other Tools
/* -*- 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
#include "nsWindowsShellService.h"
#include "imgIContainer.h"
#include "imgIRequest.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/RefPtr.h"
#include "nsIContent.h"
#include "nsIImageLoadingContent.h"
#include "nsIOutputStream.h"
#include "nsIPrefService.h"
#include "nsIPrefLocalizedString.h"
#include "nsIServiceManager.h"
#include "nsIStringBundle.h"
#include "nsNetUtil.h"
#include "nsServiceManagerUtils.h"
#include "nsShellService.h"
#include "nsIProcess.h"
#include "nsICategoryManager.h"
#include "nsDirectoryServiceUtils.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsDirectoryServiceDefs.h"
#include "nsIWindowsRegKey.h"
#include "nsUnicharUtils.h"
#include "nsIURLFormatter.h"
#include "nsXULAppAPI.h"
#include "mozilla/WindowsVersion.h"
#include "mozilla/dom/Element.h"
#include "windows.h"
#include "shellapi.h"
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT 0x0600
#define INITGUID
#include <shlobj.h>
#ifndef MAX_BUF
#define MAX_BUF 4096
#endif
#define REG_SUCCEEDED(val) \
(val == ERROR_SUCCESS)
#define REG_FAILED(val) \
(val != ERROR_SUCCESS)
using namespace mozilla;
using namespace mozilla::gfx;
NS_IMPL_ISUPPORTS(nsWindowsShellService, nsIShellService)
static nsresult
OpenKeyForReading(HKEY aKeyRoot, const wchar_t* aKeyName, HKEY* aKey)
{
DWORD res = ::RegOpenKeyExW(aKeyRoot, aKeyName, 0, KEY_READ, aKey);
switch (res) {
case ERROR_SUCCESS:
break;
case ERROR_ACCESS_DENIED:
return NS_ERROR_FILE_ACCESS_DENIED;
case ERROR_FILE_NOT_FOUND:
return NS_ERROR_NOT_AVAILABLE;
}
return NS_OK;
}
///////////////////////////////////////////////////////////////////////////////
// Default SeaMonkey OS integration Registry Settings
// Note: Some settings only exist when using the installer!
// The setting of SeaMonkey as default application is made by a helper
// application since writing those values may require elevation.
//
// Default Browser settings:
// - File Extension Mappings
// -----------------------
// The following file extensions:
// .htm .html .shtml .xht .xhtml
// are mapped like so:
//
// HKCU\SOFTWARE\Classes\.<ext>\ (default) REG_SZ SeaMonkeyHTML
//
// as aliases to the class:
//
// HKCU\SOFTWARE\Classes\SeaMonkeyHTML\
// DefaultIcon (default) REG_SZ <appfolder>\chrome\icons\default\html-file.ico
// shell\open\command (default) REG_SZ <apppath> -url "%1"
//
// - Windows Vista Protocol Handler
//
// HKCU\SOFTWARE\Classes\SeaMonkeyURL\(default) REG_SZ <appname> URL
// EditFlags REG_DWORD 2
// FriendlyTypeName REG_SZ <appname> URL
// DefaultIcon (default) REG_SZ <apppath>,1
// shell\open\command (default) REG_SZ <apppath> -requestPending -osint -url "%1"
// shell\open\ddeexec (default) REG_SZ "%1",,0,0,,,,
// shell\open\ddeexec NoActivateHandler REG_SZ
// \Application (default) REG_SZ SeaMonkey
// \Topic (default) REG_SZ WWW_OpenURL
//
// - Protocol Mappings
// -----------------
// The following protocols:
// HTTP, HTTPS, FTP
// are mapped like so:
//
// HKCU\SOFTWARE\Classes\<protocol>\
// DefaultIcon (default) REG_SZ <apppath>,0
// shell\open\command (default) REG_SZ <apppath> -requestPending -osint -url "%1"
// shell\open\ddeexec (default) REG_SZ "%1",,0,0,,,,
// shell\open\ddeexec NoActivateHandler REG_SZ
// \Application (default) REG_SZ SeaMonkey
// \Topic (default) REG_SZ WWW_OpenURL
//
// - Windows Start Menu (Win2K SP2, XP SP1, and newer)
// -------------------------------------------------
// The following keys are set to make SeaMonkey appear in the Start Menu as the
// browser:
//
// HKCU\SOFTWARE\Clients\StartMenuInternet\SEAMONKEY.EXE\
// (default) REG_SZ <appname>
// DefaultIcon (default) REG_SZ <apppath>,0
// InstallInfo HideIconsCommand REG_SZ <uninstpath> /HideShortcuts
// InstallInfo IconsVisible REG_DWORD 1
// InstallInfo ReinstallCommand REG_SZ <uninstpath> /SetAsDefaultAppGlobal
// InstallInfo ShowIconsCommand REG_SZ <uninstpath> /ShowShortcuts
// shell\open\command (default) REG_SZ <apppath>
// shell\properties (default) REG_SZ <appname> &Preferences
// shell\properties\command (default) REG_SZ <apppath> -preferences
// shell\safemode (default) REG_SZ <appname> &Safe Mode
// shell\safemode\command (default) REG_SZ <apppath> -safe-mode
//
//
//
// Default Mail&News settings
//
// - File Extension Mappings
// -----------------------
// The following file extension:
// .eml
// is mapped like this:
//
// HKCU\SOFTWARE\Classes\.eml (default) REG_SZ SeaMonkeyEML
//
// That aliases to this class:
// HKCU\SOFTWARE\Classes\SeaMonkeyEML\ (default) REG_SZ SeaMonkey (Mail) Document
// FriendlyTypeName REG_SZ SeaMonkey (Mail) Document
// DefaultIcon (default) REG_SZ <appfolder>\chrome\icons\default\html-file.ico
// shell\open\command (default) REG_SZ <apppath> "%1"
//
// - Windows Vista Protocol Handler
//
// HKCU\SOFTWARE\Classes\SeaMonkeyCOMPOSE (default) REG_SZ SeaMonkey (Mail) URL
// DefaultIcon REG_SZ <apppath>,0
// EditFlags REG_DWORD 2
// shell\open\command (default) REG_SZ <apppath> -osint -compose "%1"
//
// HKCU\SOFTWARE\Classes\SeaMonkeyNEWS (default) REG_SZ SeaMonkey (News) URL
// DefaultIcon REG_SZ <apppath>,0
// EditFlags REG_DWORD 2
// shell\open\command (default) REG_SZ <apppath> -osint -news "%1"
//
//
// - Protocol Mappings
// -----------------
// The following protocol:
// mailto
// is mapped like this:
//
// HKCU\SOFTWARE\Classes\mailto\ (default) REG_SZ SeaMonkey (Mail) URL
// EditFlags REG_DWORD 2
// URL Protocol REG_SZ
// DefaultIcon (default) REG_SZ <apppath>,0
// shell\open\command (default) REG_SZ <apppath> -osint -compose "%1"
//
// The following protocols:
// news,nntp,snews
// are mapped like this:
//
// HKCU\SOFTWARE\Classes\<protocol>\ (default) REG_SZ SeaMonkey (News) URL
// EditFlags REG_DWORD 2
// URL Protocol REG_SZ
// DefaultIcon (default) REG_SZ <appath>,0
// shell\open\command (default) REG_SZ <appath> -osint -news "%1"
//
// - Windows Start Menu (Win2K SP2, XP SP1, and newer)
// -------------------------------------------------
// The following keys are set to make SeaMonkey appear in the Start Menu as
// the default mail program:
//
// HKCU\SOFTWARE\Clients\Mail\SeaMonkey
// (default) REG_SZ <appname>
// DLLPath REG_SZ <appfolder>\mozMapi32.dll
// DefaultIcon (default) REG_SZ <apppath>,0
// InstallInfo HideIconsCommand REG_SZ <uninstpath> /HideShortcuts
// InstallInfo ReinstallCommand REG_SZ <uninstpath> /SetAsDefaultAppGlobal
// InstallInfo ShowIconsCommand REG_SZ <uninstpath> /ShowShortcuts
// shell\open\command (default) REG_SZ <apppath> -mail
// shell\properties (default) REG_SZ <appname> &Preferences
// shell\properties\command (default) REG_SZ <apppath> -preferences
//
// Also set SeaMonkey as News reader (Usenet), though Windows does currently
// not expose a default news reader to UI. Applications like Outlook
// also add themselves to this registry key
//
// HKCU\SOFTWARE\Clients\News\SeaMonkey
// (default) REG_SZ <appname>
// DLLPath REG_SZ <appfolder>\mozMapi32.dll
// DefaultIcon (default) REG_SZ <apppath>,0
// shell\open\command (default) REG_SZ <apppath> -news
//
///////////////////////////////////////////////////////////////////////////////
typedef enum {
NO_SUBSTITUTION = 0x00,
APP_PATH_SUBSTITUTION = 0x01
} SettingFlags;
#define APP_REG_NAME L"SeaMonkey"
// APP_REG_NAME_MAIL and APP_REG_NAME_NEWS should be kept in synch with
// AppRegNameMail and AppRegNameNews in the installer file: defines.nsi.in
#define APP_REG_NAME_MAIL L"SeaMonkey (Mail)"
#define APP_REG_NAME_NEWS L"SeaMonkey (News)"
#define CLS_HTML "SeaMonkeyHTML"
#define CLS_URL "SeaMonkeyURL"
#define CLS_EML "SeaMonkeyEML"
#define CLS_MAILTOURL "SeaMonkeyCOMPOSE"
#define CLS_NEWSURL "SeaMonkeyNEWS"
#define CLS_FEEDURL "SeaMonkeyFEED"
#define SMI "SOFTWARE\\Clients\\StartMenuInternet\\"
#define DI "\\DefaultIcon"
#define II "\\InstallInfo"
#define SOP "\\shell\\open\\command"
#define VAL_ICON "%APPPATH%,0"
#define VAL_HTML_OPEN "\"%APPPATH%\" -url \"%1\""
#define VAL_URL_OPEN "\"%APPPATH%\" -requestPending -osint -url \"%1\""
#define VAL_MAIL_OPEN "\"%APPPATH%\" \"%1\""
#define MAKE_KEY_NAME1(PREFIX, MID) \
PREFIX MID
// The DefaultIcon registry key value should never be used (e.g. NON_ESSENTIAL)
// when checking if SeaMonkey is the default browser since other applications
// (e.g. MS Office) may modify the DefaultIcon registry key value to add Icon
// Handlers.
static SETTING gBrowserSettings[] = {
// File Extension Class - as of 1.8.1.2 the value for VAL_URL_OPEN is also
// checked for CLS_HTML since SeaMonkey should also own opening local files
// when set as the default browser.
{ MAKE_KEY_NAME1(CLS_HTML, SOP), "", VAL_HTML_OPEN, APP_PATH_SUBSTITUTION },
// Protocol Handler Class - for Vista and above
{ MAKE_KEY_NAME1(CLS_URL, SOP), "", VAL_URL_OPEN, APP_PATH_SUBSTITUTION },
// Protocol Handlers
{ MAKE_KEY_NAME1("HTTP", DI), "", VAL_ICON, APP_PATH_SUBSTITUTION },
{ MAKE_KEY_NAME1("HTTP", SOP), "", VAL_URL_OPEN, APP_PATH_SUBSTITUTION },
{ MAKE_KEY_NAME1("HTTPS", DI), "", VAL_ICON, APP_PATH_SUBSTITUTION },
{ MAKE_KEY_NAME1("HTTPS", SOP), "", VAL_URL_OPEN, APP_PATH_SUBSTITUTION }
// These values must be set by hand, since they contain localized strings.
// seamonkey.exe\shell\properties (default) REG_SZ SeaMonkey &Preferences
// seamonkey.exe\shell\safemode (default) REG_SZ SeaMonkey &Safe Mode
};
static SETTING gMailSettings[] = {
// File Extension Aliases
{ ".eml", "", CLS_EML, NO_SUBSTITUTION },
// File Extension Class
{ MAKE_KEY_NAME1(CLS_EML, SOP), "", VAL_MAIL_OPEN, APP_PATH_SUBSTITUTION},
// Protocol Handler Class - for Vista and above
{ MAKE_KEY_NAME1(CLS_MAILTOURL, SOP), "", "\"%APPPATH%\" -osint -compose \"%1\"", APP_PATH_SUBSTITUTION },
// Protocol Handlers
{ MAKE_KEY_NAME1("mailto", SOP), "", "\"%APPPATH%\" -osint -compose \"%1\"", APP_PATH_SUBSTITUTION }
};
static SETTING gNewsSettings[] = {
// Protocol Handler Class - for Vista and above
{ MAKE_KEY_NAME1(CLS_NEWSURL, SOP), "", "\"%APPPATH%\" -osint -mail \"%1\"", APP_PATH_SUBSTITUTION },
// Protocol Handlers
{ MAKE_KEY_NAME1("news", SOP), "", "\"%APPPATH%\" -osint -mail \"%1\"", APP_PATH_SUBSTITUTION },
{ MAKE_KEY_NAME1("nntp", SOP), "", "\"%APPPATH%\" -osint -mail \"%1\"", APP_PATH_SUBSTITUTION },
};
static SETTING gFeedSettings[] = {
// Protocol Handler Class - for Vista and above
{ MAKE_KEY_NAME1(CLS_FEEDURL, SOP), "", "\"%APPPATH%\" -osint -mail \"%1\"", APP_PATH_SUBSTITUTION },
// Protocol Handlers
{ MAKE_KEY_NAME1("feed", SOP), "", "\"%APPPATH%\" -osint -mail \"%1\"", APP_PATH_SUBSTITUTION },
};
nsresult
GetHelperPath(nsString& aPath)
{
nsresult rv;
nsCOMPtr<nsIProperties> directoryService =
do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIFile> appHelper;
rv = directoryService->Get(XRE_EXECUTABLE_FILE,
NS_GET_IID(nsIFile),
getter_AddRefs(appHelper));
NS_ENSURE_SUCCESS(rv, rv);
rv = appHelper->SetNativeLeafName("uninstall"_ns);
NS_ENSURE_SUCCESS(rv, rv);
rv = appHelper->AppendNative("helper.exe"_ns);
NS_ENSURE_SUCCESS(rv, rv);
rv = appHelper->GetPath(aPath);
aPath.Insert('"', 0);
aPath.Append('"');
return rv;
}
nsresult
LaunchHelper(const nsString& aPath)
{
STARTUPINFOW si = {sizeof(si), 0};
PROCESS_INFORMATION pi = {0};
BOOL ok = CreateProcessW(nullptr, (LPWSTR)aPath.get(), nullptr, nullptr,
FALSE, 0, nullptr, nullptr, &si, &pi);
if (!ok)
return NS_ERROR_FAILURE;
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return NS_OK;
}
/* helper routine. Iterate over the passed in settings object,
testing each key to see if we are handling it.
*/
bool
nsWindowsShellService::TestForDefault(SETTING aSettings[], int32_t aSize)
{
wchar_t currValue[MAX_BUF];
SETTING* end = aSettings + aSize;
for (SETTING * settings = aSettings; settings < end; ++settings) {
NS_ConvertUTF8toUTF16 dataLongPath(settings->valueData);
NS_ConvertUTF8toUTF16 dataShortPath(settings->valueData);
NS_ConvertUTF8toUTF16 key(settings->keyName);
NS_ConvertUTF8toUTF16 value(settings->valueName);
if (settings->flags & APP_PATH_SUBSTITUTION) {
int32_t offset = dataLongPath.Find(u"%APPPATH%");
dataLongPath.Replace(offset, 9, mAppLongPath);
// Remove the quotes around %APPPATH% in VAL_OPEN for short paths
int32_t offsetQuoted = dataShortPath.Find(u"\"%APPPATH%\"");
if (offsetQuoted != -1)
dataShortPath.Replace(offsetQuoted, 11, mAppShortPath);
else
dataShortPath.Replace(offset, 9, mAppShortPath);
}
::ZeroMemory(currValue, sizeof(currValue));
HKEY theKey;
nsresult rv = OpenKeyForReading(HKEY_CLASSES_ROOT, key.get(), &theKey);
if (NS_FAILED(rv))
// Key does not exist
return false;
DWORD len = sizeof currValue;
DWORD res = ::RegQueryValueExW(theKey, value.get(),
nullptr, nullptr, (LPBYTE)currValue, &len);
// Close the key we opened.
::RegCloseKey(theKey);
if (REG_FAILED(res) ||
_wcsicmp(dataLongPath.get(), currValue) &&
_wcsicmp(dataShortPath.get(), currValue)) {
// Key wasn't set, or was set to something else (something else became the default client)
return false;
}
}
return true;
}
nsresult nsWindowsShellService::Init()
{
wchar_t appPath[MAX_BUF];
if (!::GetModuleFileNameW(0, appPath, MAX_BUF))
return NS_ERROR_FAILURE;
mAppLongPath.Assign(appPath);
// Support short path to the exe so if it is already set the user is not
// prompted to set the default mail client again.
if (!::GetShortPathNameW(appPath, appPath, MAX_BUF))
return NS_ERROR_FAILURE;
mAppShortPath.Assign(appPath);
return NS_OK;
}
bool
nsWindowsShellService::IsDefaultClientVista(uint16_t aApps, bool* aIsDefaultClient)
{
IApplicationAssociationRegistration* pAAR;
HRESULT hr = CoCreateInstance(CLSID_ApplicationAssociationRegistration,
nullptr,
CLSCTX_INPROC,
IID_IApplicationAssociationRegistration,
(void**)&pAAR);
if (SUCCEEDED(hr)) {
BOOL isDefaultBrowser = true;
BOOL isDefaultMail = true;
BOOL isDefaultNews = true;
if (aApps & nsIShellService::BROWSER)
pAAR->QueryAppIsDefaultAll(AL_EFFECTIVE, APP_REG_NAME, &isDefaultBrowser);
if (aApps & nsIShellService::MAIL)
pAAR->QueryAppIsDefaultAll(AL_EFFECTIVE, APP_REG_NAME_MAIL, &isDefaultMail);
if (aApps & nsIShellService::NEWS)
pAAR->QueryAppIsDefaultAll(AL_EFFECTIVE, APP_REG_NAME_NEWS, &isDefaultNews);
*aIsDefaultClient = isDefaultBrowser && isDefaultNews && isDefaultMail;
pAAR->Release();
return true;
}
return false;
}
NS_IMETHODIMP
nsWindowsShellService::IsDefaultClient(bool aStartupCheck, uint16_t aApps, bool *aIsDefaultClient)
{
*aIsDefaultClient = true;
// for each type, check if it is the default app
// browser check needs to be at the top
if (aApps & nsIShellService::BROWSER) {
*aIsDefaultClient &= TestForDefault(gBrowserSettings, sizeof(gBrowserSettings)/sizeof(SETTING));
// Only check if this app is default on Vista if the previous checks
// indicate that this app is the default.
if (*aIsDefaultClient)
IsDefaultClientVista(nsIShellService::BROWSER, aIsDefaultClient);
}
if (aApps & nsIShellService::MAIL) {
*aIsDefaultClient &= TestForDefault(gMailSettings, sizeof(gMailSettings)/sizeof(SETTING));
// Only check if this app is default on Vista if the previous checks
// indicate that this app is the default.
if (*aIsDefaultClient)
IsDefaultClientVista(nsIShellService::MAIL, aIsDefaultClient);
}
if (aApps & nsIShellService::NEWS) {
*aIsDefaultClient &= TestForDefault(gNewsSettings, sizeof(gNewsSettings)/sizeof(SETTING));
// Only check if this app is default on Vista if the previous checks
// indicate that this app is the default.
if (*aIsDefaultClient)
IsDefaultClientVista(nsIShellService::NEWS, aIsDefaultClient);
}
return NS_OK;
}
NS_IMETHODIMP
nsWindowsShellService::SetDefaultClient(bool aForAllUsers,
bool aClaimAllTypes, uint16_t aApps)
{
nsAutoString appHelperPath;
if (NS_FAILED(GetHelperPath(appHelperPath)))
return NS_ERROR_FAILURE;
if (aForAllUsers)
appHelperPath.AppendLiteral(" /SetAsDefaultAppGlobal");
else {
appHelperPath.AppendLiteral(" /SetAsDefaultAppUser");
if (aApps & nsIShellService::BROWSER)
appHelperPath.AppendLiteral(" Browser");
if (aApps & nsIShellService::MAIL)
appHelperPath.AppendLiteral(" Mail");
if (aApps & nsIShellService::NEWS)
appHelperPath.AppendLiteral(" News");
}
return LaunchHelper(appHelperPath);
}
static nsresult
WriteBitmap(nsIFile* aFile, imgIContainer* aImage)
{
nsresult rv;
RefPtr<SourceSurface> surface =
aImage->GetFrame(imgIContainer::FRAME_CURRENT,
imgIContainer::FLAG_SYNC_DECODE);
NS_ENSURE_TRUE(surface, NS_ERROR_FAILURE);
// For either of the following formats we want to set the biBitCount member
// of the BITMAPINFOHEADER struct to 32, below. For that value the bitmap
// format defines that the A8/X8 WORDs in the bitmap byte stream be ignored
// for the BI_RGB value we use for the biCompression member.
MOZ_ASSERT(surface->GetFormat() == SurfaceFormat::B8G8R8A8 ||
surface->GetFormat() == SurfaceFormat::B8G8R8X8);
RefPtr<DataSourceSurface> dataSurface = surface->GetDataSurface();
NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE);
int32_t width = dataSurface->GetSize().width;
int32_t height = dataSurface->GetSize().height;
int32_t bytesPerPixel = 4 * sizeof(uint8_t);
int32_t bytesPerRow = bytesPerPixel * width;
// initialize these bitmap structs which we will later
// serialize directly to the head of the bitmap file
BITMAPINFOHEADER bmi;
bmi.biSize = sizeof(BITMAPINFOHEADER);
bmi.biWidth = width;
bmi.biHeight = height;
bmi.biPlanes = 1;
bmi.biBitCount = (WORD)bytesPerPixel*8;
bmi.biCompression = BI_RGB;
bmi.biSizeImage = bytesPerRow * height;
bmi.biXPelsPerMeter = 0;
bmi.biYPelsPerMeter = 0;
bmi.biClrUsed = 0;
bmi.biClrImportant = 0;
BITMAPFILEHEADER bf;
bf.bfType = 0x4D42; // 'BM'
bf.bfReserved1 = 0;
bf.bfReserved2 = 0;
bf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
bf.bfSize = bf.bfOffBits + bmi.biSizeImage;
// get a file output stream
nsCOMPtr<nsIOutputStream> stream;
rv = NS_NewLocalFileOutputStream(getter_AddRefs(stream), aFile);
NS_ENSURE_SUCCESS(rv, rv);
DataSourceSurface::MappedSurface map;
if (!dataSurface->Map(DataSourceSurface::MapType::READ, &map)) {
return NS_ERROR_FAILURE;
}
// write the bitmap headers and rgb pixel data to the file
rv = NS_ERROR_FAILURE;
if (stream) {
uint32_t written;
stream->Write((const char*)&bf, sizeof(BITMAPFILEHEADER), &written);
if (written == sizeof(BITMAPFILEHEADER)) {
stream->Write((const char*)&bmi, sizeof(BITMAPINFOHEADER), &written);
if (written == sizeof(BITMAPINFOHEADER)) {
// write out the image data backwards because the desktop won't
// show bitmaps with negative heights for top-to-bottom
uint32_t i = map.mStride * height;
rv = NS_OK;
do {
i -= map.mStride;
stream->Write(((const char*)map.mData) + i, bytesPerRow, &written);
if (written != bytesPerRow) {
rv = NS_ERROR_FAILURE;
break;
}
} while (i != 0);
}
}
stream->Close();
}
dataSurface->Unmap();
return rv;
}
NS_IMETHODIMP
nsWindowsShellService::SetDesktopBackground(dom::Element* aElement,
int32_t aPosition,
const nsACString& aImageName)
{
if (!aElement || !aElement->IsHTMLElement(nsGkAtoms::img)) {
// XXX write background loading stuff!
return NS_ERROR_NOT_AVAILABLE;
}
nsresult rv;
nsCOMPtr<nsIImageLoadingContent> imageContent =
do_QueryInterface(aElement, &rv);
if (!imageContent)
return rv;
// get the image container
nsCOMPtr<imgIRequest> request;
rv = imageContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
getter_AddRefs(request));
if (!request)
return rv;
nsCOMPtr<imgIContainer> container;
rv = request->GetImage(getter_AddRefs(container));
if (!container)
return NS_ERROR_FAILURE;
// get the file name from localized strings
nsCOMPtr<nsIStringBundleService> bundleService(
do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIStringBundle> shellBundle;
rv = bundleService->CreateBundle(SHELLSERVICE_PROPERTIES,
getter_AddRefs(shellBundle));
NS_ENSURE_SUCCESS(rv, rv);
// e.g. "Desktop Background.bmp"
nsAutoString fileLeafName;
rv = shellBundle->GetStringFromName("desktopBackgroundLeafNameWin",
fileLeafName);
NS_ENSURE_SUCCESS(rv, rv);
// get the profile root directory
nsCOMPtr<nsIFile> file;
rv = NS_GetSpecialDirectory(NS_APP_APPLICATION_REGISTRY_DIR,
getter_AddRefs(file));
NS_ENSURE_SUCCESS(rv, rv);
// eventually, the path is "%APPDATA%\Mozilla\SeaMonkey\Desktop Background.bmp"
rv = file->Append(fileLeafName);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString path;
rv = file->GetPath(path);
NS_ENSURE_SUCCESS(rv, rv);
// write the bitmap to a file in the profile directory
rv = WriteBitmap(file, container);
// if the file was written successfully, set it as the system wallpaper
if (NS_SUCCEEDED(rv)) {
nsCOMPtr<nsIWindowsRegKey> key(do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv));
NS_ENSURE_SUCCESS(rv, rv);
rv = key->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
u"Control Panel\\Desktop"_ns,
nsIWindowsRegKey::ACCESS_SET_VALUE);
NS_ENSURE_SUCCESS(rv, rv);
int style = 0;
switch (aPosition) {
case BACKGROUND_STRETCH:
style = 2;
break;
case BACKGROUND_FILL:
style = 10;
break;
case BACKGROUND_FIT:
style = 6;
break;
}
nsString value;
value.AppendInt(style);
rv = key->WriteStringValue(u"WallpaperStyle"_ns, value);
NS_ENSURE_SUCCESS(rv, rv);
value.Assign(aPosition == BACKGROUND_TILE ? '1' : '0');
rv = key->WriteStringValue(u"TileWallpaper"_ns, value);
NS_ENSURE_SUCCESS(rv, rv);
rv = key->Close();
NS_ENSURE_SUCCESS(rv, rv);
::SystemParametersInfoW(SPI_SETDESKWALLPAPER, 0, (PVOID)path.get(),
SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);
}
return rv;
}
NS_IMETHODIMP
nsWindowsShellService::GetDesktopBackgroundColor(uint32_t* aColor)
{
uint32_t color = ::GetSysColor(COLOR_DESKTOP);
*aColor = (GetRValue(color) << 16) | (GetGValue(color) << 8) | GetBValue(color);
return NS_OK;
}
NS_IMETHODIMP
nsWindowsShellService::SetDesktopBackgroundColor(uint32_t aColor)
{
int parameter = COLOR_DESKTOP;
BYTE r = (aColor >> 16);
BYTE g = (aColor << 16) >> 24;
BYTE b = (aColor << 24) >> 24;
COLORREF color = RGB(r,g,b);
::SetSysColors(1, ¶meter, &color);
nsresult rv;
nsCOMPtr<nsIWindowsRegKey> key(do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv));
NS_ENSURE_SUCCESS(rv, rv);
rv = key->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
u"Control Panel\\Colors"_ns,
nsIWindowsRegKey::ACCESS_SET_VALUE);
NS_ENSURE_SUCCESS(rv, rv);
wchar_t rgb[12];
_snwprintf(rgb, 12, L"%u %u %u", r, g, b);
rv = key->WriteStringValue(u"Background"_ns,
nsDependentString(rgb));
NS_ENSURE_SUCCESS(rv, rv);
return key->Close();
}
NS_IMETHODIMP
nsWindowsShellService::OpenApplicationWithURI(nsIFile* aApplication,
const nsACString& aURI)
{
nsresult rv;
nsCOMPtr<nsIProcess> process =
do_CreateInstance("@mozilla.org/process/util;1", &rv);
if (NS_FAILED(rv))
return rv;
rv = process->Init(aApplication);
if (NS_FAILED(rv))
return rv;
const nsCString& spec = PromiseFlatCString(aURI);
const char* specStr = spec.get();
return process->Run(false, &specStr, 1);
}
NS_IMETHODIMP
nsWindowsShellService::GetDefaultFeedReader(nsIFile** _retval)
{
*_retval = nullptr;
nsresult rv;
nsCOMPtr<nsIWindowsRegKey> key(do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv));
NS_ENSURE_SUCCESS(rv, rv);
rv = key->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
u"feed\\shell\\open\\command"_ns,
nsIWindowsRegKey::ACCESS_READ);
NS_ENSURE_SUCCESS(rv, rv);
nsString path;
rv = key->ReadStringValue(EmptyString(), path);
NS_ENSURE_SUCCESS(rv, rv);
if (path.IsEmpty())
return NS_ERROR_FAILURE;
if (path.First() == '"') {
// Everything inside the quotes
path = Substring(path, 1, path.FindChar('"', 1) - 1);
} else {
// Everything up to the first space
path = Substring(path, 0, path.FindChar(' '));
}
nsCOMPtr<nsIFile> defaultReader =
do_CreateInstance("@mozilla.org/file/local;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = defaultReader->InitWithPath(path);
NS_ENSURE_SUCCESS(rv, rv);
bool exists;
rv = defaultReader->Exists(&exists);
NS_ENSURE_SUCCESS(rv, rv);
if (!exists)
return NS_ERROR_FAILURE;
NS_ADDREF(*_retval = defaultReader);
return NS_OK;
}