зеркало из https://github.com/mozilla/gecko-dev.git
558 строки
14 KiB
C++
558 строки
14 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim:set ts=2 sts=2 sw=2 et cin: */
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is mozilla.org code.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Mozilla Foundation.
|
|
* Portions created by the Initial Developer are Copyright (C) 2011
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Masayuki Nakano <masayuki@d-toybox.com>
|
|
*
|
|
* Original nsWindow.cpp Contributor(s):
|
|
* Dean Tessman <dean_tessman@hotmail.com>
|
|
* Ere Maijala <emaijala@kolumbus.fi>
|
|
* Mark Hammond <markh@activestate.com>
|
|
* Michael Lowe <michael.lowe@bigfoot.com>
|
|
* Peter Bajusz <hyp-x@inf.bme.hu>
|
|
* Pierre Phaneuf <pp@ludusdesign.com>
|
|
* Robert O'Callahan <roc+moz@cs.cmu.edu>
|
|
* Roy Yokoyama <yokoyama@netscape.com>
|
|
* Makoto Kato <m_kato@ga2.so-net.ne.jp>
|
|
* Masayuki Nakano <masayuki@d-toybox.com>
|
|
* Dainis Jonitis <Dainis_Jonitis@swh-t.lv>
|
|
* Christian Biesinger <cbiesinger@web.de>
|
|
* Mats Palmgren <matspal@gmail.com>
|
|
* Ningjie Chen <chenn@email.uc.edu>
|
|
* Jim Mathies <jmathies@mozilla.com>
|
|
* Kyle Huey <me@kylehuey.com>
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
#include "WinUtils.h"
|
|
#include "nsWindow.h"
|
|
#include "nsWindowDefs.h"
|
|
#include "nsGUIEvent.h"
|
|
#include "nsIDOMMouseEvent.h"
|
|
#include "mozilla/Preferences.h"
|
|
|
|
#ifdef DEBUG
|
|
#ifndef max
|
|
#define max(a,b) (((a) > (b)) ? (a) : (b))
|
|
#endif
|
|
|
|
#ifndef min
|
|
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
|
#endif
|
|
|
|
#include <gdiplus.h>
|
|
#endif
|
|
|
|
namespace mozilla {
|
|
namespace widget {
|
|
|
|
// SHCreateItemFromParsingName is only available on vista and up.
|
|
WinUtils::SHCreateItemFromParsingNamePtr WinUtils::sCreateItemFromParsingName = nsnull;
|
|
|
|
/* static */
|
|
WinUtils::WinVersion
|
|
WinUtils::GetWindowsVersion()
|
|
{
|
|
static PRInt32 version = 0;
|
|
|
|
if (version) {
|
|
return static_cast<WinVersion>(version);
|
|
}
|
|
|
|
OSVERSIONINFOEX osInfo;
|
|
osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
|
|
// This cast is safe and supposed to be here, don't worry
|
|
::GetVersionEx((OSVERSIONINFO*)&osInfo);
|
|
version =
|
|
(osInfo.dwMajorVersion & 0xff) << 8 | (osInfo.dwMinorVersion & 0xff);
|
|
return static_cast<WinVersion>(version);
|
|
}
|
|
|
|
/* static */
|
|
bool
|
|
WinUtils::GetRegistryKey(HKEY aRoot,
|
|
const PRUnichar* aKeyName,
|
|
const PRUnichar* aValueName,
|
|
PRUnichar* aBuffer,
|
|
DWORD aBufferLength)
|
|
{
|
|
NS_PRECONDITION(aKeyName, "The key name is NULL");
|
|
|
|
HKEY key;
|
|
LONG result =
|
|
::RegOpenKeyExW(aRoot, aKeyName, NULL, KEY_READ | KEY_WOW64_32KEY, &key);
|
|
if (result != ERROR_SUCCESS) {
|
|
result =
|
|
::RegOpenKeyExW(aRoot, aKeyName, NULL, KEY_READ | KEY_WOW64_64KEY, &key);
|
|
if (result != ERROR_SUCCESS) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
DWORD type;
|
|
result =
|
|
::RegQueryValueExW(key, aValueName, NULL, &type, (BYTE*) aBuffer,
|
|
&aBufferLength);
|
|
::RegCloseKey(key);
|
|
if (result != ERROR_SUCCESS || type != REG_SZ) {
|
|
return false;
|
|
}
|
|
if (aBuffer) {
|
|
aBuffer[aBufferLength / sizeof(*aBuffer) - 1] = 0;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/* static */
|
|
bool
|
|
WinUtils::HasRegistryKey(HKEY aRoot, const PRUnichar* aKeyName)
|
|
{
|
|
MOZ_ASSERT(aRoot, "aRoot must not be NULL");
|
|
MOZ_ASSERT(aKeyName, "aKeyName must not be NULL");
|
|
HKEY key;
|
|
LONG result =
|
|
::RegOpenKeyExW(aRoot, aKeyName, 0, KEY_READ | KEY_WOW64_32KEY, &key);
|
|
if (result != ERROR_SUCCESS) {
|
|
result =
|
|
::RegOpenKeyExW(aRoot, aKeyName, 0, KEY_READ | KEY_WOW64_64KEY, &key);
|
|
if (result != ERROR_SUCCESS) {
|
|
return false;
|
|
}
|
|
}
|
|
::RegCloseKey(key);
|
|
return true;
|
|
}
|
|
|
|
/* static */
|
|
HWND
|
|
WinUtils::GetTopLevelHWND(HWND aWnd,
|
|
bool aStopIfNotChild,
|
|
bool aStopIfNotPopup)
|
|
{
|
|
HWND curWnd = aWnd;
|
|
HWND topWnd = NULL;
|
|
|
|
while (curWnd) {
|
|
topWnd = curWnd;
|
|
|
|
if (aStopIfNotChild) {
|
|
DWORD_PTR style = ::GetWindowLongPtrW(curWnd, GWL_STYLE);
|
|
|
|
VERIFY_WINDOW_STYLE(style);
|
|
|
|
if (!(style & WS_CHILD)) // first top-level window
|
|
break;
|
|
}
|
|
|
|
HWND upWnd = ::GetParent(curWnd); // Parent or owner (if has no parent)
|
|
|
|
// GetParent will only return the owner if the passed in window
|
|
// has the WS_POPUP style.
|
|
if (!upWnd && !aStopIfNotPopup) {
|
|
upWnd = ::GetWindow(curWnd, GW_OWNER);
|
|
}
|
|
curWnd = upWnd;
|
|
}
|
|
|
|
return topWnd;
|
|
}
|
|
|
|
static PRUnichar*
|
|
GetNSWindowPropName()
|
|
{
|
|
static PRUnichar sPropName[40] = L"";
|
|
if (!*sPropName) {
|
|
_snwprintf(sPropName, 39, L"MozillansIWidgetPtr%p",
|
|
::GetCurrentProcessId());
|
|
sPropName[39] = '\0';
|
|
}
|
|
return sPropName;
|
|
}
|
|
|
|
/* static */
|
|
bool
|
|
WinUtils::SetNSWindowPtr(HWND aWnd, nsWindow* aWindow)
|
|
{
|
|
if (!aWindow) {
|
|
::RemovePropW(aWnd, GetNSWindowPropName());
|
|
return true;
|
|
}
|
|
return ::SetPropW(aWnd, GetNSWindowPropName(), (HANDLE)aWindow);
|
|
}
|
|
|
|
/* static */
|
|
nsWindow*
|
|
WinUtils::GetNSWindowPtr(HWND aWnd)
|
|
{
|
|
return static_cast<nsWindow*>(::GetPropW(aWnd, GetNSWindowPropName()));
|
|
}
|
|
|
|
static BOOL CALLBACK
|
|
AddMonitor(HMONITOR, HDC, LPRECT, LPARAM aParam)
|
|
{
|
|
(*(PRInt32*)aParam)++;
|
|
return TRUE;
|
|
}
|
|
|
|
/* static */
|
|
PRInt32
|
|
WinUtils::GetMonitorCount()
|
|
{
|
|
PRInt32 monitorCount = 0;
|
|
EnumDisplayMonitors(NULL, NULL, AddMonitor, (LPARAM)&monitorCount);
|
|
return monitorCount;
|
|
}
|
|
|
|
/* static */
|
|
bool
|
|
WinUtils::IsOurProcessWindow(HWND aWnd)
|
|
{
|
|
if (!aWnd) {
|
|
return false;
|
|
}
|
|
DWORD processId = 0;
|
|
::GetWindowThreadProcessId(aWnd, &processId);
|
|
return (processId == ::GetCurrentProcessId());
|
|
}
|
|
|
|
/* static */
|
|
HWND
|
|
WinUtils::FindOurProcessWindow(HWND aWnd)
|
|
{
|
|
for (HWND wnd = ::GetParent(aWnd); wnd; wnd = ::GetParent(wnd)) {
|
|
if (IsOurProcessWindow(wnd)) {
|
|
return wnd;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static bool
|
|
IsPointInWindow(HWND aWnd, const POINT& aPointInScreen)
|
|
{
|
|
RECT bounds;
|
|
if (!::GetWindowRect(aWnd, &bounds)) {
|
|
return false;
|
|
}
|
|
|
|
return (aPointInScreen.x >= bounds.left && aPointInScreen.x < bounds.right &&
|
|
aPointInScreen.y >= bounds.top && aPointInScreen.y < bounds.bottom);
|
|
}
|
|
|
|
/**
|
|
* FindTopmostWindowAtPoint() returns the topmost child window (topmost means
|
|
* forground in this context) of aWnd.
|
|
*/
|
|
|
|
static HWND
|
|
FindTopmostWindowAtPoint(HWND aWnd, const POINT& aPointInScreen)
|
|
{
|
|
if (!::IsWindowVisible(aWnd) || !IsPointInWindow(aWnd, aPointInScreen)) {
|
|
return NULL;
|
|
}
|
|
|
|
HWND childWnd = ::GetTopWindow(aWnd);
|
|
while (childWnd) {
|
|
HWND topmostWnd = FindTopmostWindowAtPoint(childWnd, aPointInScreen);
|
|
if (topmostWnd) {
|
|
return topmostWnd;
|
|
}
|
|
childWnd = ::GetNextWindow(childWnd, GW_HWNDNEXT);
|
|
}
|
|
|
|
return aWnd;
|
|
}
|
|
|
|
struct FindOurWindowAtPointInfo
|
|
{
|
|
POINT mInPointInScreen;
|
|
HWND mOutWnd;
|
|
};
|
|
|
|
static BOOL CALLBACK
|
|
FindOurWindowAtPointCallback(HWND aWnd, LPARAM aLPARAM)
|
|
{
|
|
if (!WinUtils::IsOurProcessWindow(aWnd)) {
|
|
// This isn't one of our top-level windows; continue enumerating.
|
|
return TRUE;
|
|
}
|
|
|
|
// Get the top-most child window under the point. If there's no child
|
|
// window, and the point is within the top-level window, then the top-level
|
|
// window will be returned. (This is the usual case. A child window
|
|
// would be returned for plugins.)
|
|
FindOurWindowAtPointInfo* info =
|
|
reinterpret_cast<FindOurWindowAtPointInfo*>(aLPARAM);
|
|
HWND childWnd = FindTopmostWindowAtPoint(aWnd, info->mInPointInScreen);
|
|
if (!childWnd) {
|
|
// This window doesn't contain the point; continue enumerating.
|
|
return TRUE;
|
|
}
|
|
|
|
// Return the HWND and stop enumerating.
|
|
info->mOutWnd = childWnd;
|
|
return FALSE;
|
|
}
|
|
|
|
/* static */
|
|
HWND
|
|
WinUtils::FindOurWindowAtPoint(const POINT& aPointInScreen)
|
|
{
|
|
FindOurWindowAtPointInfo info;
|
|
info.mInPointInScreen = aPointInScreen;
|
|
info.mOutWnd = NULL;
|
|
|
|
// This will enumerate all top-level windows in order from top to bottom.
|
|
EnumWindows(FindOurWindowAtPointCallback, reinterpret_cast<LPARAM>(&info));
|
|
return info.mOutWnd;
|
|
}
|
|
|
|
/* static */
|
|
UINT
|
|
WinUtils::GetInternalMessage(UINT aNativeMessage)
|
|
{
|
|
switch (aNativeMessage) {
|
|
case WM_MOUSEWHEEL:
|
|
return MOZ_WM_MOUSEVWHEEL;
|
|
case WM_MOUSEHWHEEL:
|
|
return MOZ_WM_MOUSEHWHEEL;
|
|
case WM_VSCROLL:
|
|
return MOZ_WM_VSCROLL;
|
|
case WM_HSCROLL:
|
|
return MOZ_WM_HSCROLL;
|
|
default:
|
|
return aNativeMessage;
|
|
}
|
|
}
|
|
|
|
/* static */
|
|
UINT
|
|
WinUtils::GetNativeMessage(UINT aInternalMessage)
|
|
{
|
|
switch (aInternalMessage) {
|
|
case MOZ_WM_MOUSEVWHEEL:
|
|
return WM_MOUSEWHEEL;
|
|
case MOZ_WM_MOUSEHWHEEL:
|
|
return WM_MOUSEHWHEEL;
|
|
case MOZ_WM_VSCROLL:
|
|
return WM_VSCROLL;
|
|
case MOZ_WM_HSCROLL:
|
|
return WM_HSCROLL;
|
|
default:
|
|
return aInternalMessage;
|
|
}
|
|
}
|
|
|
|
/* static */
|
|
PRUint16
|
|
WinUtils::GetMouseInputSource()
|
|
{
|
|
PRInt32 inputSource = nsIDOMMouseEvent::MOZ_SOURCE_MOUSE;
|
|
LPARAM lParamExtraInfo = ::GetMessageExtraInfo();
|
|
if ((lParamExtraInfo & TABLET_INK_SIGNATURE) == TABLET_INK_CHECK) {
|
|
inputSource = (lParamExtraInfo & TABLET_INK_TOUCH) ?
|
|
nsIDOMMouseEvent::MOZ_SOURCE_TOUCH : nsIDOMMouseEvent::MOZ_SOURCE_PEN;
|
|
}
|
|
return static_cast<PRUint16>(inputSource);
|
|
}
|
|
|
|
/* static */
|
|
MSG
|
|
WinUtils::InitMSG(UINT aMessage, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
MSG msg;
|
|
msg.message = aMessage;
|
|
msg.wParam = wParam;
|
|
msg.lParam = lParam;
|
|
return msg;
|
|
}
|
|
|
|
/* static */
|
|
bool
|
|
WinUtils::VistaCreateItemFromParsingNameInit()
|
|
{
|
|
// Load and store Vista+ SHCreateItemFromParsingName
|
|
if (sCreateItemFromParsingName) {
|
|
return true;
|
|
}
|
|
static HMODULE sShellDll = nsnull;
|
|
if (sShellDll) {
|
|
return false;
|
|
}
|
|
static const PRUnichar kSehllLibraryName[] = L"shell32.dll";
|
|
sShellDll = ::LoadLibraryW(kSehllLibraryName);
|
|
if (!sShellDll) {
|
|
return false;
|
|
}
|
|
sCreateItemFromParsingName = (SHCreateItemFromParsingNamePtr)
|
|
GetProcAddress(sShellDll, "SHCreateItemFromParsingName");
|
|
return sCreateItemFromParsingName != nsnull;
|
|
}
|
|
|
|
/* static */
|
|
HRESULT
|
|
WinUtils::SHCreateItemFromParsingName(PCWSTR pszPath, IBindCtx *pbc,
|
|
REFIID riid, void **ppv)
|
|
{
|
|
if (!VistaCreateItemFromParsingNameInit())
|
|
return E_FAIL;
|
|
return sCreateItemFromParsingName(pszPath, pbc, riid, ppv);
|
|
}
|
|
|
|
/* static */
|
|
bool
|
|
WinUtils::GetShellItemPath(IShellItem* aItem,
|
|
nsString& aResultString)
|
|
{
|
|
NS_ENSURE_TRUE(aItem, false);
|
|
LPWSTR str = NULL;
|
|
if (FAILED(aItem->GetDisplayName(SIGDN_FILESYSPATH, &str)))
|
|
return false;
|
|
aResultString.Assign(str);
|
|
CoTaskMemFree(str);
|
|
return !aResultString.IsEmpty();
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
// Win xp and up
|
|
#pragma comment(lib, "gdiplus.lib")
|
|
|
|
static bool
|
|
GetEncoderClsid(const WCHAR* aFormat, CLSID* aClsid)
|
|
{
|
|
using namespace Gdiplus;
|
|
|
|
UINT num = 0;
|
|
UINT size = 0;
|
|
|
|
ImageCodecInfo* pImageCodecInfo = NULL;
|
|
|
|
GetImageEncodersSize(&num, &size);
|
|
if(size == 0)
|
|
return false;
|
|
|
|
pImageCodecInfo = (ImageCodecInfo*)(moz_malloc(size));
|
|
|
|
if (GetImageEncoders(num, size, pImageCodecInfo) != Ok)
|
|
return false;
|
|
|
|
for(UINT j = 0; j < num; ++j) {
|
|
if(!wcscmp(pImageCodecInfo[j].MimeType, aFormat)) {
|
|
*aClsid = pImageCodecInfo[j].Clsid;
|
|
moz_free(pImageCodecInfo);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
moz_free(pImageCodecInfo);
|
|
return false;
|
|
}
|
|
|
|
/* static */
|
|
void
|
|
WinUtils::SaveDCToPng(HDC aHdc, const WCHAR* aFilePath, int aXPos, int aYPos,
|
|
int aWidth, int aHeight)
|
|
{
|
|
using namespace Gdiplus;
|
|
|
|
static ULONG_PTR sGiplusToken;
|
|
|
|
nsCOMPtr<nsILocalFile> file(do_CreateInstance("@mozilla.org/file/local;1"));
|
|
if (!file || NS_FAILED(file->InitWithPath(nsDependentString(aFilePath)))) {
|
|
NS_WARNING("bad file path.");
|
|
return;
|
|
}
|
|
|
|
GdiplusStartupInput gdiplusStartupInput;
|
|
if (!sGiplusToken)
|
|
GdiplusStartup(&sGiplusToken, &gdiplusStartupInput, NULL);
|
|
|
|
HDC memdc;
|
|
HBITMAP membit;
|
|
memdc = CreateCompatibleDC(aHdc);
|
|
NS_WARN_IF_FALSE(memdc, "CreateCompatibleDC failed");
|
|
if (!memdc)
|
|
return;
|
|
membit = CreateCompatibleBitmap(aHdc, aWidth, aHeight);
|
|
NS_WARN_IF_FALSE(membit, "CreateCompatibleBitmap failed");
|
|
if (!membit) {
|
|
DeleteObject(memdc);
|
|
return;
|
|
}
|
|
HBITMAP hOldBitmap =(HBITMAP) SelectObject(memdc, membit);
|
|
if (!hOldBitmap || hOldBitmap == HGDI_ERROR) {
|
|
DeleteObject(memdc);
|
|
DeleteObject(membit);
|
|
return;
|
|
}
|
|
BitBlt(memdc, 0, 0, aWidth, aHeight, aHdc, aXPos, aYPos, SRCCOPY);
|
|
|
|
Gdiplus::Bitmap bitmap(membit, NULL);
|
|
|
|
CLSID clsid;
|
|
if (!GetEncoderClsid(L"image/png", &clsid)) {
|
|
NS_WARNING("GetEncoderClsid failed");
|
|
return;
|
|
}
|
|
|
|
file->Remove(false);
|
|
if (bitmap.Save(aFilePath, &clsid) != Ok) {
|
|
NS_WARNING("bitmap.Save faled.");
|
|
}
|
|
|
|
SelectObject(memdc, hOldBitmap);
|
|
DeleteObject(memdc);
|
|
DeleteObject(membit);
|
|
}
|
|
|
|
/* static */
|
|
void
|
|
WinUtils::SaveDCToPngIndexed(HDC aHdc, const WCHAR* aDirectory, const WCHAR* aAnnotation,
|
|
int aXPos, int aYPos, int aWidth, int aHeight)
|
|
{
|
|
static int sPngFileIndex;
|
|
WCHAR filename[512];
|
|
filename[0] = 0;
|
|
wsprintf(filename, L"%s\\%s_image-%d.png", aDirectory, aAnnotation,
|
|
sPngFileIndex);
|
|
sPngFileIndex++;
|
|
WinUtils::SaveDCToPng(aHdc, filename, aXPos, aYPos, aWidth, aHeight);
|
|
}
|
|
|
|
#endif // DEBUG
|
|
|
|
} // namespace widget
|
|
} // namespace mozilla
|