michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim:set ts=2 sts=2 sw=2 et cin: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* michael@0: * nsWindow - Native window management and event handling. michael@0: * michael@0: * nsWindow is organized into a set of major blocks and michael@0: * block subsections. The layout is as follows: michael@0: * michael@0: * Includes michael@0: * Variables michael@0: * nsIWidget impl. michael@0: * nsIWidget methods and utilities michael@0: * nsSwitchToUIThread impl. michael@0: * nsSwitchToUIThread methods and utilities michael@0: * Moz events michael@0: * Event initialization michael@0: * Event dispatching michael@0: * Native events michael@0: * Wndproc(s) michael@0: * Event processing michael@0: * OnEvent event handlers michael@0: * IME management and accessibility michael@0: * Transparency michael@0: * Popup hook handling michael@0: * Misc. utilities michael@0: * Child window impl. michael@0: * michael@0: * Search for "BLOCK:" to find major blocks. michael@0: * Search for "SECTION:" to find specific sections. michael@0: * michael@0: * Blocks should be split out into separate files if they michael@0: * become unmanageable. michael@0: * michael@0: * Related source: michael@0: * michael@0: * nsWindowDefs.h - Definitions, macros, structs, enums michael@0: * and general setup. michael@0: * nsWindowDbg.h/.cpp - Debug related code and directives. michael@0: * nsWindowGfx.h/.cpp - Graphics and painting. michael@0: * michael@0: */ michael@0: michael@0: /************************************************************** michael@0: ************************************************************** michael@0: ** michael@0: ** BLOCK: Includes michael@0: ** michael@0: ** Include headers. michael@0: ** michael@0: ************************************************************** michael@0: **************************************************************/ michael@0: michael@0: #include "mozilla/MathAlgorithms.h" michael@0: #include "mozilla/MiscEvents.h" michael@0: #include "mozilla/MouseEvents.h" michael@0: #include "mozilla/TouchEvents.h" michael@0: michael@0: #include "mozilla/ipc/MessageChannel.h" michael@0: #include michael@0: michael@0: #include "nsWindow.h" michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include "prlog.h" michael@0: #include "prtime.h" michael@0: #include "prprf.h" michael@0: #include "prmem.h" michael@0: #include "prenv.h" michael@0: michael@0: #include "mozilla/WidgetTraceEvent.h" michael@0: #include "nsIAppShell.h" michael@0: #include "nsISupportsPrimitives.h" michael@0: #include "nsIDOMMouseEvent.h" michael@0: #include "nsITheme.h" michael@0: #include "nsIObserverService.h" michael@0: #include "nsIScreenManager.h" michael@0: #include "imgIContainer.h" michael@0: #include "nsIFile.h" michael@0: #include "nsIRollupListener.h" michael@0: #include "nsIServiceManager.h" michael@0: #include "nsIClipboard.h" michael@0: #include "nsIMM32Handler.h" michael@0: #include "WinMouseScrollHandler.h" michael@0: #include "nsFontMetrics.h" michael@0: #include "nsIFontEnumerator.h" michael@0: #include "nsFont.h" michael@0: #include "nsRect.h" michael@0: #include "nsThreadUtils.h" michael@0: #include "nsNativeCharsetUtils.h" michael@0: #include "nsGkAtoms.h" michael@0: #include "nsCRT.h" michael@0: #include "nsAppDirectoryServiceDefs.h" michael@0: #include "nsXPIDLString.h" michael@0: #include "nsWidgetsCID.h" michael@0: #include "nsTHashtable.h" michael@0: #include "nsHashKeys.h" michael@0: #include "nsString.h" michael@0: #include "mozilla/Services.h" michael@0: #include "nsNativeThemeWin.h" michael@0: #include "nsWindowsDllInterceptor.h" michael@0: #include "nsLayoutUtils.h" michael@0: #include "nsView.h" michael@0: #include "nsIWindowMediator.h" michael@0: #include "nsIServiceManager.h" michael@0: #include "nsWindowGfx.h" michael@0: #include "gfxWindowsPlatform.h" michael@0: #include "Layers.h" michael@0: #include "nsPrintfCString.h" michael@0: #include "mozilla/Preferences.h" michael@0: #include "nsISound.h" michael@0: #include "WinTaskbar.h" michael@0: #include "WinUtils.h" michael@0: #include "WidgetUtils.h" michael@0: #include "nsIWidgetListener.h" michael@0: #include "mozilla/dom/Touch.h" michael@0: #include "mozilla/gfx/2D.h" michael@0: #include "nsToolkitCompsCID.h" michael@0: #include "nsIAppStartup.h" michael@0: #include "mozilla/WindowsVersion.h" michael@0: #include "nsThemeConstants.h" michael@0: michael@0: #ifdef MOZ_ENABLE_D3D9_LAYER michael@0: #include "LayerManagerD3D9.h" michael@0: #endif michael@0: michael@0: #ifdef MOZ_ENABLE_D3D10_LAYER michael@0: #include "LayerManagerD3D10.h" michael@0: #endif michael@0: michael@0: #include "nsIGfxInfo.h" michael@0: #include "nsUXThemeConstants.h" michael@0: #include "KeyboardLayout.h" michael@0: #include "nsNativeDragTarget.h" michael@0: #include // needed for WIN32_LEAN_AND_MEAN michael@0: #include michael@0: #include michael@0: michael@0: #if defined(ACCESSIBILITY) michael@0: michael@0: #ifdef DEBUG michael@0: #include "mozilla/a11y/Logging.h" michael@0: #endif michael@0: michael@0: #include "oleidl.h" michael@0: #include michael@0: #include "nsAccessibilityService.h" michael@0: #include "mozilla/a11y/DocAccessible.h" michael@0: #include "mozilla/a11y/Platform.h" michael@0: #if !defined(WINABLEAPI) michael@0: #include michael@0: #endif // !defined(WINABLEAPI) michael@0: #endif // defined(ACCESSIBILITY) michael@0: michael@0: #include "nsIWinTaskbar.h" michael@0: #define NS_TASKBAR_CONTRACTID "@mozilla.org/windows-taskbar;1" michael@0: michael@0: #include "nsWindowDefs.h" michael@0: michael@0: #include "nsCrashOnException.h" michael@0: #include "nsIXULRuntime.h" michael@0: michael@0: #include "nsIContent.h" michael@0: michael@0: #include "mozilla/HangMonitor.h" michael@0: #include "WinIMEHandler.h" michael@0: michael@0: #include "npapi.h" michael@0: michael@0: #if !defined(SM_CONVERTIBLESLATEMODE) michael@0: #define SM_CONVERTIBLESLATEMODE 0x2003 michael@0: #endif michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::dom; michael@0: using namespace mozilla::layers; michael@0: using namespace mozilla::widget; michael@0: michael@0: /************************************************************** michael@0: ************************************************************** michael@0: ** michael@0: ** BLOCK: Variables michael@0: ** michael@0: ** nsWindow Class static initializations and global variables. michael@0: ** michael@0: ************************************************************** michael@0: **************************************************************/ michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: nsWindow statics michael@0: * michael@0: **************************************************************/ michael@0: michael@0: bool nsWindow::sDropShadowEnabled = true; michael@0: uint32_t nsWindow::sInstanceCount = 0; michael@0: bool nsWindow::sSwitchKeyboardLayout = false; michael@0: BOOL nsWindow::sIsOleInitialized = FALSE; michael@0: HCURSOR nsWindow::sHCursor = nullptr; michael@0: imgIContainer* nsWindow::sCursorImgContainer = nullptr; michael@0: nsWindow* nsWindow::sCurrentWindow = nullptr; michael@0: bool nsWindow::sJustGotDeactivate = false; michael@0: bool nsWindow::sJustGotActivate = false; michael@0: bool nsWindow::sIsInMouseCapture = false; michael@0: michael@0: // imported in nsWidgetFactory.cpp michael@0: TriStateBool nsWindow::sCanQuit = TRI_UNKNOWN; michael@0: michael@0: // Hook Data Memebers for Dropdowns. sProcessHook Tells the michael@0: // hook methods whether they should be processing the hook michael@0: // messages. michael@0: HHOOK nsWindow::sMsgFilterHook = nullptr; michael@0: HHOOK nsWindow::sCallProcHook = nullptr; michael@0: HHOOK nsWindow::sCallMouseHook = nullptr; michael@0: bool nsWindow::sProcessHook = false; michael@0: UINT nsWindow::sRollupMsgId = 0; michael@0: HWND nsWindow::sRollupMsgWnd = nullptr; michael@0: UINT nsWindow::sHookTimerId = 0; michael@0: michael@0: // Mouse Clicks - static variable definitions for figuring michael@0: // out 1 - 3 Clicks. michael@0: POINT nsWindow::sLastMousePoint = {0}; michael@0: POINT nsWindow::sLastMouseMovePoint = {0}; michael@0: LONG nsWindow::sLastMouseDownTime = 0L; michael@0: LONG nsWindow::sLastClickCount = 0L; michael@0: BYTE nsWindow::sLastMouseButton = 0; michael@0: michael@0: // Trim heap on minimize. (initialized, but still true.) michael@0: int nsWindow::sTrimOnMinimize = 2; michael@0: michael@0: // Default value for general window class (used when the pref is the empty string). michael@0: const char* nsWindow::sDefaultMainWindowClass = kClassNameGeneral; michael@0: michael@0: // If we're using D3D9, this will not be allowed during initial 5 seconds. michael@0: bool nsWindow::sAllowD3D9 = false; michael@0: michael@0: TriStateBool nsWindow::sHasBogusPopupsDropShadowOnMultiMonitor = TRI_UNKNOWN; michael@0: michael@0: // Used in OOPP plugin focus processing. michael@0: const wchar_t* kOOPPPluginFocusEventId = L"OOPP Plugin Focus Widget Event"; michael@0: uint32_t nsWindow::sOOPPPluginFocusEvent = michael@0: RegisterWindowMessageW(kOOPPPluginFocusEventId); michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: globals variables michael@0: * michael@0: **************************************************************/ michael@0: michael@0: static const char *sScreenManagerContractID = "@mozilla.org/gfx/screenmanager;1"; michael@0: michael@0: #ifdef PR_LOGGING michael@0: extern PRLogModuleInfo* gWindowsLog; michael@0: #endif michael@0: michael@0: // Global used in Show window enumerations. michael@0: static bool gWindowsVisible = false; michael@0: michael@0: // True if we have sent a notification that we are suspending/sleeping. michael@0: static bool gIsSleepMode = false; michael@0: michael@0: static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID); michael@0: michael@0: // General purpose user32.dll hook object michael@0: static WindowsDllInterceptor sUser32Intercept; michael@0: michael@0: // 2 pixel offset for eTransparencyBorderlessGlass which equals the size of michael@0: // the default window border Windows paints. Glass will be extended inward michael@0: // this distance to remove the border. michael@0: static const int32_t kGlassMarginAdjustment = 2; michael@0: michael@0: // When the client area is extended out into the default window frame area, michael@0: // this is the minimum amount of space along the edge of resizable windows michael@0: // we will always display a resize cursor in, regardless of the underlying michael@0: // content. michael@0: static const int32_t kResizableBorderMinSize = 3; michael@0: michael@0: // Cached pointer events enabler value, True if pointer events are enabled. michael@0: static bool gIsPointerEventsEnabled = false; michael@0: michael@0: // We should never really try to accelerate windows bigger than this. In some michael@0: // cases this might lead to no D3D9 acceleration where we could have had it michael@0: // but D3D9 does not reliably report when it supports bigger windows. 8192 michael@0: // is as safe as we can get, we know at least D3D10 hardware always supports michael@0: // this, other hardware we expect to report correctly in D3D9. michael@0: #define MAX_ACCELERATED_DIMENSION 8192 michael@0: michael@0: // On window open (as well as after), Windows has an unfortunate habit of michael@0: // sending rather a lot of WM_NCHITTEST messages. Because we have to do point michael@0: // to DOM target conversions for these, we cache responses for a given michael@0: // coordinate this many milliseconds: michael@0: #define HITTEST_CACHE_LIFETIME_MS 50 michael@0: michael@0: michael@0: /************************************************************** michael@0: ************************************************************** michael@0: ** michael@0: ** BLOCK: nsIWidget impl. michael@0: ** michael@0: ** nsIWidget interface implementation, broken down into michael@0: ** sections. michael@0: ** michael@0: ************************************************************** michael@0: **************************************************************/ michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: nsWindow construction and destruction michael@0: * michael@0: **************************************************************/ michael@0: michael@0: nsWindow::nsWindow() : nsWindowBase() michael@0: { michael@0: mIconSmall = nullptr; michael@0: mIconBig = nullptr; michael@0: mWnd = nullptr; michael@0: mPaintDC = nullptr; michael@0: mCompositeDC = nullptr; michael@0: mPrevWndProc = nullptr; michael@0: mNativeDragTarget = nullptr; michael@0: mInDtor = false; michael@0: mIsVisible = false; michael@0: mIsTopWidgetWindow = false; michael@0: mUnicodeWidget = true; michael@0: mDisplayPanFeedback = false; michael@0: mTouchWindow = false; michael@0: mCustomNonClient = false; michael@0: mHideChrome = false; michael@0: mFullscreenMode = false; michael@0: mMousePresent = false; michael@0: mDestroyCalled = false; michael@0: mHasTaskbarIconBeenCreated = false; michael@0: mMouseTransparent = false; michael@0: mPickerDisplayCount = 0; michael@0: mWindowType = eWindowType_child; michael@0: mBorderStyle = eBorderStyle_default; michael@0: mOldSizeMode = nsSizeMode_Normal; michael@0: mLastSizeMode = nsSizeMode_Normal; michael@0: mLastSize.width = 0; michael@0: mLastSize.height = 0; michael@0: mOldStyle = 0; michael@0: mOldExStyle = 0; michael@0: mPainting = 0; michael@0: mLastKeyboardLayout = 0; michael@0: mBlurSuppressLevel = 0; michael@0: mLastPaintEndTime = TimeStamp::Now(); michael@0: mCachedHitTestPoint.x = 0; michael@0: mCachedHitTestPoint.y = 0; michael@0: mCachedHitTestTime = TimeStamp::Now(); michael@0: mCachedHitTestResult = 0; michael@0: #ifdef MOZ_XUL michael@0: mTransparentSurface = nullptr; michael@0: mMemoryDC = nullptr; michael@0: mTransparencyMode = eTransparencyOpaque; michael@0: memset(&mGlassMargins, 0, sizeof mGlassMargins); michael@0: #endif michael@0: DWORD background = ::GetSysColor(COLOR_BTNFACE); michael@0: mBrush = ::CreateSolidBrush(NSRGB_2_COLOREF(background)); michael@0: michael@0: mTaskbarPreview = nullptr; michael@0: michael@0: // Global initialization michael@0: if (!sInstanceCount) { michael@0: // Global app registration id for Win7 and up. See michael@0: // WinTaskbar.cpp for details. michael@0: mozilla::widget::WinTaskbar::RegisterAppUserModelID(); michael@0: KeyboardLayout::GetInstance()->OnLayoutChange(::GetKeyboardLayout(0)); michael@0: IMEHandler::Initialize(); michael@0: if (SUCCEEDED(::OleInitialize(nullptr))) { michael@0: sIsOleInitialized = TRUE; michael@0: } michael@0: NS_ASSERTION(sIsOleInitialized, "***** OLE is not initialized!\n"); michael@0: MouseScrollHandler::Initialize(); michael@0: // Init titlebar button info for custom frames. michael@0: nsUXThemeData::InitTitlebarInfo(); michael@0: // Init theme data michael@0: nsUXThemeData::UpdateNativeThemeInfo(); michael@0: RedirectedKeyDownMessageManager::Forget(); michael@0: michael@0: Preferences::AddBoolVarCache(&gIsPointerEventsEnabled, michael@0: "dom.w3c_pointer_events.enabled", michael@0: gIsPointerEventsEnabled); michael@0: } // !sInstanceCount michael@0: michael@0: mIdleService = nullptr; michael@0: michael@0: sInstanceCount++; michael@0: } michael@0: michael@0: nsWindow::~nsWindow() michael@0: { michael@0: mInDtor = true; michael@0: michael@0: // If the widget was released without calling Destroy() then the native window still michael@0: // exists, and we need to destroy it. This will also result in a call to OnDestroy. michael@0: // michael@0: // XXX How could this happen??? michael@0: if (nullptr != mWnd) michael@0: Destroy(); michael@0: michael@0: // Free app icon resources. This must happen after `OnDestroy` (see bug 708033). michael@0: if (mIconSmall) michael@0: ::DestroyIcon(mIconSmall); michael@0: michael@0: if (mIconBig) michael@0: ::DestroyIcon(mIconBig); michael@0: michael@0: sInstanceCount--; michael@0: michael@0: // Global shutdown michael@0: if (sInstanceCount == 0) { michael@0: IMEHandler::Terminate(); michael@0: NS_IF_RELEASE(sCursorImgContainer); michael@0: if (sIsOleInitialized) { michael@0: ::OleFlushClipboard(); michael@0: ::OleUninitialize(); michael@0: sIsOleInitialized = FALSE; michael@0: } michael@0: } michael@0: michael@0: NS_IF_RELEASE(mNativeDragTarget); michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS_INHERITED0(nsWindow, nsBaseWidget) michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: nsIWidget::Create, nsIWidget::Destroy michael@0: * michael@0: * Creating and destroying windows for this widget. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: // Allow Derived classes to modify the height that is passed michael@0: // when the window is created or resized. michael@0: int32_t nsWindow::GetHeight(int32_t aProposedHeight) michael@0: { michael@0: return aProposedHeight; michael@0: } michael@0: michael@0: // Create the proper widget michael@0: nsresult michael@0: nsWindow::Create(nsIWidget *aParent, michael@0: nsNativeWidget aNativeParent, michael@0: const nsIntRect &aRect, michael@0: nsDeviceContext *aContext, michael@0: nsWidgetInitData *aInitData) michael@0: { michael@0: nsWidgetInitData defaultInitData; michael@0: if (!aInitData) michael@0: aInitData = &defaultInitData; michael@0: michael@0: mUnicodeWidget = aInitData->mUnicode; michael@0: michael@0: nsIWidget *baseParent = aInitData->mWindowType == eWindowType_dialog || michael@0: aInitData->mWindowType == eWindowType_toplevel || michael@0: aInitData->mWindowType == eWindowType_invisible ? michael@0: nullptr : aParent; michael@0: michael@0: mIsTopWidgetWindow = (nullptr == baseParent); michael@0: mBounds = aRect; michael@0: michael@0: // Ensure that the toolkit is created. michael@0: nsToolkit::GetToolkit(); michael@0: michael@0: BaseCreate(baseParent, aRect, aContext, aInitData); michael@0: michael@0: HWND parent; michael@0: if (aParent) { // has a nsIWidget parent michael@0: parent = aParent ? (HWND)aParent->GetNativeData(NS_NATIVE_WINDOW) : nullptr; michael@0: mParent = aParent; michael@0: } else { // has a nsNative parent michael@0: parent = (HWND)aNativeParent; michael@0: mParent = aNativeParent ? michael@0: WinUtils::GetNSWindowPtr((HWND)aNativeParent) : nullptr; michael@0: } michael@0: michael@0: mIsRTL = aInitData->mRTL; michael@0: michael@0: DWORD style = WindowStyle(); michael@0: DWORD extendedStyle = WindowExStyle(); michael@0: michael@0: if (mWindowType == eWindowType_popup) { michael@0: if (!aParent) { michael@0: parent = nullptr; michael@0: } michael@0: michael@0: if (IsVistaOrLater() && !IsWin8OrLater() && michael@0: HasBogusPopupsDropShadowOnMultiMonitor()) { michael@0: extendedStyle |= WS_EX_COMPOSITED; michael@0: } michael@0: michael@0: if (aInitData->mMouseTransparent) { michael@0: // This flag makes the window transparent to mouse events michael@0: mMouseTransparent = true; michael@0: extendedStyle |= WS_EX_TRANSPARENT; michael@0: } michael@0: } else if (mWindowType == eWindowType_invisible) { michael@0: // Make sure CreateWindowEx succeeds at creating a toplevel window michael@0: style &= ~0x40000000; // WS_CHILDWINDOW michael@0: } else { michael@0: // See if the caller wants to explictly set clip children and clip siblings michael@0: if (aInitData->clipChildren) { michael@0: style |= WS_CLIPCHILDREN; michael@0: } else { michael@0: style &= ~WS_CLIPCHILDREN; michael@0: } michael@0: if (aInitData->clipSiblings) { michael@0: style |= WS_CLIPSIBLINGS; michael@0: } michael@0: } michael@0: michael@0: nsAutoString className; michael@0: if (aInitData->mDropShadow) { michael@0: GetWindowPopupClass(className); michael@0: } else { michael@0: GetWindowClass(className); michael@0: } michael@0: // Plugins are created in the disabled state so that they can't michael@0: // steal focus away from our main window. This is especially michael@0: // important if the plugin has loaded in a background tab. michael@0: if(aInitData->mWindowType == eWindowType_plugin) { michael@0: style |= WS_DISABLED; michael@0: } michael@0: mWnd = ::CreateWindowExW(extendedStyle, michael@0: className.get(), michael@0: L"", michael@0: style, michael@0: aRect.x, michael@0: aRect.y, michael@0: aRect.width, michael@0: GetHeight(aRect.height), michael@0: parent, michael@0: nullptr, michael@0: nsToolkit::mDllInstance, michael@0: nullptr); michael@0: michael@0: if (!mWnd) { michael@0: NS_WARNING("nsWindow CreateWindowEx failed."); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: if (mIsRTL && WinUtils::dwmSetWindowAttributePtr) { michael@0: DWORD dwAttribute = TRUE; michael@0: WinUtils::dwmSetWindowAttributePtr(mWnd, DWMWA_NONCLIENT_RTL_LAYOUT, &dwAttribute, sizeof dwAttribute); michael@0: } michael@0: michael@0: if (mWindowType != eWindowType_plugin && michael@0: mWindowType != eWindowType_invisible && michael@0: MouseScrollHandler::Device::IsFakeScrollableWindowNeeded()) { michael@0: // Ugly Thinkpad Driver Hack (Bugs 507222 and 594977) michael@0: // michael@0: // We create two zero-sized windows as descendants of the top-level window, michael@0: // like so: michael@0: // michael@0: // Top-level window (MozillaWindowClass) michael@0: // FAKETRACKPOINTSCROLLCONTAINER (MozillaWindowClass) michael@0: // FAKETRACKPOINTSCROLLABLE (MozillaWindowClass) michael@0: // michael@0: // We need to have the middle window, otherwise the Trackpoint driver michael@0: // will fail to deliver scroll messages. WM_MOUSEWHEEL messages are michael@0: // sent to the FAKETRACKPOINTSCROLLABLE, which then propagate up the michael@0: // window hierarchy until they are handled by nsWindow::WindowProc. michael@0: // WM_HSCROLL messages are also sent to the FAKETRACKPOINTSCROLLABLE, michael@0: // but these do not propagate automatically, so we have the window michael@0: // procedure pretend that they were dispatched to the top-level window michael@0: // instead. michael@0: // michael@0: // The FAKETRACKPOINTSCROLLABLE needs to have the specific window styles it michael@0: // is given below so that it catches the Trackpoint driver's heuristics. michael@0: HWND scrollContainerWnd = ::CreateWindowW michael@0: (className.get(), L"FAKETRACKPOINTSCROLLCONTAINER", michael@0: WS_CHILD | WS_VISIBLE, michael@0: 0, 0, 0, 0, mWnd, nullptr, nsToolkit::mDllInstance, nullptr); michael@0: HWND scrollableWnd = ::CreateWindowW michael@0: (className.get(), L"FAKETRACKPOINTSCROLLABLE", michael@0: WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP | 0x30, michael@0: 0, 0, 0, 0, scrollContainerWnd, nullptr, nsToolkit::mDllInstance, michael@0: nullptr); michael@0: michael@0: // Give the FAKETRACKPOINTSCROLLABLE window a specific ID so that michael@0: // WindowProcInternal can distinguish it from the top-level window michael@0: // easily. michael@0: ::SetWindowLongPtrW(scrollableWnd, GWLP_ID, eFakeTrackPointScrollableID); michael@0: michael@0: // Make FAKETRACKPOINTSCROLLABLE use nsWindow::WindowProc, and store the michael@0: // old window procedure in its "user data". michael@0: WNDPROC oldWndProc; michael@0: if (mUnicodeWidget) michael@0: oldWndProc = (WNDPROC)::SetWindowLongPtrW(scrollableWnd, GWLP_WNDPROC, michael@0: (LONG_PTR)nsWindow::WindowProc); michael@0: else michael@0: oldWndProc = (WNDPROC)::SetWindowLongPtrA(scrollableWnd, GWLP_WNDPROC, michael@0: (LONG_PTR)nsWindow::WindowProc); michael@0: ::SetWindowLongPtrW(scrollableWnd, GWLP_USERDATA, (LONG_PTR)oldWndProc); michael@0: } michael@0: michael@0: SubclassWindow(TRUE); michael@0: michael@0: IMEHandler::InitInputContext(this, mInputContext); michael@0: michael@0: // If the internal variable set by the config.trim_on_minimize pref has not michael@0: // been initialized, and if this is the hidden window (conveniently created michael@0: // before any visible windows, and after the profile has been initialized), michael@0: // do some initialization work. michael@0: if (sTrimOnMinimize == 2 && mWindowType == eWindowType_invisible) { michael@0: // Our internal trim prevention logic is effective on 2K/XP at maintaining michael@0: // the working set when windows are minimized, but on Vista and up it has michael@0: // little to no effect. Since this feature has been the source of numerous michael@0: // bugs over the years, disable it (sTrimOnMinimize=1) on Vista and up. michael@0: sTrimOnMinimize = michael@0: Preferences::GetBool("config.trim_on_minimize", michael@0: IsVistaOrLater() ? 1 : 0); michael@0: sSwitchKeyboardLayout = michael@0: Preferences::GetBool("intl.keyboard.per_window_layout", false); michael@0: } michael@0: michael@0: // Query for command button metric data for rendering the titlebar. We michael@0: // only do this once on the first window. michael@0: if (mWindowType == eWindowType_toplevel && michael@0: (!nsUXThemeData::sTitlebarInfoPopulatedThemed || michael@0: !nsUXThemeData::sTitlebarInfoPopulatedAero)) { michael@0: nsUXThemeData::UpdateTitlebarInfo(mWnd); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Close this nsWindow michael@0: NS_METHOD nsWindow::Destroy() michael@0: { michael@0: // WM_DESTROY has already fired, avoid calling it twice michael@0: if (mOnDestroyCalled) michael@0: return NS_OK; michael@0: michael@0: // Don't destroy windows that have file pickers open, we'll tear these down michael@0: // later once the picker is closed. michael@0: mDestroyCalled = true; michael@0: if (mPickerDisplayCount) michael@0: return NS_OK; michael@0: michael@0: // During the destruction of all of our children, make sure we don't get deleted. michael@0: nsCOMPtr kungFuDeathGrip(this); michael@0: michael@0: /** michael@0: * On windows the LayerManagerOGL destructor wants the widget to be around for michael@0: * cleanup. It also would like to have the HWND intact, so we nullptr it here. michael@0: */ michael@0: if (mLayerManager) { michael@0: mLayerManager->Destroy(); michael@0: } michael@0: mLayerManager = nullptr; michael@0: michael@0: /* We should clear our cached resources now and not wait for the GC to michael@0: * delete the nsWindow. */ michael@0: ClearCachedResources(); michael@0: michael@0: // The DestroyWindow function destroys the specified window. The function sends WM_DESTROY michael@0: // and WM_NCDESTROY messages to the window to deactivate it and remove the keyboard focus michael@0: // from it. The function also destroys the window's menu, flushes the thread message queue, michael@0: // destroys timers, removes clipboard ownership, and breaks the clipboard viewer chain (if michael@0: // the window is at the top of the viewer chain). michael@0: // michael@0: // If the specified window is a parent or owner window, DestroyWindow automatically destroys michael@0: // the associated child or owned windows when it destroys the parent or owner window. The michael@0: // function first destroys child or owned windows, and then it destroys the parent or owner michael@0: // window. michael@0: VERIFY(::DestroyWindow(mWnd)); michael@0: michael@0: // Our windows can be subclassed which may prevent us receiving WM_DESTROY. If OnDestroy() michael@0: // didn't get called, call it now. michael@0: if (false == mOnDestroyCalled) { michael@0: MSGResult msgResult; michael@0: mWindowHook.Notify(mWnd, WM_DESTROY, 0, 0, msgResult); michael@0: OnDestroy(); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: Window class utilities michael@0: * michael@0: * Utilities for calculating the proper window class name for michael@0: * Create window. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: void nsWindow::RegisterWindowClass(const nsString& aClassName, UINT aExtraStyle, michael@0: LPWSTR aIconID) michael@0: { michael@0: WNDCLASSW wc; michael@0: if (::GetClassInfoW(nsToolkit::mDllInstance, aClassName.get(), &wc)) { michael@0: // already registered michael@0: return; michael@0: } michael@0: michael@0: wc.style = CS_DBLCLKS | aExtraStyle; michael@0: wc.lpfnWndProc = ::DefWindowProcW; michael@0: wc.cbClsExtra = 0; michael@0: wc.cbWndExtra = 0; michael@0: wc.hInstance = nsToolkit::mDllInstance; michael@0: wc.hIcon = aIconID ? ::LoadIconW(::GetModuleHandleW(nullptr), aIconID) : nullptr; michael@0: wc.hCursor = nullptr; michael@0: wc.hbrBackground = mBrush; michael@0: wc.lpszMenuName = nullptr; michael@0: wc.lpszClassName = aClassName.get(); michael@0: michael@0: if (!::RegisterClassW(&wc)) { michael@0: // For older versions of Win32 (i.e., not XP), the registration may michael@0: // fail with aExtraStyle, so we have to re-register without it. michael@0: wc.style = CS_DBLCLKS; michael@0: ::RegisterClassW(&wc); michael@0: } michael@0: } michael@0: michael@0: static LPWSTR const gStockApplicationIcon = MAKEINTRESOURCEW(32512); michael@0: michael@0: // Return the proper window class for everything except popups. michael@0: void nsWindow::GetWindowClass(nsString& aWindowClass) michael@0: { michael@0: switch (mWindowType) { michael@0: case eWindowType_invisible: michael@0: aWindowClass.AssignLiteral(kClassNameHidden); michael@0: RegisterWindowClass(aWindowClass, 0, gStockApplicationIcon); michael@0: break; michael@0: case eWindowType_dialog: michael@0: aWindowClass.AssignLiteral(kClassNameDialog); michael@0: RegisterWindowClass(aWindowClass, 0, 0); michael@0: break; michael@0: default: michael@0: GetMainWindowClass(aWindowClass); michael@0: RegisterWindowClass(aWindowClass, 0, gStockApplicationIcon); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: // Return the proper popup window class michael@0: void nsWindow::GetWindowPopupClass(nsString& aWindowClass) michael@0: { michael@0: aWindowClass.AssignLiteral(kClassNameDropShadow); michael@0: RegisterWindowClass(aWindowClass, CS_XP_DROPSHADOW, gStockApplicationIcon); michael@0: } michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: Window styles utilities michael@0: * michael@0: * Return the proper windows styles and extended styles. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: // Return nsWindow styles michael@0: DWORD nsWindow::WindowStyle() michael@0: { michael@0: DWORD style; michael@0: michael@0: switch (mWindowType) { michael@0: case eWindowType_plugin: michael@0: case eWindowType_child: michael@0: style = WS_OVERLAPPED; michael@0: break; michael@0: michael@0: case eWindowType_dialog: michael@0: style = WS_OVERLAPPED | WS_BORDER | WS_DLGFRAME | WS_SYSMENU | DS_3DLOOK | michael@0: DS_MODALFRAME | WS_CLIPCHILDREN; michael@0: if (mBorderStyle != eBorderStyle_default) michael@0: style |= WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX; michael@0: break; michael@0: michael@0: case eWindowType_popup: michael@0: style = WS_POPUP; michael@0: if (!HasGlass()) { michael@0: style |= WS_OVERLAPPED; michael@0: } michael@0: break; michael@0: michael@0: default: michael@0: NS_ERROR("unknown border style"); michael@0: // fall through michael@0: michael@0: case eWindowType_toplevel: michael@0: case eWindowType_invisible: michael@0: style = WS_OVERLAPPED | WS_BORDER | WS_DLGFRAME | WS_SYSMENU | michael@0: WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPCHILDREN; michael@0: break; michael@0: } michael@0: michael@0: if (mBorderStyle != eBorderStyle_default && mBorderStyle != eBorderStyle_all) { michael@0: if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_border)) michael@0: style &= ~WS_BORDER; michael@0: michael@0: if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_title)) { michael@0: style &= ~WS_DLGFRAME; michael@0: style |= WS_POPUP; michael@0: style &= ~WS_CHILD; michael@0: } michael@0: michael@0: if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_close)) michael@0: style &= ~0; michael@0: // XXX The close box can only be removed by changing the window class, michael@0: // as far as I know --- roc+moz@cs.cmu.edu michael@0: michael@0: if (mBorderStyle == eBorderStyle_none || michael@0: !(mBorderStyle & (eBorderStyle_menu | eBorderStyle_close))) michael@0: style &= ~WS_SYSMENU; michael@0: // Looks like getting rid of the system menu also does away with the michael@0: // close box. So, we only get rid of the system menu if you want neither it michael@0: // nor the close box. How does the Windows "Dialog" window class get just michael@0: // closebox and no sysmenu? Who knows. michael@0: michael@0: if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_resizeh)) michael@0: style &= ~WS_THICKFRAME; michael@0: michael@0: if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_minimize)) michael@0: style &= ~WS_MINIMIZEBOX; michael@0: michael@0: if (mBorderStyle == eBorderStyle_none || !(mBorderStyle & eBorderStyle_maximize)) michael@0: style &= ~WS_MAXIMIZEBOX; michael@0: michael@0: if (IsPopupWithTitleBar()) { michael@0: style |= WS_CAPTION; michael@0: if (mBorderStyle & eBorderStyle_close) { michael@0: style |= WS_SYSMENU; michael@0: } michael@0: } michael@0: } michael@0: michael@0: VERIFY_WINDOW_STYLE(style); michael@0: return style; michael@0: } michael@0: michael@0: // Return nsWindow extended styles michael@0: DWORD nsWindow::WindowExStyle() michael@0: { michael@0: switch (mWindowType) michael@0: { michael@0: case eWindowType_plugin: michael@0: case eWindowType_child: michael@0: return 0; michael@0: michael@0: case eWindowType_dialog: michael@0: return WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME; michael@0: michael@0: case eWindowType_popup: michael@0: { michael@0: DWORD extendedStyle = WS_EX_TOOLWINDOW; michael@0: if (mPopupLevel == ePopupLevelTop) michael@0: extendedStyle |= WS_EX_TOPMOST; michael@0: return extendedStyle; michael@0: } michael@0: default: michael@0: NS_ERROR("unknown border style"); michael@0: // fall through michael@0: michael@0: case eWindowType_toplevel: michael@0: case eWindowType_invisible: michael@0: return WS_EX_WINDOWEDGE; michael@0: } michael@0: } michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: Window subclassing utilities michael@0: * michael@0: * Set or clear window subclasses on native windows. Used in michael@0: * Create and Destroy. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: // Subclass (or remove the subclass from) this component's nsWindow michael@0: void nsWindow::SubclassWindow(BOOL bState) michael@0: { michael@0: if (bState) { michael@0: if (!mWnd || !IsWindow(mWnd)) { michael@0: NS_ERROR("Invalid window handle"); michael@0: } michael@0: michael@0: if (mUnicodeWidget) { michael@0: mPrevWndProc = michael@0: reinterpret_cast( michael@0: SetWindowLongPtrW(mWnd, michael@0: GWLP_WNDPROC, michael@0: reinterpret_cast(nsWindow::WindowProc))); michael@0: } else { michael@0: mPrevWndProc = michael@0: reinterpret_cast( michael@0: SetWindowLongPtrA(mWnd, michael@0: GWLP_WNDPROC, michael@0: reinterpret_cast(nsWindow::WindowProc))); michael@0: } michael@0: NS_ASSERTION(mPrevWndProc, "Null standard window procedure"); michael@0: // connect the this pointer to the nsWindow handle michael@0: WinUtils::SetNSWindowBasePtr(mWnd, this); michael@0: } else { michael@0: if (IsWindow(mWnd)) { michael@0: if (mUnicodeWidget) { michael@0: SetWindowLongPtrW(mWnd, michael@0: GWLP_WNDPROC, michael@0: reinterpret_cast(mPrevWndProc)); michael@0: } else { michael@0: SetWindowLongPtrA(mWnd, michael@0: GWLP_WNDPROC, michael@0: reinterpret_cast(mPrevWndProc)); michael@0: } michael@0: } michael@0: WinUtils::SetNSWindowBasePtr(mWnd, nullptr); michael@0: mPrevWndProc = nullptr; michael@0: } michael@0: } michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: nsIWidget::SetParent, nsIWidget::GetParent michael@0: * michael@0: * Set or clear the parent widgets using window properties, and michael@0: * handles calculating native parent handles. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: // Get and set parent widgets michael@0: NS_IMETHODIMP nsWindow::SetParent(nsIWidget *aNewParent) michael@0: { michael@0: mParent = aNewParent; michael@0: michael@0: nsCOMPtr kungFuDeathGrip(this); michael@0: nsIWidget* parent = GetParent(); michael@0: if (parent) { michael@0: parent->RemoveChild(this); michael@0: } michael@0: if (aNewParent) { michael@0: ReparentNativeWidget(aNewParent); michael@0: aNewParent->AddChild(this); michael@0: return NS_OK; michael@0: } michael@0: if (mWnd) { michael@0: // If we have no parent, SetParent should return the desktop. michael@0: VERIFY(::SetParent(mWnd, nullptr)); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::ReparentNativeWidget(nsIWidget* aNewParent) michael@0: { michael@0: NS_PRECONDITION(aNewParent, ""); michael@0: michael@0: mParent = aNewParent; michael@0: if (mWindowType == eWindowType_popup) { michael@0: return NS_OK; michael@0: } michael@0: HWND newParent = (HWND)aNewParent->GetNativeData(NS_NATIVE_WINDOW); michael@0: NS_ASSERTION(newParent, "Parent widget has a null native window handle"); michael@0: if (newParent && mWnd) { michael@0: ::SetParent(mWnd, newParent); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsIWidget* nsWindow::GetParent(void) michael@0: { michael@0: return GetParentWindow(false); michael@0: } michael@0: michael@0: float nsWindow::GetDPI() michael@0: { michael@0: HDC dc = ::GetDC(mWnd); michael@0: if (!dc) michael@0: return 96.0f; michael@0: michael@0: double heightInches = ::GetDeviceCaps(dc, VERTSIZE)/MM_PER_INCH_FLOAT; michael@0: int heightPx = ::GetDeviceCaps(dc, VERTRES); michael@0: ::ReleaseDC(mWnd, dc); michael@0: if (heightInches < 0.25) { michael@0: // Something's broken michael@0: return 96.0f; michael@0: } michael@0: return float(heightPx/heightInches); michael@0: } michael@0: michael@0: double nsWindow::GetDefaultScaleInternal() michael@0: { michael@0: return WinUtils::LogToPhysFactor(); michael@0: } michael@0: michael@0: nsWindow* michael@0: nsWindow::GetParentWindow(bool aIncludeOwner) michael@0: { michael@0: return static_cast(GetParentWindowBase(aIncludeOwner)); michael@0: } michael@0: michael@0: nsWindowBase* michael@0: nsWindow::GetParentWindowBase(bool aIncludeOwner) michael@0: { michael@0: if (mIsTopWidgetWindow) { michael@0: // Must use a flag instead of mWindowType to tell if the window is the michael@0: // owned by the topmost widget, because a child window can be embedded inside michael@0: // a HWND which is not associated with a nsIWidget. michael@0: return nullptr; michael@0: } michael@0: michael@0: // If this widget has already been destroyed, pretend we have no parent. michael@0: // This corresponds to code in Destroy which removes the destroyed michael@0: // widget from its parent's child list. michael@0: if (mInDtor || mOnDestroyCalled) michael@0: return nullptr; michael@0: michael@0: michael@0: // aIncludeOwner set to true implies walking the parent chain to retrieve the michael@0: // root owner. aIncludeOwner set to false implies the search will stop at the michael@0: // true parent (default). michael@0: nsWindow* widget = nullptr; michael@0: if (mWnd) { michael@0: HWND parent = nullptr; michael@0: if (aIncludeOwner) michael@0: parent = ::GetParent(mWnd); michael@0: else michael@0: parent = ::GetAncestor(mWnd, GA_PARENT); michael@0: michael@0: if (parent) { michael@0: widget = WinUtils::GetNSWindowPtr(parent); michael@0: if (widget) { michael@0: // If the widget is in the process of being destroyed then michael@0: // do NOT return it michael@0: if (widget->mInDtor) { michael@0: widget = nullptr; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: return static_cast(widget); michael@0: } michael@0: michael@0: BOOL CALLBACK michael@0: nsWindow::EnumAllChildWindProc(HWND aWnd, LPARAM aParam) michael@0: { michael@0: nsWindow *wnd = WinUtils::GetNSWindowPtr(aWnd); michael@0: if (wnd) { michael@0: ((nsWindow::WindowEnumCallback*)aParam)(wnd); michael@0: } michael@0: return TRUE; michael@0: } michael@0: michael@0: BOOL CALLBACK michael@0: nsWindow::EnumAllThreadWindowProc(HWND aWnd, LPARAM aParam) michael@0: { michael@0: nsWindow *wnd = WinUtils::GetNSWindowPtr(aWnd); michael@0: if (wnd) { michael@0: ((nsWindow::WindowEnumCallback*)aParam)(wnd); michael@0: } michael@0: EnumChildWindows(aWnd, EnumAllChildWindProc, aParam); michael@0: return TRUE; michael@0: } michael@0: michael@0: void michael@0: nsWindow::EnumAllWindows(WindowEnumCallback aCallback) michael@0: { michael@0: EnumThreadWindows(GetCurrentThreadId(), michael@0: EnumAllThreadWindowProc, michael@0: (LPARAM)aCallback); michael@0: } michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: nsIWidget::Show michael@0: * michael@0: * Hide or show this component. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: NS_METHOD nsWindow::Show(bool bState) michael@0: { michael@0: if (mWindowType == eWindowType_popup) { michael@0: // See bug 603793. When we try to draw D3D9/10 windows with a drop shadow michael@0: // without the DWM on a secondary monitor, windows fails to composite michael@0: // our windows correctly. We therefor switch off the drop shadow for michael@0: // pop-up windows when the DWM is disabled and two monitors are michael@0: // connected. michael@0: if (HasBogusPopupsDropShadowOnMultiMonitor() && michael@0: WinUtils::GetMonitorCount() > 1 && michael@0: !nsUXThemeData::CheckForCompositor()) michael@0: { michael@0: if (sDropShadowEnabled) { michael@0: ::SetClassLongA(mWnd, GCL_STYLE, 0); michael@0: sDropShadowEnabled = false; michael@0: } michael@0: } else { michael@0: if (!sDropShadowEnabled) { michael@0: ::SetClassLongA(mWnd, GCL_STYLE, CS_DROPSHADOW); michael@0: sDropShadowEnabled = true; michael@0: } michael@0: } michael@0: michael@0: // WS_EX_COMPOSITED conflicts with the WS_EX_LAYERED style and causes michael@0: // some popup menus to become invisible. michael@0: LONG_PTR exStyle = ::GetWindowLongPtrW(mWnd, GWL_EXSTYLE); michael@0: if (exStyle & WS_EX_LAYERED) { michael@0: ::SetWindowLongPtrW(mWnd, GWL_EXSTYLE, exStyle & ~WS_EX_COMPOSITED); michael@0: } michael@0: } michael@0: michael@0: bool syncInvalidate = false; michael@0: michael@0: bool wasVisible = mIsVisible; michael@0: // Set the status now so that anyone asking during ShowWindow or michael@0: // SetWindowPos would get the correct answer. michael@0: mIsVisible = bState; michael@0: michael@0: // We may have cached an out of date visible state. This can happen michael@0: // when session restore sets the full screen mode. michael@0: if (mIsVisible) michael@0: mOldStyle |= WS_VISIBLE; michael@0: else michael@0: mOldStyle &= ~WS_VISIBLE; michael@0: michael@0: if (!mIsVisible && wasVisible) { michael@0: ClearCachedResources(); michael@0: } michael@0: michael@0: if (mWnd) { michael@0: if (bState) { michael@0: if (!wasVisible && mWindowType == eWindowType_toplevel) { michael@0: // speed up the initial paint after show for michael@0: // top level windows: michael@0: syncInvalidate = true; michael@0: switch (mSizeMode) { michael@0: case nsSizeMode_Fullscreen: michael@0: ::ShowWindow(mWnd, SW_SHOW); michael@0: break; michael@0: case nsSizeMode_Maximized : michael@0: ::ShowWindow(mWnd, SW_SHOWMAXIMIZED); michael@0: break; michael@0: case nsSizeMode_Minimized : michael@0: ::ShowWindow(mWnd, SW_SHOWMINIMIZED); michael@0: break; michael@0: default: michael@0: if (CanTakeFocus()) { michael@0: ::ShowWindow(mWnd, SW_SHOWNORMAL); michael@0: } else { michael@0: // Place the window behind the foreground window michael@0: // (as long as it is not topmost) michael@0: HWND wndAfter = ::GetForegroundWindow(); michael@0: if (!wndAfter) michael@0: wndAfter = HWND_BOTTOM; michael@0: else if (GetWindowLongPtrW(wndAfter, GWL_EXSTYLE) & WS_EX_TOPMOST) michael@0: wndAfter = HWND_TOP; michael@0: ::SetWindowPos(mWnd, wndAfter, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | michael@0: SWP_NOMOVE | SWP_NOACTIVATE); michael@0: GetAttention(2); michael@0: } michael@0: break; michael@0: } michael@0: } else { michael@0: DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW; michael@0: if (wasVisible) michael@0: flags |= SWP_NOZORDER; michael@0: michael@0: if (mWindowType == eWindowType_popup) { michael@0: // ensure popups are the topmost of the TOPMOST michael@0: // layer. Remember not to set the SWP_NOZORDER michael@0: // flag as that might allow the taskbar to overlap michael@0: // the popup. michael@0: flags |= SWP_NOACTIVATE; michael@0: HWND owner = ::GetWindow(mWnd, GW_OWNER); michael@0: ::SetWindowPos(mWnd, owner ? 0 : HWND_TOPMOST, 0, 0, 0, 0, flags); michael@0: } else { michael@0: if (mWindowType == eWindowType_dialog && !CanTakeFocus()) michael@0: flags |= SWP_NOACTIVATE; michael@0: michael@0: ::SetWindowPos(mWnd, HWND_TOP, 0, 0, 0, 0, flags); michael@0: } michael@0: } michael@0: michael@0: if (!wasVisible && (mWindowType == eWindowType_toplevel || mWindowType == eWindowType_dialog)) { michael@0: // when a toplevel window or dialog is shown, initialize the UI state michael@0: ::SendMessageW(mWnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_INITIALIZE, UISF_HIDEFOCUS | UISF_HIDEACCEL), 0); michael@0: } michael@0: } else { michael@0: // Clear contents to avoid ghosting of old content if we display michael@0: // this window again. michael@0: if (wasVisible && mTransparencyMode == eTransparencyTransparent) { michael@0: ClearTranslucentWindow(); michael@0: } michael@0: if (mWindowType != eWindowType_dialog) { michael@0: ::ShowWindow(mWnd, SW_HIDE); michael@0: } else { michael@0: ::SetWindowPos(mWnd, 0, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | michael@0: SWP_NOZORDER | SWP_NOACTIVATE); michael@0: } michael@0: } michael@0: } michael@0: michael@0: #ifdef MOZ_XUL michael@0: if (!wasVisible && bState) { michael@0: Invalidate(); michael@0: if (syncInvalidate && !mInDtor && !mOnDestroyCalled) { michael@0: ::UpdateWindow(mWnd); michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: nsIWidget::IsVisible michael@0: * michael@0: * Returns the visibility state. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: // Return true if the whether the component is visible, false otherwise michael@0: bool nsWindow::IsVisible() const michael@0: { michael@0: return mIsVisible; michael@0: } michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: Window clipping utilities michael@0: * michael@0: * Used in Size and Move operations for setting the proper michael@0: * window clipping regions for window transparency. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: // XP and Vista visual styles sometimes require window clipping regions to be applied for proper michael@0: // transparency. These routines are called on size and move operations. michael@0: void nsWindow::ClearThemeRegion() michael@0: { michael@0: if (IsVistaOrLater() && !HasGlass() && michael@0: (mWindowType == eWindowType_popup && !IsPopupWithTitleBar() && michael@0: (mPopupType == ePopupTypeTooltip || mPopupType == ePopupTypePanel))) { michael@0: SetWindowRgn(mWnd, nullptr, false); michael@0: } michael@0: } michael@0: michael@0: void nsWindow::SetThemeRegion() michael@0: { michael@0: // Popup types that have a visual styles region applied (bug 376408). This can be expanded michael@0: // for other window types as needed. The regions are applied generically to the base window michael@0: // so default constants are used for part and state. At some point we might need part and michael@0: // state values from nsNativeThemeWin's GetThemePartAndState, but currently windows that michael@0: // change shape based on state haven't come up. michael@0: if (IsVistaOrLater() && !HasGlass() && michael@0: (mWindowType == eWindowType_popup && !IsPopupWithTitleBar() && michael@0: (mPopupType == ePopupTypeTooltip || mPopupType == ePopupTypePanel))) { michael@0: HRGN hRgn = nullptr; michael@0: RECT rect = {0,0,mBounds.width,mBounds.height}; michael@0: michael@0: HDC dc = ::GetDC(mWnd); michael@0: GetThemeBackgroundRegion(nsUXThemeData::GetTheme(eUXTooltip), dc, TTP_STANDARD, TS_NORMAL, &rect, &hRgn); michael@0: if (hRgn) { michael@0: if (!SetWindowRgn(mWnd, hRgn, false)) // do not delete or alter hRgn if accepted. michael@0: DeleteObject(hRgn); michael@0: } michael@0: ::ReleaseDC(mWnd, dc); michael@0: } michael@0: } michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: nsIWidget::RegisterTouchWindow, michael@0: * nsIWidget::UnregisterTouchWindow, and helper functions michael@0: * michael@0: * Used to register the native window to receive touch events michael@0: * michael@0: **************************************************************/ michael@0: michael@0: NS_METHOD nsWindow::RegisterTouchWindow() { michael@0: if (Preferences::GetInt("dom.w3c_touch_events.enabled", 0) || michael@0: gIsPointerEventsEnabled) { michael@0: mTouchWindow = true; michael@0: mGesture.RegisterTouchWindow(mWnd); michael@0: ::EnumChildWindows(mWnd, nsWindow::RegisterTouchForDescendants, 0); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_METHOD nsWindow::UnregisterTouchWindow() { michael@0: mTouchWindow = false; michael@0: mGesture.UnregisterTouchWindow(mWnd); michael@0: ::EnumChildWindows(mWnd, nsWindow::UnregisterTouchForDescendants, 0); michael@0: return NS_OK; michael@0: } michael@0: michael@0: BOOL CALLBACK nsWindow::RegisterTouchForDescendants(HWND aWnd, LPARAM aMsg) { michael@0: nsWindow* win = WinUtils::GetNSWindowPtr(aWnd); michael@0: if (win) michael@0: win->mGesture.RegisterTouchWindow(aWnd); michael@0: return TRUE; michael@0: } michael@0: michael@0: BOOL CALLBACK nsWindow::UnregisterTouchForDescendants(HWND aWnd, LPARAM aMsg) { michael@0: nsWindow* win = WinUtils::GetNSWindowPtr(aWnd); michael@0: if (win) michael@0: win->mGesture.UnregisterTouchWindow(aWnd); michael@0: return TRUE; michael@0: } michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: nsIWidget::Move, nsIWidget::Resize, michael@0: * nsIWidget::Size, nsIWidget::BeginResizeDrag michael@0: * michael@0: * Repositioning and sizing a window. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: void michael@0: nsWindow::SetSizeConstraints(const SizeConstraints& aConstraints) michael@0: { michael@0: SizeConstraints c = aConstraints; michael@0: if (mWindowType != eWindowType_popup) { michael@0: c.mMinSize.width = std::max(int32_t(::GetSystemMetrics(SM_CXMINTRACK)), c.mMinSize.width); michael@0: c.mMinSize.height = std::max(int32_t(::GetSystemMetrics(SM_CYMINTRACK)), c.mMinSize.height); michael@0: } michael@0: michael@0: nsBaseWidget::SetSizeConstraints(c); michael@0: } michael@0: michael@0: // Move this component michael@0: NS_METHOD nsWindow::Move(double aX, double aY) michael@0: { michael@0: if (mWindowType == eWindowType_toplevel || michael@0: mWindowType == eWindowType_dialog) { michael@0: SetSizeMode(nsSizeMode_Normal); michael@0: } michael@0: michael@0: // for top-level windows only, convert coordinates from global display pixels michael@0: // (the "parent" coordinate space) to the window's device pixel space michael@0: CSSToLayoutDeviceScale scale = BoundsUseDisplayPixels() ? GetDefaultScale() michael@0: : CSSToLayoutDeviceScale(1.0); michael@0: int32_t x = NSToIntRound(aX * scale.scale); michael@0: int32_t y = NSToIntRound(aY * scale.scale); michael@0: michael@0: // Check to see if window needs to be moved first michael@0: // to avoid a costly call to SetWindowPos. This check michael@0: // can not be moved to the calling code in nsView, because michael@0: // some platforms do not position child windows correctly michael@0: michael@0: // Only perform this check for non-popup windows, since the positioning can michael@0: // in fact change even when the x/y do not. We always need to perform the michael@0: // check. See bug #97805 for details. michael@0: if (mWindowType != eWindowType_popup && (mBounds.x == x) && (mBounds.y == y)) michael@0: { michael@0: // Nothing to do, since it is already positioned correctly. michael@0: return NS_OK; michael@0: } michael@0: michael@0: mBounds.x = x; michael@0: mBounds.y = y; michael@0: michael@0: if (mWnd) { michael@0: #ifdef DEBUG michael@0: // complain if a window is moved offscreen (legal, but potentially worrisome) michael@0: if (mIsTopWidgetWindow) { // only a problem for top-level windows michael@0: // Make sure this window is actually on the screen before we move it michael@0: // XXX: Needs multiple monitor support michael@0: HDC dc = ::GetDC(mWnd); michael@0: if (dc) { michael@0: if (::GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY) { michael@0: RECT workArea; michael@0: ::SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0); michael@0: // no annoying assertions. just mention the issue. michael@0: if (x < 0 || x >= workArea.right || y < 0 || y >= workArea.bottom) { michael@0: PR_LOG(gWindowsLog, PR_LOG_ALWAYS, michael@0: ("window moved to offscreen position\n")); michael@0: } michael@0: } michael@0: ::ReleaseDC(mWnd, dc); michael@0: } michael@0: } michael@0: #endif michael@0: ClearThemeRegion(); michael@0: michael@0: UINT flags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE; michael@0: // Workaround SetWindowPos bug with D3D9. If our window has a clip michael@0: // region, some drivers or OSes may incorrectly copy into the clipped-out michael@0: // area. michael@0: if (mWindowType == eWindowType_plugin && michael@0: (!mLayerManager || mLayerManager->GetBackendType() == LayersBackend::LAYERS_D3D9) && michael@0: mClipRects && michael@0: (mClipRectCount != 1 || !mClipRects[0].IsEqualInterior(nsIntRect(0, 0, mBounds.width, mBounds.height)))) { michael@0: flags |= SWP_NOCOPYBITS; michael@0: } michael@0: VERIFY(::SetWindowPos(mWnd, nullptr, x, y, 0, 0, flags)); michael@0: michael@0: SetThemeRegion(); michael@0: } michael@0: NotifyRollupGeometryChange(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Resize this component michael@0: NS_METHOD nsWindow::Resize(double aWidth, double aHeight, bool aRepaint) michael@0: { michael@0: // for top-level windows only, convert coordinates from global display pixels michael@0: // (the "parent" coordinate space) to the window's device pixel space michael@0: CSSToLayoutDeviceScale scale = BoundsUseDisplayPixels() ? GetDefaultScale() michael@0: : CSSToLayoutDeviceScale(1.0); michael@0: int32_t width = NSToIntRound(aWidth * scale.scale); michael@0: int32_t height = NSToIntRound(aHeight * scale.scale); michael@0: michael@0: NS_ASSERTION((width >= 0) , "Negative width passed to nsWindow::Resize"); michael@0: NS_ASSERTION((height >= 0), "Negative height passed to nsWindow::Resize"); michael@0: michael@0: ConstrainSize(&width, &height); michael@0: michael@0: // Avoid unnecessary resizing calls michael@0: if (mBounds.width == width && mBounds.height == height) { michael@0: if (aRepaint) { michael@0: Invalidate(); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: #ifdef MOZ_XUL michael@0: if (eTransparencyTransparent == mTransparencyMode) michael@0: ResizeTranslucentWindow(width, height); michael@0: #endif michael@0: michael@0: // Set cached value for lightweight and printing michael@0: mBounds.width = width; michael@0: mBounds.height = height; michael@0: michael@0: if (mWnd) { michael@0: UINT flags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE; michael@0: michael@0: if (!aRepaint) { michael@0: flags |= SWP_NOREDRAW; michael@0: } michael@0: michael@0: ClearThemeRegion(); michael@0: VERIFY(::SetWindowPos(mWnd, nullptr, 0, 0, michael@0: width, GetHeight(height), flags)); michael@0: SetThemeRegion(); michael@0: } michael@0: michael@0: if (aRepaint) michael@0: Invalidate(); michael@0: michael@0: NotifyRollupGeometryChange(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Resize this component michael@0: NS_METHOD nsWindow::Resize(double aX, double aY, double aWidth, double aHeight, bool aRepaint) michael@0: { michael@0: // for top-level windows only, convert coordinates from global display pixels michael@0: // (the "parent" coordinate space) to the window's device pixel space michael@0: CSSToLayoutDeviceScale scale = BoundsUseDisplayPixels() ? GetDefaultScale() michael@0: : CSSToLayoutDeviceScale(1.0); michael@0: int32_t x = NSToIntRound(aX * scale.scale); michael@0: int32_t y = NSToIntRound(aY * scale.scale); michael@0: int32_t width = NSToIntRound(aWidth * scale.scale); michael@0: int32_t height = NSToIntRound(aHeight * scale.scale); michael@0: michael@0: NS_ASSERTION((width >= 0), "Negative width passed to nsWindow::Resize"); michael@0: NS_ASSERTION((height >= 0), "Negative height passed to nsWindow::Resize"); michael@0: michael@0: ConstrainSize(&width, &height); michael@0: michael@0: // Avoid unnecessary resizing calls michael@0: if (mBounds.x == x && mBounds.y == y && michael@0: mBounds.width == width && mBounds.height == height) { michael@0: if (aRepaint) { michael@0: Invalidate(); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: #ifdef MOZ_XUL michael@0: if (eTransparencyTransparent == mTransparencyMode) michael@0: ResizeTranslucentWindow(width, height); michael@0: #endif michael@0: michael@0: // Set cached value for lightweight and printing michael@0: mBounds.x = x; michael@0: mBounds.y = y; michael@0: mBounds.width = width; michael@0: mBounds.height = height; michael@0: michael@0: if (mWnd) { michael@0: UINT flags = SWP_NOZORDER | SWP_NOACTIVATE; michael@0: if (!aRepaint) { michael@0: flags |= SWP_NOREDRAW; michael@0: } michael@0: michael@0: ClearThemeRegion(); michael@0: VERIFY(::SetWindowPos(mWnd, nullptr, x, y, michael@0: width, GetHeight(height), flags)); michael@0: SetThemeRegion(); michael@0: } michael@0: michael@0: if (aRepaint) michael@0: Invalidate(); michael@0: michael@0: NotifyRollupGeometryChange(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::BeginResizeDrag(WidgetGUIEvent* aEvent, michael@0: int32_t aHorizontal, michael@0: int32_t aVertical) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aEvent); michael@0: michael@0: if (aEvent->eventStructType != NS_MOUSE_EVENT) { michael@0: // you can only begin a resize drag with a mouse event michael@0: return NS_ERROR_INVALID_ARG; michael@0: } michael@0: michael@0: if (aEvent->AsMouseEvent()->button != WidgetMouseEvent::eLeftButton) { michael@0: // you can only begin a resize drag with the left mouse button michael@0: return NS_ERROR_INVALID_ARG; michael@0: } michael@0: michael@0: // work out what sizemode we're talking about michael@0: WPARAM syscommand; michael@0: if (aVertical < 0) { michael@0: if (aHorizontal < 0) { michael@0: syscommand = SC_SIZE | WMSZ_TOPLEFT; michael@0: } else if (aHorizontal == 0) { michael@0: syscommand = SC_SIZE | WMSZ_TOP; michael@0: } else { michael@0: syscommand = SC_SIZE | WMSZ_TOPRIGHT; michael@0: } michael@0: } else if (aVertical == 0) { michael@0: if (aHorizontal < 0) { michael@0: syscommand = SC_SIZE | WMSZ_LEFT; michael@0: } else if (aHorizontal == 0) { michael@0: return NS_ERROR_INVALID_ARG; michael@0: } else { michael@0: syscommand = SC_SIZE | WMSZ_RIGHT; michael@0: } michael@0: } else { michael@0: if (aHorizontal < 0) { michael@0: syscommand = SC_SIZE | WMSZ_BOTTOMLEFT; michael@0: } else if (aHorizontal == 0) { michael@0: syscommand = SC_SIZE | WMSZ_BOTTOM; michael@0: } else { michael@0: syscommand = SC_SIZE | WMSZ_BOTTOMRIGHT; michael@0: } michael@0: } michael@0: michael@0: // resizing doesn't work if the mouse is already captured michael@0: CaptureMouse(false); michael@0: michael@0: // find the top-level window michael@0: HWND toplevelWnd = WinUtils::GetTopLevelHWND(mWnd, true); michael@0: michael@0: // tell Windows to start the resize michael@0: ::PostMessage(toplevelWnd, WM_SYSCOMMAND, syscommand, michael@0: POINTTOPOINTS(aEvent->refPoint)); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: Window Z-order and state. michael@0: * michael@0: * nsIWidget::PlaceBehind, nsIWidget::SetSizeMode, michael@0: * nsIWidget::ConstrainPosition michael@0: * michael@0: * Z-order, positioning, restore, minimize, and maximize. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: // Position the window behind the given window michael@0: NS_METHOD nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement, michael@0: nsIWidget *aWidget, bool aActivate) michael@0: { michael@0: HWND behind = HWND_TOP; michael@0: if (aPlacement == eZPlacementBottom) michael@0: behind = HWND_BOTTOM; michael@0: else if (aPlacement == eZPlacementBelow && aWidget) michael@0: behind = (HWND)aWidget->GetNativeData(NS_NATIVE_WINDOW); michael@0: UINT flags = SWP_NOMOVE | SWP_NOREPOSITION | SWP_NOSIZE; michael@0: if (!aActivate) michael@0: flags |= SWP_NOACTIVATE; michael@0: michael@0: if (!CanTakeFocus() && behind == HWND_TOP) michael@0: { michael@0: // Can't place the window to top so place it behind the foreground window michael@0: // (as long as it is not topmost) michael@0: HWND wndAfter = ::GetForegroundWindow(); michael@0: if (!wndAfter) michael@0: behind = HWND_BOTTOM; michael@0: else if (!(GetWindowLongPtrW(wndAfter, GWL_EXSTYLE) & WS_EX_TOPMOST)) michael@0: behind = wndAfter; michael@0: flags |= SWP_NOACTIVATE; michael@0: } michael@0: michael@0: ::SetWindowPos(mWnd, behind, 0, 0, 0, 0, flags); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Maximize, minimize or restore the window. michael@0: NS_IMETHODIMP nsWindow::SetSizeMode(int32_t aMode) { michael@0: michael@0: nsresult rv; michael@0: michael@0: // Let's not try and do anything if we're already in that state. michael@0: // (This is needed to prevent problems when calling window.minimize(), which michael@0: // calls us directly, and then the OS triggers another call to us.) michael@0: if (aMode == mSizeMode) michael@0: return NS_OK; michael@0: michael@0: // save the requested state michael@0: mLastSizeMode = mSizeMode; michael@0: rv = nsBaseWidget::SetSizeMode(aMode); michael@0: if (NS_SUCCEEDED(rv) && mIsVisible) { michael@0: int mode; michael@0: michael@0: switch (aMode) { michael@0: case nsSizeMode_Fullscreen : michael@0: mode = SW_SHOW; michael@0: break; michael@0: michael@0: case nsSizeMode_Maximized : michael@0: mode = SW_MAXIMIZE; michael@0: break; michael@0: michael@0: case nsSizeMode_Minimized : michael@0: // Using SW_SHOWMINIMIZED prevents the working set from being trimmed but michael@0: // keeps the window active in the tray. So after the window is minimized, michael@0: // windows will fire WM_WINDOWPOSCHANGED (OnWindowPosChanged) at which point michael@0: // we will do some additional processing to get the active window set right. michael@0: // If sTrimOnMinimize is set, we let windows handle minimization normally michael@0: // using SW_MINIMIZE. michael@0: mode = sTrimOnMinimize ? SW_MINIMIZE : SW_SHOWMINIMIZED; michael@0: break; michael@0: michael@0: default : michael@0: mode = SW_RESTORE; michael@0: } michael@0: michael@0: WINDOWPLACEMENT pl; michael@0: pl.length = sizeof(pl); michael@0: ::GetWindowPlacement(mWnd, &pl); michael@0: // Don't call ::ShowWindow if we're trying to "restore" a window that is michael@0: // already in a normal state. Prevents a bug where snapping to one side michael@0: // of the screen and then minimizing would cause Windows to forget our michael@0: // window's correct restored position/size. michael@0: if( !(pl.showCmd == SW_SHOWNORMAL && mode == SW_RESTORE) ) { michael@0: ::ShowWindow(mWnd, mode); michael@0: } michael@0: // we activate here to ensure that the right child window is focused michael@0: if (mode == SW_MAXIMIZE || mode == SW_SHOW) michael@0: DispatchFocusToTopLevelWindow(true); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: // Constrain a potential move to fit onscreen michael@0: // Position (aX, aY) is specified in Windows screen (logical) pixels michael@0: NS_METHOD nsWindow::ConstrainPosition(bool aAllowSlop, michael@0: int32_t *aX, int32_t *aY) michael@0: { michael@0: if (!mIsTopWidgetWindow) // only a problem for top-level windows michael@0: return NS_OK; michael@0: michael@0: double dpiScale = GetDefaultScale().scale; michael@0: michael@0: // we need to use the window size in logical screen pixels michael@0: int32_t logWidth = std::max(NSToIntRound(mBounds.width / dpiScale), 1); michael@0: int32_t logHeight = std::max(NSToIntRound(mBounds.height / dpiScale), 1); michael@0: michael@0: bool doConstrain = false; // whether we have enough info to do anything michael@0: michael@0: /* get our playing field. use the current screen, or failing that michael@0: for any reason, use device caps for the default screen. */ michael@0: RECT screenRect; michael@0: michael@0: nsCOMPtr screenmgr = do_GetService(sScreenManagerContractID); michael@0: if (screenmgr) { michael@0: nsCOMPtr screen; michael@0: int32_t left, top, width, height; michael@0: michael@0: screenmgr->ScreenForRect(*aX, *aY, logWidth, logHeight, michael@0: getter_AddRefs(screen)); michael@0: if (screen) { michael@0: if (mSizeMode != nsSizeMode_Fullscreen) { michael@0: // For normalized windows, use the desktop work area. michael@0: screen->GetAvailRectDisplayPix(&left, &top, &width, &height); michael@0: } else { michael@0: // For full screen windows, use the desktop. michael@0: screen->GetRectDisplayPix(&left, &top, &width, &height); michael@0: } michael@0: screenRect.left = left; michael@0: screenRect.right = left + width; michael@0: screenRect.top = top; michael@0: screenRect.bottom = top + height; michael@0: doConstrain = true; michael@0: } michael@0: } else { michael@0: if (mWnd) { michael@0: HDC dc = ::GetDC(mWnd); michael@0: if (dc) { michael@0: if (::GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY) { michael@0: if (mSizeMode != nsSizeMode_Fullscreen) { michael@0: ::SystemParametersInfo(SPI_GETWORKAREA, 0, &screenRect, 0); michael@0: } else { michael@0: screenRect.left = screenRect.top = 0; michael@0: screenRect.right = GetSystemMetrics(SM_CXFULLSCREEN); michael@0: screenRect.bottom = GetSystemMetrics(SM_CYFULLSCREEN); michael@0: } michael@0: doConstrain = true; michael@0: } michael@0: ::ReleaseDC(mWnd, dc); michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (aAllowSlop) { michael@0: if (*aX < screenRect.left - logWidth + kWindowPositionSlop) michael@0: *aX = screenRect.left - logWidth + kWindowPositionSlop; michael@0: else if (*aX >= screenRect.right - kWindowPositionSlop) michael@0: *aX = screenRect.right - kWindowPositionSlop; michael@0: michael@0: if (*aY < screenRect.top - logHeight + kWindowPositionSlop) michael@0: *aY = screenRect.top - logHeight + kWindowPositionSlop; michael@0: else if (*aY >= screenRect.bottom - kWindowPositionSlop) michael@0: *aY = screenRect.bottom - kWindowPositionSlop; michael@0: michael@0: } else { michael@0: michael@0: if (*aX < screenRect.left) michael@0: *aX = screenRect.left; michael@0: else if (*aX >= screenRect.right - logWidth) michael@0: *aX = screenRect.right - logWidth; michael@0: michael@0: if (*aY < screenRect.top) michael@0: *aY = screenRect.top; michael@0: else if (*aY >= screenRect.bottom - logHeight) michael@0: *aY = screenRect.bottom - logHeight; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: nsIWidget::Enable, nsIWidget::IsEnabled michael@0: * michael@0: * Enabling and disabling the widget. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: // Enable/disable this component michael@0: NS_METHOD nsWindow::Enable(bool bState) michael@0: { michael@0: if (mWnd) { michael@0: ::EnableWindow(mWnd, bState); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Return the current enable state michael@0: bool nsWindow::IsEnabled() const michael@0: { michael@0: return !mWnd || michael@0: (::IsWindowEnabled(mWnd) && michael@0: ::IsWindowEnabled(::GetAncestor(mWnd, GA_ROOT))); michael@0: } michael@0: michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: nsIWidget::SetFocus michael@0: * michael@0: * Give the focus to this widget. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: NS_METHOD nsWindow::SetFocus(bool aRaise) michael@0: { michael@0: if (mWnd) { michael@0: #ifdef WINSTATE_DEBUG_OUTPUT michael@0: if (mWnd == WinUtils::GetTopLevelHWND(mWnd)) { michael@0: PR_LOG(gWindowsLog, PR_LOG_ALWAYS, michael@0: ("*** SetFocus: [ top] raise=%d\n", aRaise)); michael@0: } else { michael@0: PR_LOG(gWindowsLog, PR_LOG_ALWAYS, michael@0: ("*** SetFocus: [child] raise=%d\n", aRaise)); michael@0: } michael@0: #endif michael@0: // Uniconify, if necessary michael@0: HWND toplevelWnd = WinUtils::GetTopLevelHWND(mWnd); michael@0: if (aRaise && ::IsIconic(toplevelWnd)) { michael@0: ::ShowWindow(toplevelWnd, SW_RESTORE); michael@0: } michael@0: ::SetFocus(mWnd); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: Bounds michael@0: * michael@0: * GetBounds, GetClientBounds, GetScreenBounds, GetClientOffset michael@0: * SetDrawsInTitlebar, GetNonClientMargins, SetNonClientMargins michael@0: * michael@0: * Bound calculations. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: // Return the window's full dimensions in screen coordinates. michael@0: // If the window has a parent, converts the origin to an offset michael@0: // of the parent's screen origin. michael@0: NS_METHOD nsWindow::GetBounds(nsIntRect &aRect) michael@0: { michael@0: if (mWnd) { michael@0: RECT r; michael@0: VERIFY(::GetWindowRect(mWnd, &r)); michael@0: michael@0: // assign size michael@0: aRect.width = r.right - r.left; michael@0: aRect.height = r.bottom - r.top; michael@0: michael@0: // popup window bounds' are in screen coordinates, not relative to parent michael@0: // window michael@0: if (mWindowType == eWindowType_popup) { michael@0: aRect.x = r.left; michael@0: aRect.y = r.top; michael@0: return NS_OK; michael@0: } michael@0: michael@0: // chrome on parent: michael@0: // ___ 5,5 (chrome start) michael@0: // | ____ 10,10 (client start) michael@0: // | | ____ 20,20 (child start) michael@0: // | | | michael@0: // 20,20 - 5,5 = 15,15 (??) michael@0: // minus GetClientOffset: michael@0: // 15,15 - 5,5 = 10,10 michael@0: // michael@0: // no chrome on parent: michael@0: // ______ 10,10 (win start) michael@0: // | ____ 20,20 (child start) michael@0: // | | michael@0: // 20,20 - 10,10 = 10,10 michael@0: // michael@0: // walking the chain: michael@0: // ___ 5,5 (chrome start) michael@0: // | ___ 10,10 (client start) michael@0: // | | ___ 20,20 (child start) michael@0: // | | | __ 30,30 (child start) michael@0: // | | | | michael@0: // 30,30 - 20,20 = 10,10 (offset from second child to first) michael@0: // 20,20 - 5,5 = 15,15 + 10,10 = 25,25 (??) michael@0: // minus GetClientOffset: michael@0: // 25,25 - 5,5 = 20,20 (offset from second child to parent client) michael@0: michael@0: // convert coordinates if parent exists michael@0: HWND parent = ::GetParent(mWnd); michael@0: if (parent) { michael@0: RECT pr; michael@0: VERIFY(::GetWindowRect(parent, &pr)); michael@0: r.left -= pr.left; michael@0: r.top -= pr.top; michael@0: // adjust for chrome michael@0: nsWindow* pWidget = static_cast(GetParent()); michael@0: if (pWidget && pWidget->IsTopLevelWidget()) { michael@0: nsIntPoint clientOffset = pWidget->GetClientOffset(); michael@0: r.left -= clientOffset.x; michael@0: r.top -= clientOffset.y; michael@0: } michael@0: } michael@0: aRect.x = r.left; michael@0: aRect.y = r.top; michael@0: } else { michael@0: aRect = mBounds; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Get this component dimension michael@0: NS_METHOD nsWindow::GetClientBounds(nsIntRect &aRect) michael@0: { michael@0: if (mWnd) { michael@0: RECT r; michael@0: VERIFY(::GetClientRect(mWnd, &r)); michael@0: michael@0: nsIntRect bounds; michael@0: GetBounds(bounds); michael@0: aRect.MoveTo(bounds.TopLeft() + GetClientOffset()); michael@0: aRect.width = r.right - r.left; michael@0: aRect.height = r.bottom - r.top; michael@0: michael@0: } else { michael@0: aRect.SetRect(0,0,0,0); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Like GetBounds, but don't offset by the parent michael@0: NS_METHOD nsWindow::GetScreenBounds(nsIntRect &aRect) michael@0: { michael@0: if (mWnd) { michael@0: RECT r; michael@0: VERIFY(::GetWindowRect(mWnd, &r)); michael@0: michael@0: aRect.width = r.right - r.left; michael@0: aRect.height = r.bottom - r.top; michael@0: aRect.x = r.left; michael@0: aRect.y = r.top; michael@0: } else michael@0: aRect = mBounds; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // return the x,y offset of the client area from the origin michael@0: // of the window. If the window is borderless returns (0,0). michael@0: nsIntPoint nsWindow::GetClientOffset() michael@0: { michael@0: if (!mWnd) { michael@0: return nsIntPoint(0, 0); michael@0: } michael@0: michael@0: RECT r1; michael@0: GetWindowRect(mWnd, &r1); michael@0: nsIntPoint pt = WidgetToScreenOffset(); michael@0: return nsIntPoint(pt.x - r1.left, pt.y - r1.top); michael@0: } michael@0: michael@0: void michael@0: nsWindow::SetDrawsInTitlebar(bool aState) michael@0: { michael@0: nsWindow * window = GetTopLevelWindow(true); michael@0: if (window && window != this) { michael@0: return window->SetDrawsInTitlebar(aState); michael@0: } michael@0: michael@0: if (aState) { michael@0: // top, right, bottom, left for nsIntMargin michael@0: nsIntMargin margins(0, -1, -1, -1); michael@0: SetNonClientMargins(margins); michael@0: } michael@0: else { michael@0: nsIntMargin margins(-1, -1, -1, -1); michael@0: SetNonClientMargins(margins); michael@0: } michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::GetNonClientMargins(nsIntMargin &margins) michael@0: { michael@0: nsWindow * window = GetTopLevelWindow(true); michael@0: if (window && window != this) { michael@0: return window->GetNonClientMargins(margins); michael@0: } michael@0: michael@0: if (mCustomNonClient) { michael@0: margins = mNonClientMargins; michael@0: return NS_OK; michael@0: } michael@0: michael@0: margins.top = GetSystemMetrics(SM_CYCAPTION); michael@0: margins.bottom = GetSystemMetrics(SM_CYFRAME); michael@0: margins.top += margins.bottom; michael@0: margins.left = margins.right = GetSystemMetrics(SM_CXFRAME); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: nsWindow::ResetLayout() michael@0: { michael@0: // This will trigger a frame changed event, triggering michael@0: // nc calc size and a sizemode gecko event. michael@0: SetWindowPos(mWnd, 0, 0, 0, 0, 0, michael@0: SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOMOVE| michael@0: SWP_NOOWNERZORDER|SWP_NOSIZE|SWP_NOZORDER); michael@0: michael@0: // If hidden, just send the frame changed event for now. michael@0: if (!mIsVisible) michael@0: return; michael@0: michael@0: // Send a gecko size event to trigger reflow. michael@0: RECT clientRc = {0}; michael@0: GetClientRect(mWnd, &clientRc); michael@0: nsIntRect evRect(WinUtils::ToIntRect(clientRc)); michael@0: OnResize(evRect); michael@0: michael@0: // Invalidate and update michael@0: Invalidate(); michael@0: } michael@0: michael@0: // Internally track the caption status via a window property. Required michael@0: // due to our internal handling of WM_NCACTIVATE when custom client michael@0: // margins are set. michael@0: static const wchar_t kManageWindowInfoProperty[] = L"ManageWindowInfoProperty"; michael@0: typedef BOOL (WINAPI *GetWindowInfoPtr)(HWND hwnd, PWINDOWINFO pwi); michael@0: static GetWindowInfoPtr sGetWindowInfoPtrStub = nullptr; michael@0: michael@0: BOOL WINAPI michael@0: GetWindowInfoHook(HWND hWnd, PWINDOWINFO pwi) michael@0: { michael@0: if (!sGetWindowInfoPtrStub) { michael@0: NS_ASSERTION(FALSE, "Something is horribly wrong in GetWindowInfoHook!"); michael@0: return FALSE; michael@0: } michael@0: int windowStatus = michael@0: reinterpret_cast(GetPropW(hWnd, kManageWindowInfoProperty)); michael@0: // No property set, return the default data. michael@0: if (!windowStatus) michael@0: return sGetWindowInfoPtrStub(hWnd, pwi); michael@0: // Call GetWindowInfo and update dwWindowStatus with our michael@0: // internally tracked value. michael@0: BOOL result = sGetWindowInfoPtrStub(hWnd, pwi); michael@0: if (result && pwi) michael@0: pwi->dwWindowStatus = (windowStatus == 1 ? 0 : WS_ACTIVECAPTION); michael@0: return result; michael@0: } michael@0: michael@0: void michael@0: nsWindow::UpdateGetWindowInfoCaptionStatus(bool aActiveCaption) michael@0: { michael@0: if (!mWnd) michael@0: return; michael@0: michael@0: if (!sGetWindowInfoPtrStub) { michael@0: sUser32Intercept.Init("user32.dll"); michael@0: if (!sUser32Intercept.AddHook("GetWindowInfo", reinterpret_cast(GetWindowInfoHook), michael@0: (void**) &sGetWindowInfoPtrStub)) michael@0: return; michael@0: } michael@0: // Update our internally tracked caption status michael@0: SetPropW(mWnd, kManageWindowInfoProperty, michael@0: reinterpret_cast(static_cast(aActiveCaption) + 1)); michael@0: } michael@0: michael@0: /** michael@0: * Called when the window layout changes: full screen mode transitions, michael@0: * theme changes, and composition changes. Calculates the new non-client michael@0: * margins and fires off a frame changed event, which triggers an nc calc michael@0: * size windows event, kicking the changes in. michael@0: * michael@0: * The offsets calculated here are based on the value of `mNonClientMargins` michael@0: * which is specified in the "chromemargins" attribute of the window. For michael@0: * each margin, the value specified has the following meaning: michael@0: * -1 - leave the default frame in place michael@0: * 0 - remove the frame michael@0: * >0 - frame size equals min(0, (default frame size - margin value)) michael@0: * michael@0: * This function calculates and populates `mNonClientOffset`. michael@0: * In our processing of `WM_NCCALCSIZE`, the frame size will be calculated michael@0: * as (default frame size - offset). For example, if the left frame should michael@0: * be 1 pixel narrower than the default frame size, `mNonClientOffset.left` michael@0: * will equal 1. michael@0: * michael@0: * For maximized, fullscreen, and minimized windows, the values stored in michael@0: * `mNonClientMargins` are ignored, and special processing takes place. michael@0: * michael@0: * For non-glass windows, we only allow frames to be their default size michael@0: * or removed entirely. michael@0: */ michael@0: bool michael@0: nsWindow::UpdateNonClientMargins(int32_t aSizeMode, bool aReflowWindow) michael@0: { michael@0: if (!mCustomNonClient) michael@0: return false; michael@0: michael@0: if (aSizeMode == -1) { michael@0: aSizeMode = mSizeMode; michael@0: } michael@0: michael@0: bool hasCaption = (mBorderStyle michael@0: & (eBorderStyle_all michael@0: | eBorderStyle_title michael@0: | eBorderStyle_menu michael@0: | eBorderStyle_default)); michael@0: michael@0: // mCaptionHeight is the default size of the NC area at michael@0: // the top of the window. If the window has a caption, michael@0: // the size is calculated as the sum of: michael@0: // SM_CYFRAME - The thickness of the sizing border michael@0: // around a resizable window michael@0: // SM_CXPADDEDBORDER - The amount of border padding michael@0: // for captioned windows michael@0: // SM_CYCAPTION - The height of the caption area michael@0: // michael@0: // If the window does not have a caption, mCaptionHeight will be equal to michael@0: // `GetSystemMetrics(SM_CYFRAME)` michael@0: mCaptionHeight = GetSystemMetrics(SM_CYFRAME) michael@0: + (hasCaption ? GetSystemMetrics(SM_CYCAPTION) michael@0: + GetSystemMetrics(SM_CXPADDEDBORDER) michael@0: : 0); michael@0: michael@0: // mHorResizeMargin is the size of the default NC areas on the michael@0: // left and right sides of our window. It is calculated as michael@0: // the sum of: michael@0: // SM_CXFRAME - The thickness of the sizing border michael@0: // SM_CXPADDEDBORDER - The amount of border padding michael@0: // for captioned windows michael@0: // michael@0: // If the window does not have a caption, mHorResizeMargin will be equal to michael@0: // `GetSystemMetrics(SM_CXFRAME)` michael@0: mHorResizeMargin = GetSystemMetrics(SM_CXFRAME) michael@0: + (hasCaption ? GetSystemMetrics(SM_CXPADDEDBORDER) : 0); michael@0: michael@0: // mVertResizeMargin is the size of the default NC area at the michael@0: // bottom of the window. It is calculated as the sum of: michael@0: // SM_CYFRAME - The thickness of the sizing border michael@0: // SM_CXPADDEDBORDER - The amount of border padding michael@0: // for captioned windows. michael@0: // michael@0: // If the window does not have a caption, mVertResizeMargin will be equal to michael@0: // `GetSystemMetrics(SM_CYFRAME)` michael@0: mVertResizeMargin = GetSystemMetrics(SM_CYFRAME) michael@0: + (hasCaption ? GetSystemMetrics(SM_CXPADDEDBORDER) : 0); michael@0: michael@0: if (aSizeMode == nsSizeMode_Minimized) { michael@0: // Use default frame size for minimized windows michael@0: mNonClientOffset.top = 0; michael@0: mNonClientOffset.left = 0; michael@0: mNonClientOffset.right = 0; michael@0: mNonClientOffset.bottom = 0; michael@0: } else if (aSizeMode == nsSizeMode_Fullscreen) { michael@0: // Remove the default frame from the top of our fullscreen window. This michael@0: // makes the whole caption part of our client area, allowing us to draw michael@0: // in the whole caption area. Additionally remove the default frame from michael@0: // the left, right, and bottom. michael@0: mNonClientOffset.top = mCaptionHeight; michael@0: mNonClientOffset.bottom = mVertResizeMargin; michael@0: mNonClientOffset.left = mHorResizeMargin; michael@0: mNonClientOffset.right = mHorResizeMargin; michael@0: } else if (aSizeMode == nsSizeMode_Maximized) { michael@0: // Remove the default frame from the top of our maximized window. This michael@0: // makes the whole caption part of our client area, allowing us to draw michael@0: // in the whole caption area. Use default frame size on left, right, and michael@0: // bottom. The reason this works is that, for maximized windows, michael@0: // Windows positions them so that their frames fall off the screen. michael@0: // This gives the illusion of windows having no frames when they are michael@0: // maximized. If we try to mess with the frame sizes by setting these michael@0: // offsets to positive values, our client area will fall off the screen. michael@0: mNonClientOffset.top = mCaptionHeight; michael@0: mNonClientOffset.bottom = 0; michael@0: mNonClientOffset.left = 0; michael@0: mNonClientOffset.right = 0; michael@0: michael@0: APPBARDATA appBarData; michael@0: appBarData.cbSize = sizeof(appBarData); michael@0: UINT taskbarState = SHAppBarMessage(ABM_GETSTATE, &appBarData); michael@0: if (ABS_AUTOHIDE & taskbarState) { michael@0: UINT edge = -1; michael@0: appBarData.hWnd = FindWindow(L"Shell_TrayWnd", nullptr); michael@0: if (appBarData.hWnd) { michael@0: HMONITOR taskbarMonitor = ::MonitorFromWindow(appBarData.hWnd, michael@0: MONITOR_DEFAULTTOPRIMARY); michael@0: HMONITOR windowMonitor = ::MonitorFromWindow(mWnd, michael@0: MONITOR_DEFAULTTONEAREST); michael@0: if (taskbarMonitor == windowMonitor) { michael@0: SHAppBarMessage(ABM_GETTASKBARPOS, &appBarData); michael@0: edge = appBarData.uEdge; michael@0: } michael@0: } michael@0: michael@0: if (ABE_LEFT == edge) { michael@0: mNonClientOffset.left -= 1; michael@0: } else if (ABE_RIGHT == edge) { michael@0: mNonClientOffset.right -= 1; michael@0: } else if (ABE_BOTTOM == edge || ABE_TOP == edge) { michael@0: mNonClientOffset.bottom -= 1; michael@0: } michael@0: } michael@0: } else { michael@0: bool glass = nsUXThemeData::CheckForCompositor(); michael@0: michael@0: // We're dealing with a "normal" window (not maximized, minimized, or michael@0: // fullscreen), so process `mNonClientMargins` and set `mNonClientOffset` michael@0: // accordingly. michael@0: // michael@0: // Setting `mNonClientOffset` to 0 has the effect of leaving the default michael@0: // frame intact. Setting it to a value greater than 0 reduces the frame michael@0: // size by that amount. michael@0: michael@0: if (mNonClientMargins.top > 0 && glass) { michael@0: mNonClientOffset.top = std::min(mCaptionHeight, mNonClientMargins.top); michael@0: } else if (mNonClientMargins.top == 0) { michael@0: mNonClientOffset.top = mCaptionHeight; michael@0: } else { michael@0: mNonClientOffset.top = 0; michael@0: } michael@0: michael@0: if (mNonClientMargins.bottom > 0 && glass) { michael@0: mNonClientOffset.bottom = std::min(mVertResizeMargin, mNonClientMargins.bottom); michael@0: } else if (mNonClientMargins.bottom == 0) { michael@0: mNonClientOffset.bottom = mVertResizeMargin; michael@0: } else { michael@0: mNonClientOffset.bottom = 0; michael@0: } michael@0: michael@0: if (mNonClientMargins.left > 0 && glass) { michael@0: mNonClientOffset.left = std::min(mHorResizeMargin, mNonClientMargins.left); michael@0: } else if (mNonClientMargins.left == 0) { michael@0: mNonClientOffset.left = mHorResizeMargin; michael@0: } else { michael@0: mNonClientOffset.left = 0; michael@0: } michael@0: michael@0: if (mNonClientMargins.right > 0 && glass) { michael@0: mNonClientOffset.right = std::min(mHorResizeMargin, mNonClientMargins.right); michael@0: } else if (mNonClientMargins.right == 0) { michael@0: mNonClientOffset.right = mHorResizeMargin; michael@0: } else { michael@0: mNonClientOffset.right = 0; michael@0: } michael@0: } michael@0: michael@0: if (aReflowWindow) { michael@0: // Force a reflow of content based on the new client michael@0: // dimensions. michael@0: ResetLayout(); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::SetNonClientMargins(nsIntMargin &margins) michael@0: { michael@0: if (!mIsTopWidgetWindow || michael@0: mBorderStyle & eBorderStyle_none || michael@0: mHideChrome) michael@0: return NS_ERROR_INVALID_ARG; michael@0: michael@0: // Request for a reset michael@0: if (margins.top == -1 && margins.left == -1 && michael@0: margins.right == -1 && margins.bottom == -1) { michael@0: mCustomNonClient = false; michael@0: mNonClientMargins = margins; michael@0: // Force a reflow of content based on the new client michael@0: // dimensions. michael@0: ResetLayout(); michael@0: michael@0: int windowStatus = michael@0: reinterpret_cast(GetPropW(mWnd, kManageWindowInfoProperty)); michael@0: if (windowStatus) { michael@0: ::SendMessageW(mWnd, WM_NCACTIVATE, 1 != windowStatus, 0); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (margins.top < -1 || margins.bottom < -1 || michael@0: margins.left < -1 || margins.right < -1) michael@0: return NS_ERROR_INVALID_ARG; michael@0: michael@0: mNonClientMargins = margins; michael@0: mCustomNonClient = true; michael@0: if (!UpdateNonClientMargins()) { michael@0: NS_WARNING("UpdateNonClientMargins failed!"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: nsWindow::InvalidateNonClientRegion() michael@0: { michael@0: // +-+-----------------------+-+ michael@0: // | | app non-client chrome | | michael@0: // | +-----------------------+ | michael@0: // | | app client chrome | | } michael@0: // | +-----------------------+ | } michael@0: // | | app content | | } area we don't want to invalidate michael@0: // | +-----------------------+ | } michael@0: // | | app client chrome | | } michael@0: // | +-----------------------+ | michael@0: // +---------------------------+ < michael@0: // ^ ^ windows non-client chrome michael@0: // client area = app * michael@0: RECT rect; michael@0: GetWindowRect(mWnd, &rect); michael@0: MapWindowPoints(nullptr, mWnd, (LPPOINT)&rect, 2); michael@0: HRGN winRgn = CreateRectRgnIndirect(&rect); michael@0: michael@0: // Subtract app client chrome and app content leaving michael@0: // windows non-client chrome and app non-client chrome michael@0: // in winRgn. michael@0: GetWindowRect(mWnd, &rect); michael@0: rect.top += mCaptionHeight; michael@0: rect.right -= mHorResizeMargin; michael@0: rect.bottom -= mHorResizeMargin; michael@0: rect.left += mVertResizeMargin; michael@0: MapWindowPoints(nullptr, mWnd, (LPPOINT)&rect, 2); michael@0: HRGN clientRgn = CreateRectRgnIndirect(&rect); michael@0: CombineRgn(winRgn, winRgn, clientRgn, RGN_DIFF); michael@0: DeleteObject(clientRgn); michael@0: michael@0: // triggers ncpaint and paint events for the two areas michael@0: RedrawWindow(mWnd, nullptr, winRgn, RDW_FRAME | RDW_INVALIDATE); michael@0: DeleteObject(winRgn); michael@0: } michael@0: michael@0: HRGN michael@0: nsWindow::ExcludeNonClientFromPaintRegion(HRGN aRegion) michael@0: { michael@0: RECT rect; michael@0: HRGN rgn = nullptr; michael@0: if (aRegion == (HRGN)1) { // undocumented value indicating a full refresh michael@0: GetWindowRect(mWnd, &rect); michael@0: rgn = CreateRectRgnIndirect(&rect); michael@0: } else { michael@0: rgn = aRegion; michael@0: } michael@0: GetClientRect(mWnd, &rect); michael@0: MapWindowPoints(mWnd, nullptr, (LPPOINT)&rect, 2); michael@0: HRGN nonClientRgn = CreateRectRgnIndirect(&rect); michael@0: CombineRgn(rgn, rgn, nonClientRgn, RGN_DIFF); michael@0: DeleteObject(nonClientRgn); michael@0: return rgn; michael@0: } michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: nsIWidget::SetBackgroundColor michael@0: * michael@0: * Sets the window background paint color. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: void nsWindow::SetBackgroundColor(const nscolor &aColor) michael@0: { michael@0: if (mBrush) michael@0: ::DeleteObject(mBrush); michael@0: michael@0: mBrush = ::CreateSolidBrush(NSRGB_2_COLOREF(aColor)); michael@0: if (mWnd != nullptr) { michael@0: ::SetClassLongPtrW(mWnd, GCLP_HBRBACKGROUND, (LONG_PTR)mBrush); michael@0: } michael@0: } michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: nsIWidget::SetCursor michael@0: * michael@0: * SetCursor and related utilities for manging cursor state. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: // Set this component cursor michael@0: NS_METHOD nsWindow::SetCursor(nsCursor aCursor) michael@0: { michael@0: // Only change cursor if it's changing michael@0: michael@0: //XXX mCursor isn't always right. Scrollbars and others change it, too. michael@0: //XXX If we want this optimization we need a better way to do it. michael@0: //if (aCursor != mCursor) { michael@0: HCURSOR newCursor = nullptr; michael@0: michael@0: switch (aCursor) { michael@0: case eCursor_select: michael@0: newCursor = ::LoadCursor(nullptr, IDC_IBEAM); michael@0: break; michael@0: michael@0: case eCursor_wait: michael@0: newCursor = ::LoadCursor(nullptr, IDC_WAIT); michael@0: break; michael@0: michael@0: case eCursor_hyperlink: michael@0: { michael@0: newCursor = ::LoadCursor(nullptr, IDC_HAND); michael@0: break; michael@0: } michael@0: michael@0: case eCursor_standard: michael@0: case eCursor_context_menu: // XXX See bug 258960. michael@0: newCursor = ::LoadCursor(nullptr, IDC_ARROW); michael@0: break; michael@0: michael@0: case eCursor_n_resize: michael@0: case eCursor_s_resize: michael@0: newCursor = ::LoadCursor(nullptr, IDC_SIZENS); michael@0: break; michael@0: michael@0: case eCursor_w_resize: michael@0: case eCursor_e_resize: michael@0: newCursor = ::LoadCursor(nullptr, IDC_SIZEWE); michael@0: break; michael@0: michael@0: case eCursor_nw_resize: michael@0: case eCursor_se_resize: michael@0: newCursor = ::LoadCursor(nullptr, IDC_SIZENWSE); michael@0: break; michael@0: michael@0: case eCursor_ne_resize: michael@0: case eCursor_sw_resize: michael@0: newCursor = ::LoadCursor(nullptr, IDC_SIZENESW); michael@0: break; michael@0: michael@0: case eCursor_crosshair: michael@0: newCursor = ::LoadCursor(nullptr, IDC_CROSS); michael@0: break; michael@0: michael@0: case eCursor_move: michael@0: newCursor = ::LoadCursor(nullptr, IDC_SIZEALL); michael@0: break; michael@0: michael@0: case eCursor_help: michael@0: newCursor = ::LoadCursor(nullptr, IDC_HELP); michael@0: break; michael@0: michael@0: case eCursor_copy: // CSS3 michael@0: newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_COPY)); michael@0: break; michael@0: michael@0: case eCursor_alias: michael@0: newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ALIAS)); michael@0: break; michael@0: michael@0: case eCursor_cell: michael@0: newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_CELL)); michael@0: break; michael@0: michael@0: case eCursor_grab: michael@0: newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_GRAB)); michael@0: break; michael@0: michael@0: case eCursor_grabbing: michael@0: newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_GRABBING)); michael@0: break; michael@0: michael@0: case eCursor_spinning: michael@0: newCursor = ::LoadCursor(nullptr, IDC_APPSTARTING); michael@0: break; michael@0: michael@0: case eCursor_zoom_in: michael@0: newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ZOOMIN)); michael@0: break; michael@0: michael@0: case eCursor_zoom_out: michael@0: newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ZOOMOUT)); michael@0: break; michael@0: michael@0: case eCursor_not_allowed: michael@0: case eCursor_no_drop: michael@0: newCursor = ::LoadCursor(nullptr, IDC_NO); michael@0: break; michael@0: michael@0: case eCursor_col_resize: michael@0: newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_COLRESIZE)); michael@0: break; michael@0: michael@0: case eCursor_row_resize: michael@0: newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_ROWRESIZE)); michael@0: break; michael@0: michael@0: case eCursor_vertical_text: michael@0: newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_VERTICALTEXT)); michael@0: break; michael@0: michael@0: case eCursor_all_scroll: michael@0: // XXX not 100% appropriate perhaps michael@0: newCursor = ::LoadCursor(nullptr, IDC_SIZEALL); michael@0: break; michael@0: michael@0: case eCursor_nesw_resize: michael@0: newCursor = ::LoadCursor(nullptr, IDC_SIZENESW); michael@0: break; michael@0: michael@0: case eCursor_nwse_resize: michael@0: newCursor = ::LoadCursor(nullptr, IDC_SIZENWSE); michael@0: break; michael@0: michael@0: case eCursor_ns_resize: michael@0: newCursor = ::LoadCursor(nullptr, IDC_SIZENS); michael@0: break; michael@0: michael@0: case eCursor_ew_resize: michael@0: newCursor = ::LoadCursor(nullptr, IDC_SIZEWE); michael@0: break; michael@0: michael@0: case eCursor_none: michael@0: newCursor = ::LoadCursor(nsToolkit::mDllInstance, MAKEINTRESOURCE(IDC_NONE)); michael@0: break; michael@0: michael@0: default: michael@0: NS_ERROR("Invalid cursor type"); michael@0: break; michael@0: } michael@0: michael@0: if (nullptr != newCursor) { michael@0: mCursor = aCursor; michael@0: HCURSOR oldCursor = ::SetCursor(newCursor); michael@0: michael@0: if (sHCursor == oldCursor) { michael@0: NS_IF_RELEASE(sCursorImgContainer); michael@0: if (sHCursor != nullptr) michael@0: ::DestroyIcon(sHCursor); michael@0: sHCursor = nullptr; michael@0: } michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Setting the actual cursor michael@0: NS_IMETHODIMP nsWindow::SetCursor(imgIContainer* aCursor, michael@0: uint32_t aHotspotX, uint32_t aHotspotY) michael@0: { michael@0: if (sCursorImgContainer == aCursor && sHCursor) { michael@0: ::SetCursor(sHCursor); michael@0: return NS_OK; michael@0: } michael@0: michael@0: int32_t width; michael@0: int32_t height; michael@0: michael@0: nsresult rv; michael@0: rv = aCursor->GetWidth(&width); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: rv = aCursor->GetHeight(&height); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // Reject cursors greater than 128 pixels in either direction, to prevent michael@0: // spoofing. michael@0: // XXX ideally we should rescale. Also, we could modify the API to michael@0: // allow trusted content to set larger cursors. michael@0: if (width > 128 || height > 128) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: HCURSOR cursor; michael@0: // No scaling michael@0: gfxIntSize size(0, 0); michael@0: rv = nsWindowGfx::CreateIcon(aCursor, true, aHotspotX, aHotspotY, size, &cursor); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: mCursor = nsCursor(-1); michael@0: ::SetCursor(cursor); michael@0: michael@0: NS_IF_RELEASE(sCursorImgContainer); michael@0: sCursorImgContainer = aCursor; michael@0: NS_ADDREF(sCursorImgContainer); michael@0: michael@0: if (sHCursor != nullptr) michael@0: ::DestroyIcon(sHCursor); michael@0: sHCursor = cursor; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: nsIWidget::Get/SetTransparencyMode michael@0: * michael@0: * Manage the transparency mode of the top-level window michael@0: * containing this widget. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: #ifdef MOZ_XUL michael@0: nsTransparencyMode nsWindow::GetTransparencyMode() michael@0: { michael@0: return GetTopLevelWindow(true)->GetWindowTranslucencyInner(); michael@0: } michael@0: michael@0: void nsWindow::SetTransparencyMode(nsTransparencyMode aMode) michael@0: { michael@0: GetTopLevelWindow(true)->SetWindowTranslucencyInner(aMode); michael@0: } michael@0: michael@0: static const nsIntRegion michael@0: RegionFromArray(const nsTArray& aRects) michael@0: { michael@0: nsIntRegion region; michael@0: for (uint32_t i = 0; i < aRects.Length(); ++i) { michael@0: region.Or(region, aRects[i]); michael@0: } michael@0: return region; michael@0: } michael@0: michael@0: void nsWindow::UpdateOpaqueRegion(const nsIntRegion &aOpaqueRegion) michael@0: { michael@0: if (!HasGlass() || GetParent()) michael@0: return; michael@0: michael@0: // If there is no opaque region or hidechrome=true, set margins michael@0: // to support a full sheet of glass. Comments in MSDN indicate michael@0: // all values must be set to -1 to get a full sheet of glass. michael@0: MARGINS margins = { -1, -1, -1, -1 }; michael@0: if (!aOpaqueRegion.IsEmpty()) { michael@0: nsIntRect pluginBounds; michael@0: for (nsIWidget* child = GetFirstChild(); child; child = child->GetNextSibling()) { michael@0: if (child->WindowType() == eWindowType_plugin) { michael@0: // Collect the bounds of all plugins for GetLargestRectangle. michael@0: nsIntRect childBounds; michael@0: child->GetBounds(childBounds); michael@0: pluginBounds.UnionRect(pluginBounds, childBounds); michael@0: } michael@0: } michael@0: michael@0: nsIntRect clientBounds; michael@0: GetClientBounds(clientBounds); michael@0: michael@0: // Find the largest rectangle and use that to calculate the inset. Our top michael@0: // priority is to include the bounds of all plugins. michael@0: nsIntRect largest = aOpaqueRegion.GetLargestRectangle(pluginBounds); michael@0: margins.cxLeftWidth = largest.x; michael@0: margins.cxRightWidth = clientBounds.width - largest.XMost(); michael@0: margins.cyBottomHeight = clientBounds.height - largest.YMost(); michael@0: if (mCustomNonClient) { michael@0: // The minimum glass height must be the caption buttons height, michael@0: // otherwise the buttons are drawn incorrectly. michael@0: largest.y = std::max(largest.y, michael@0: nsUXThemeData::sCommandButtons[CMDBUTTONIDX_BUTTONBOX].cy); michael@0: } michael@0: margins.cyTopHeight = largest.y; michael@0: } michael@0: michael@0: // Only update glass area if there are changes michael@0: if (memcmp(&mGlassMargins, &margins, sizeof mGlassMargins)) { michael@0: mGlassMargins = margins; michael@0: UpdateGlass(); michael@0: } michael@0: } michael@0: michael@0: void nsWindow::UpdateGlass() michael@0: { michael@0: MARGINS margins = mGlassMargins; michael@0: michael@0: // DWMNCRP_USEWINDOWSTYLE - The non-client rendering area is michael@0: // rendered based on the window style. michael@0: // DWMNCRP_ENABLED - The non-client area rendering is michael@0: // enabled; the window style is ignored. michael@0: DWMNCRENDERINGPOLICY policy = DWMNCRP_USEWINDOWSTYLE; michael@0: switch (mTransparencyMode) { michael@0: case eTransparencyBorderlessGlass: michael@0: // Only adjust if there is some opaque rectangle michael@0: if (margins.cxLeftWidth >= 0) { michael@0: margins.cxLeftWidth += kGlassMarginAdjustment; michael@0: margins.cyTopHeight += kGlassMarginAdjustment; michael@0: margins.cxRightWidth += kGlassMarginAdjustment; michael@0: margins.cyBottomHeight += kGlassMarginAdjustment; michael@0: } michael@0: // Fall through michael@0: case eTransparencyGlass: michael@0: policy = DWMNCRP_ENABLED; michael@0: break; michael@0: } michael@0: michael@0: PR_LOG(gWindowsLog, PR_LOG_ALWAYS, michael@0: ("glass margins: left:%d top:%d right:%d bottom:%d\n", michael@0: margins.cxLeftWidth, margins.cyTopHeight, michael@0: margins.cxRightWidth, margins.cyBottomHeight)); michael@0: michael@0: // Extends the window frame behind the client area michael@0: if (nsUXThemeData::CheckForCompositor()) { michael@0: WinUtils::dwmExtendFrameIntoClientAreaPtr(mWnd, &margins); michael@0: WinUtils::dwmSetWindowAttributePtr(mWnd, DWMWA_NCRENDERING_POLICY, &policy, sizeof policy); michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: nsIWidget::HideWindowChrome michael@0: * michael@0: * Show or hide window chrome. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: NS_IMETHODIMP nsWindow::HideWindowChrome(bool aShouldHide) michael@0: { michael@0: HWND hwnd = WinUtils::GetTopLevelHWND(mWnd, true); michael@0: if (!WinUtils::GetNSWindowPtr(hwnd)) michael@0: { michael@0: NS_WARNING("Trying to hide window decorations in an embedded context"); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: if (mHideChrome == aShouldHide) michael@0: return NS_OK; michael@0: michael@0: DWORD_PTR style, exStyle; michael@0: mHideChrome = aShouldHide; michael@0: if (aShouldHide) { michael@0: DWORD_PTR tempStyle = ::GetWindowLongPtrW(hwnd, GWL_STYLE); michael@0: DWORD_PTR tempExStyle = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE); michael@0: michael@0: style = tempStyle & ~(WS_CAPTION | WS_THICKFRAME); michael@0: exStyle = tempExStyle & ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE | michael@0: WS_EX_CLIENTEDGE | WS_EX_STATICEDGE); michael@0: michael@0: mOldStyle = tempStyle; michael@0: mOldExStyle = tempExStyle; michael@0: } michael@0: else { michael@0: if (!mOldStyle || !mOldExStyle) { michael@0: mOldStyle = ::GetWindowLongPtrW(hwnd, GWL_STYLE); michael@0: mOldExStyle = ::GetWindowLongPtrW(hwnd, GWL_EXSTYLE); michael@0: } michael@0: michael@0: style = mOldStyle; michael@0: exStyle = mOldExStyle; michael@0: } michael@0: michael@0: VERIFY_WINDOW_STYLE(style); michael@0: ::SetWindowLongPtrW(hwnd, GWL_STYLE, style); michael@0: ::SetWindowLongPtrW(hwnd, GWL_EXSTYLE, exStyle); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: nsWindow::Invalidate michael@0: * michael@0: * Invalidate an area of the client for painting. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: // Invalidate this component visible area michael@0: NS_METHOD nsWindow::Invalidate(bool aEraseBackground, michael@0: bool aUpdateNCArea, michael@0: bool aIncludeChildren) michael@0: { michael@0: if (!mWnd) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: #ifdef WIDGET_DEBUG_OUTPUT michael@0: debug_DumpInvalidate(stdout, michael@0: this, michael@0: nullptr, michael@0: nsAutoCString("noname"), michael@0: (int32_t) mWnd); michael@0: #endif // WIDGET_DEBUG_OUTPUT michael@0: michael@0: DWORD flags = RDW_INVALIDATE; michael@0: if (aEraseBackground) { michael@0: flags |= RDW_ERASE; michael@0: } michael@0: if (aUpdateNCArea) { michael@0: flags |= RDW_FRAME; michael@0: } michael@0: if (aIncludeChildren) { michael@0: flags |= RDW_ALLCHILDREN; michael@0: } michael@0: michael@0: VERIFY(::RedrawWindow(mWnd, nullptr, nullptr, flags)); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Invalidate this component visible area michael@0: NS_METHOD nsWindow::Invalidate(const nsIntRect & aRect) michael@0: { michael@0: if (mWnd) michael@0: { michael@0: #ifdef WIDGET_DEBUG_OUTPUT michael@0: debug_DumpInvalidate(stdout, michael@0: this, michael@0: &aRect, michael@0: nsAutoCString("noname"), michael@0: (int32_t) mWnd); michael@0: #endif // WIDGET_DEBUG_OUTPUT michael@0: michael@0: RECT rect; michael@0: michael@0: rect.left = aRect.x; michael@0: rect.top = aRect.y; michael@0: rect.right = aRect.x + aRect.width; michael@0: rect.bottom = aRect.y + aRect.height; michael@0: michael@0: VERIFY(::InvalidateRect(mWnd, &rect, FALSE)); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::MakeFullScreen(bool aFullScreen) michael@0: { michael@0: // taskbarInfo will be nullptr pre Windows 7 until Bug 680227 is resolved. michael@0: nsCOMPtr taskbarInfo = michael@0: do_GetService(NS_TASKBAR_CONTRACTID); michael@0: michael@0: mFullscreenMode = aFullScreen; michael@0: if (aFullScreen) { michael@0: if (mSizeMode == nsSizeMode_Fullscreen) michael@0: return NS_OK; michael@0: mOldSizeMode = mSizeMode; michael@0: SetSizeMode(nsSizeMode_Fullscreen); michael@0: michael@0: // Notify the taskbar that we will be entering full screen mode. michael@0: if (taskbarInfo) { michael@0: taskbarInfo->PrepareFullScreenHWND(mWnd, TRUE); michael@0: } michael@0: } else { michael@0: SetSizeMode(mOldSizeMode); michael@0: } michael@0: michael@0: UpdateNonClientMargins(); michael@0: michael@0: bool visible = mIsVisible; michael@0: if (mOldSizeMode == nsSizeMode_Normal) michael@0: Show(false); michael@0: michael@0: // Will call hide chrome, reposition window. Note this will michael@0: // also cache dimensions for restoration, so it should only michael@0: // be called once per fullscreen request. michael@0: nsresult rv = nsBaseWidget::MakeFullScreen(aFullScreen); michael@0: michael@0: if (visible) { michael@0: Show(true); michael@0: Invalidate(); michael@0: } michael@0: michael@0: // Notify the taskbar that we have exited full screen mode. michael@0: if (!aFullScreen && taskbarInfo) { michael@0: taskbarInfo->PrepareFullScreenHWND(mWnd, FALSE); michael@0: } michael@0: michael@0: if (mWidgetListener) michael@0: mWidgetListener->SizeModeChanged(mSizeMode); michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: Native data storage michael@0: * michael@0: * nsIWidget::GetNativeData michael@0: * nsIWidget::FreeNativeData michael@0: * michael@0: * Set or clear native data based on a constant. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: // Return some native data according to aDataType michael@0: void* nsWindow::GetNativeData(uint32_t aDataType) michael@0: { michael@0: nsAutoString className; michael@0: switch (aDataType) { michael@0: case NS_NATIVE_TMP_WINDOW: michael@0: GetWindowClass(className); michael@0: return (void*)::CreateWindowExW(mIsRTL ? WS_EX_LAYOUTRTL : 0, michael@0: className.get(), michael@0: L"", michael@0: WS_CHILD, michael@0: CW_USEDEFAULT, michael@0: CW_USEDEFAULT, michael@0: CW_USEDEFAULT, michael@0: CW_USEDEFAULT, michael@0: mWnd, michael@0: nullptr, michael@0: nsToolkit::mDllInstance, michael@0: nullptr); michael@0: case NS_NATIVE_PLUGIN_PORT: michael@0: case NS_NATIVE_WIDGET: michael@0: case NS_NATIVE_WINDOW: michael@0: case NS_NATIVE_SHAREABLE_WINDOW: michael@0: return (void*)mWnd; michael@0: case NS_NATIVE_GRAPHIC: michael@0: // XXX: This is sleezy!! Remember to Release the DC after using it! michael@0: #ifdef MOZ_XUL michael@0: return (void*)(eTransparencyTransparent == mTransparencyMode) ? michael@0: mMemoryDC : ::GetDC(mWnd); michael@0: #else michael@0: return (void*)::GetDC(mWnd); michael@0: #endif michael@0: michael@0: case NS_NATIVE_TSF_THREAD_MGR: michael@0: case NS_NATIVE_TSF_CATEGORY_MGR: michael@0: case NS_NATIVE_TSF_DISPLAY_ATTR_MGR: michael@0: return IMEHandler::GetNativeData(aDataType); michael@0: michael@0: default: michael@0: break; michael@0: } michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: // Free some native data according to aDataType michael@0: void nsWindow::FreeNativeData(void * data, uint32_t aDataType) michael@0: { michael@0: switch (aDataType) michael@0: { michael@0: case NS_NATIVE_GRAPHIC: michael@0: #ifdef MOZ_XUL michael@0: if (eTransparencyTransparent != mTransparencyMode) michael@0: ::ReleaseDC(mWnd, (HDC)data); michael@0: #else michael@0: ::ReleaseDC(mWnd, (HDC)data); michael@0: #endif michael@0: break; michael@0: case NS_NATIVE_WIDGET: michael@0: case NS_NATIVE_WINDOW: michael@0: case NS_NATIVE_PLUGIN_PORT: michael@0: break; michael@0: default: michael@0: break; michael@0: } michael@0: } michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: nsIWidget::SetTitle michael@0: * michael@0: * Set the main windows title text. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: NS_METHOD nsWindow::SetTitle(const nsAString& aTitle) michael@0: { michael@0: const nsString& strTitle = PromiseFlatString(aTitle); michael@0: ::SendMessageW(mWnd, WM_SETTEXT, (WPARAM)0, (LPARAM)(LPCWSTR)strTitle.get()); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: nsIWidget::SetIcon michael@0: * michael@0: * Set the main windows icon. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: NS_METHOD nsWindow::SetIcon(const nsAString& aIconSpec) michael@0: { michael@0: // Assume the given string is a local identifier for an icon file. michael@0: michael@0: nsCOMPtr iconFile; michael@0: ResolveIconName(aIconSpec, NS_LITERAL_STRING(".ico"), michael@0: getter_AddRefs(iconFile)); michael@0: if (!iconFile) michael@0: return NS_OK; // not an error if icon is not found michael@0: michael@0: nsAutoString iconPath; michael@0: iconFile->GetPath(iconPath); michael@0: michael@0: // XXX this should use MZLU (see bug 239279) michael@0: michael@0: ::SetLastError(0); michael@0: michael@0: HICON bigIcon = (HICON)::LoadImageW(nullptr, michael@0: (LPCWSTR)iconPath.get(), michael@0: IMAGE_ICON, michael@0: ::GetSystemMetrics(SM_CXICON), michael@0: ::GetSystemMetrics(SM_CYICON), michael@0: LR_LOADFROMFILE ); michael@0: HICON smallIcon = (HICON)::LoadImageW(nullptr, michael@0: (LPCWSTR)iconPath.get(), michael@0: IMAGE_ICON, michael@0: ::GetSystemMetrics(SM_CXSMICON), michael@0: ::GetSystemMetrics(SM_CYSMICON), michael@0: LR_LOADFROMFILE ); michael@0: michael@0: if (bigIcon) { michael@0: HICON icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)bigIcon); michael@0: if (icon) michael@0: ::DestroyIcon(icon); michael@0: mIconBig = bigIcon; michael@0: } michael@0: #ifdef DEBUG_SetIcon michael@0: else { michael@0: NS_LossyConvertUTF16toASCII cPath(iconPath); michael@0: PR_LOG(gWindowsLog, PR_LOG_ALWAYS, michael@0: ("\nIcon load error; icon=%s, rc=0x%08X\n\n", michael@0: cPath.get(), ::GetLastError())); michael@0: } michael@0: #endif michael@0: if (smallIcon) { michael@0: HICON icon = (HICON) ::SendMessageW(mWnd, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)smallIcon); michael@0: if (icon) michael@0: ::DestroyIcon(icon); michael@0: mIconSmall = smallIcon; michael@0: } michael@0: #ifdef DEBUG_SetIcon michael@0: else { michael@0: NS_LossyConvertUTF16toASCII cPath(iconPath); michael@0: PR_LOG(gWindowsLog, PR_LOG_ALWAYS, michael@0: ("\nSmall icon load error; icon=%s, rc=0x%08X\n\n", michael@0: cPath.get(), ::GetLastError())); michael@0: } michael@0: #endif michael@0: return NS_OK; michael@0: } michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: nsIWidget::WidgetToScreenOffset michael@0: * michael@0: * Return this widget's origin in screen coordinates. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: nsIntPoint nsWindow::WidgetToScreenOffset() michael@0: { michael@0: POINT point; michael@0: point.x = 0; michael@0: point.y = 0; michael@0: ::ClientToScreen(mWnd, &point); michael@0: return nsIntPoint(point.x, point.y); michael@0: } michael@0: michael@0: nsIntSize nsWindow::ClientToWindowSize(const nsIntSize& aClientSize) michael@0: { michael@0: if (mWindowType == eWindowType_popup && !IsPopupWithTitleBar()) michael@0: return aClientSize; michael@0: michael@0: // just use (200, 200) as the position michael@0: RECT r; michael@0: r.left = 200; michael@0: r.top = 200; michael@0: r.right = 200 + aClientSize.width; michael@0: r.bottom = 200 + aClientSize.height; michael@0: ::AdjustWindowRectEx(&r, WindowStyle(), false, WindowExStyle()); michael@0: michael@0: return nsIntSize(r.right - r.left, r.bottom - r.top); michael@0: } michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: nsIWidget::EnableDragDrop michael@0: * michael@0: * Enables/Disables drag and drop of files on this widget. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: NS_METHOD nsWindow::EnableDragDrop(bool aEnable) michael@0: { michael@0: NS_ASSERTION(mWnd, "nsWindow::EnableDragDrop() called after Destroy()"); michael@0: michael@0: nsresult rv = NS_ERROR_FAILURE; michael@0: if (aEnable) { michael@0: if (nullptr == mNativeDragTarget) { michael@0: mNativeDragTarget = new nsNativeDragTarget(this); michael@0: if (nullptr != mNativeDragTarget) { michael@0: mNativeDragTarget->AddRef(); michael@0: if (S_OK == ::CoLockObjectExternal((LPUNKNOWN)mNativeDragTarget,TRUE,FALSE)) { michael@0: if (S_OK == ::RegisterDragDrop(mWnd, (LPDROPTARGET)mNativeDragTarget)) { michael@0: rv = NS_OK; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } else { michael@0: if (nullptr != mWnd && nullptr != mNativeDragTarget) { michael@0: ::RevokeDragDrop(mWnd); michael@0: if (S_OK == ::CoLockObjectExternal((LPUNKNOWN)mNativeDragTarget, FALSE, TRUE)) { michael@0: rv = NS_OK; michael@0: } michael@0: mNativeDragTarget->DragCancel(); michael@0: NS_RELEASE(mNativeDragTarget); michael@0: } michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: nsIWidget::CaptureMouse michael@0: * michael@0: * Enables/Disables system mouse capture. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: NS_METHOD nsWindow::CaptureMouse(bool aCapture) michael@0: { michael@0: if (!nsToolkit::gMouseTrailer) { michael@0: NS_ERROR("nsWindow::CaptureMouse called after nsToolkit destroyed"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (aCapture) { michael@0: nsToolkit::gMouseTrailer->SetCaptureWindow(mWnd); michael@0: ::SetCapture(mWnd); michael@0: } else { michael@0: nsToolkit::gMouseTrailer->SetCaptureWindow(nullptr); michael@0: ::ReleaseCapture(); michael@0: } michael@0: sIsInMouseCapture = aCapture; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: nsIWidget::CaptureRollupEvents michael@0: * michael@0: * Dealing with event rollup on destroy for popups. Enables & michael@0: * Disables system capture of any and all events that would michael@0: * cause a dropdown to be rolled up. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: NS_IMETHODIMP nsWindow::CaptureRollupEvents(nsIRollupListener * aListener, michael@0: bool aDoCapture) michael@0: { michael@0: if (aDoCapture) { michael@0: gRollupListener = aListener; michael@0: if (!sMsgFilterHook && !sCallProcHook && !sCallMouseHook) { michael@0: RegisterSpecialDropdownHooks(); michael@0: } michael@0: sProcessHook = true; michael@0: } else { michael@0: gRollupListener = nullptr; michael@0: sProcessHook = false; michael@0: UnregisterSpecialDropdownHooks(); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: nsIWidget::GetAttention michael@0: * michael@0: * Bring this window to the user's attention. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: // Draw user's attention to this window until it comes to foreground. michael@0: NS_IMETHODIMP michael@0: nsWindow::GetAttention(int32_t aCycleCount) michael@0: { michael@0: // Got window? michael@0: if (!mWnd) michael@0: return NS_ERROR_NOT_INITIALIZED; michael@0: michael@0: HWND flashWnd = WinUtils::GetTopLevelHWND(mWnd, false, false); michael@0: HWND fgWnd = ::GetForegroundWindow(); michael@0: // Don't flash if the flash count is 0 or if the foreground window is our michael@0: // window handle or that of our owned-most window. michael@0: if (aCycleCount == 0 || michael@0: flashWnd == fgWnd || michael@0: flashWnd == WinUtils::GetTopLevelHWND(fgWnd, false, false)) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: DWORD defaultCycleCount = 0; michael@0: ::SystemParametersInfo(SPI_GETFOREGROUNDFLASHCOUNT, 0, &defaultCycleCount, 0); michael@0: michael@0: FLASHWINFO flashInfo = { sizeof(FLASHWINFO), flashWnd, michael@0: FLASHW_ALL, aCycleCount > 0 ? aCycleCount : defaultCycleCount, 0 }; michael@0: ::FlashWindowEx(&flashInfo); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: void nsWindow::StopFlashing() michael@0: { michael@0: HWND flashWnd = mWnd; michael@0: while (HWND ownerWnd = ::GetWindow(flashWnd, GW_OWNER)) { michael@0: flashWnd = ownerWnd; michael@0: } michael@0: michael@0: FLASHWINFO flashInfo = { sizeof(FLASHWINFO), flashWnd, michael@0: FLASHW_STOP, 0, 0 }; michael@0: ::FlashWindowEx(&flashInfo); michael@0: } michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: nsIWidget::HasPendingInputEvent michael@0: * michael@0: * Ask whether there user input events pending. All input events are michael@0: * included, including those not targeted at this nsIwidget instance. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: bool michael@0: nsWindow::HasPendingInputEvent() michael@0: { michael@0: // If there is pending input or the user is currently michael@0: // moving the window then return true. michael@0: // Note: When the user is moving the window WIN32 spins michael@0: // a separate event loop and input events are not michael@0: // reported to the application. michael@0: if (HIWORD(GetQueueStatus(QS_INPUT))) michael@0: return true; michael@0: GUITHREADINFO guiInfo; michael@0: guiInfo.cbSize = sizeof(GUITHREADINFO); michael@0: if (!GetGUIThreadInfo(GetCurrentThreadId(), &guiInfo)) michael@0: return false; michael@0: return GUI_INMOVESIZE == (guiInfo.flags & GUI_INMOVESIZE); michael@0: } michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: nsIWidget::GetLayerManager michael@0: * michael@0: * Get the layer manager associated with this widget. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: struct LayerManagerPrefs { michael@0: LayerManagerPrefs() michael@0: : mAccelerateByDefault(true) michael@0: , mDisableAcceleration(false) michael@0: , mPreferOpenGL(false) michael@0: , mPreferD3D9(false) michael@0: {} michael@0: bool mAccelerateByDefault; michael@0: bool mDisableAcceleration; michael@0: bool mForceAcceleration; michael@0: bool mPreferOpenGL; michael@0: bool mPreferD3D9; michael@0: }; michael@0: michael@0: static void michael@0: GetLayerManagerPrefs(LayerManagerPrefs* aManagerPrefs) michael@0: { michael@0: Preferences::GetBool("layers.acceleration.disabled", michael@0: &aManagerPrefs->mDisableAcceleration); michael@0: Preferences::GetBool("layers.acceleration.force-enabled", michael@0: &aManagerPrefs->mForceAcceleration); michael@0: Preferences::GetBool("layers.prefer-opengl", michael@0: &aManagerPrefs->mPreferOpenGL); michael@0: Preferences::GetBool("layers.prefer-d3d9", michael@0: &aManagerPrefs->mPreferD3D9); michael@0: michael@0: const char *acceleratedEnv = PR_GetEnv("MOZ_ACCELERATED"); michael@0: aManagerPrefs->mAccelerateByDefault = michael@0: aManagerPrefs->mAccelerateByDefault || michael@0: (acceleratedEnv && (*acceleratedEnv != '0')); michael@0: michael@0: bool safeMode = false; michael@0: nsCOMPtr xr = do_GetService("@mozilla.org/xre/runtime;1"); michael@0: if (xr) michael@0: xr->GetInSafeMode(&safeMode); michael@0: aManagerPrefs->mDisableAcceleration = michael@0: aManagerPrefs->mDisableAcceleration || safeMode; michael@0: } michael@0: michael@0: LayerManager* michael@0: nsWindow::GetLayerManager(PLayerTransactionChild* aShadowManager, michael@0: LayersBackend aBackendHint, michael@0: LayerManagerPersistence aPersistence, michael@0: bool* aAllowRetaining) michael@0: { michael@0: if (aAllowRetaining) { michael@0: *aAllowRetaining = true; michael@0: } michael@0: michael@0: #ifdef MOZ_ENABLE_D3D10_LAYER michael@0: if (mLayerManager) { michael@0: if (mLayerManager->GetBackendType() == LayersBackend::LAYERS_D3D10) michael@0: { michael@0: LayerManagerD3D10 *layerManagerD3D10 = michael@0: static_cast(mLayerManager.get()); michael@0: if (layerManagerD3D10->device() != michael@0: gfxWindowsPlatform::GetPlatform()->GetD3D10Device()) michael@0: { michael@0: MOZ_ASSERT(!mLayerManager->IsInTransaction()); michael@0: michael@0: mLayerManager->Destroy(); michael@0: mLayerManager = nullptr; michael@0: } michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: RECT windowRect; michael@0: ::GetClientRect(mWnd, &windowRect); michael@0: michael@0: // Try OMTC first. michael@0: if (!mLayerManager && ShouldUseOffMainThreadCompositing()) { michael@0: // e10s uses the parameter to pass in the shadow manager from the TabChild michael@0: // so we don't expect to see it there since this doesn't support e10s. michael@0: NS_ASSERTION(aShadowManager == nullptr, "Async Compositor not supported with e10s"); michael@0: CreateCompositor(); michael@0: } michael@0: michael@0: if (!mLayerManager || michael@0: (!sAllowD3D9 && aPersistence == LAYER_MANAGER_PERSISTENT && michael@0: mLayerManager->GetBackendType() == LayersBackend::LAYERS_BASIC && michael@0: !ShouldUseOffMainThreadCompositing())) { michael@0: // If D3D9 is not currently allowed but the permanent manager is required, michael@0: // -and- we're currently using basic layers, run through this check. michael@0: LayerManagerPrefs prefs; michael@0: GetLayerManagerPrefs(&prefs); michael@0: michael@0: /* We don't currently support using an accelerated layer manager with michael@0: * transparent windows so don't even try. I'm also not sure if we even michael@0: * want to support this case. See bug #593471 */ michael@0: if (eTransparencyTransparent == mTransparencyMode || michael@0: prefs.mDisableAcceleration || michael@0: windowRect.right - windowRect.left > MAX_ACCELERATED_DIMENSION || michael@0: windowRect.bottom - windowRect.top > MAX_ACCELERATED_DIMENSION) michael@0: mUseLayersAcceleration = false; michael@0: else if (prefs.mAccelerateByDefault) michael@0: mUseLayersAcceleration = true; michael@0: michael@0: if (mUseLayersAcceleration) { michael@0: if (aPersistence == LAYER_MANAGER_PERSISTENT && !sAllowD3D9) { michael@0: MOZ_ASSERT(!mLayerManager || !mLayerManager->IsInTransaction()); michael@0: michael@0: // This will clear out our existing layer manager if we have one since michael@0: // if we hit this with a LayerManager we're always using BasicLayers. michael@0: nsToolkit::StartAllowingD3D9(); michael@0: } michael@0: michael@0: #ifdef MOZ_ENABLE_D3D10_LAYER michael@0: if (!prefs.mPreferD3D9 && !prefs.mPreferOpenGL) { michael@0: nsRefPtr layerManager = michael@0: new LayerManagerD3D10(this); michael@0: if (layerManager->Initialize(prefs.mForceAcceleration)) { michael@0: mLayerManager = layerManager; michael@0: } michael@0: } michael@0: #endif michael@0: #ifdef MOZ_ENABLE_D3D9_LAYER michael@0: if (!prefs.mPreferOpenGL && !mLayerManager && sAllowD3D9) { michael@0: nsRefPtr layerManager = michael@0: new LayerManagerD3D9(this); michael@0: if (layerManager->Initialize(prefs.mForceAcceleration)) { michael@0: mLayerManager = layerManager; michael@0: } michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: // Fall back to software if we couldn't use any hardware backends. michael@0: if (!mLayerManager) { michael@0: mLayerManager = CreateBasicLayerManager(); michael@0: } michael@0: } michael@0: michael@0: NS_ASSERTION(mLayerManager, "Couldn't provide a valid layer manager."); michael@0: michael@0: return mLayerManager; michael@0: } michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: nsIWidget::GetThebesSurface michael@0: * michael@0: * Get the Thebes surface associated with this widget. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: gfxASurface *nsWindow::GetThebesSurface() michael@0: { michael@0: if (mPaintDC) michael@0: return (new gfxWindowsSurface(mPaintDC)); michael@0: michael@0: uint32_t flags = gfxWindowsSurface::FLAG_TAKE_DC; michael@0: if (mTransparencyMode != eTransparencyOpaque) { michael@0: flags |= gfxWindowsSurface::FLAG_IS_TRANSPARENT; michael@0: } michael@0: return (new gfxWindowsSurface(mWnd, flags)); michael@0: } michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: nsIWidget::OnDefaultButtonLoaded michael@0: * michael@0: * Called after the dialog is loaded and it has a default button. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::OnDefaultButtonLoaded(const nsIntRect &aButtonRect) michael@0: { michael@0: if (aButtonRect.IsEmpty()) michael@0: return NS_OK; michael@0: michael@0: // Don't snap when we are not active. michael@0: HWND activeWnd = ::GetActiveWindow(); michael@0: if (activeWnd != ::GetForegroundWindow() || michael@0: WinUtils::GetTopLevelHWND(mWnd, true) != michael@0: WinUtils::GetTopLevelHWND(activeWnd, true)) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool isAlwaysSnapCursor = michael@0: Preferences::GetBool("ui.cursor_snapping.always_enabled", false); michael@0: michael@0: if (!isAlwaysSnapCursor) { michael@0: BOOL snapDefaultButton; michael@0: if (!::SystemParametersInfo(SPI_GETSNAPTODEFBUTTON, 0, michael@0: &snapDefaultButton, 0) || !snapDefaultButton) michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsIntRect widgetRect; michael@0: nsresult rv = GetScreenBounds(widgetRect); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: nsIntRect buttonRect(aButtonRect + widgetRect.TopLeft()); michael@0: michael@0: nsIntPoint centerOfButton(buttonRect.x + buttonRect.width / 2, michael@0: buttonRect.y + buttonRect.height / 2); michael@0: // The center of the button can be outside of the widget. michael@0: // E.g., it could be hidden by scrolling. michael@0: if (!widgetRect.Contains(centerOfButton)) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (!::SetCursorPos(centerOfButton.x, centerOfButton.y)) { michael@0: NS_ERROR("SetCursorPos failed"); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::OverrideSystemMouseScrollSpeed(double aOriginalDeltaX, michael@0: double aOriginalDeltaY, michael@0: double& aOverriddenDeltaX, michael@0: double& aOverriddenDeltaY) michael@0: { michael@0: // The default vertical and horizontal scrolling speed is 3, this is defined michael@0: // on the document of SystemParametersInfo in MSDN. michael@0: const uint32_t kSystemDefaultScrollingSpeed = 3; michael@0: michael@0: double absOriginDeltaX = Abs(aOriginalDeltaX); michael@0: double absOriginDeltaY = Abs(aOriginalDeltaY); michael@0: michael@0: // Compute the simple overridden speed. michael@0: double absComputedOverriddenDeltaX, absComputedOverriddenDeltaY; michael@0: nsresult rv = michael@0: nsBaseWidget::OverrideSystemMouseScrollSpeed(absOriginDeltaX, michael@0: absOriginDeltaY, michael@0: absComputedOverriddenDeltaX, michael@0: absComputedOverriddenDeltaY); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: aOverriddenDeltaX = aOriginalDeltaX; michael@0: aOverriddenDeltaY = aOriginalDeltaY; michael@0: michael@0: if (absComputedOverriddenDeltaX == absOriginDeltaX && michael@0: absComputedOverriddenDeltaY == absOriginDeltaY) { michael@0: // We don't override now. michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Otherwise, we should check whether the user customized the system settings michael@0: // or not. If the user did it, we should respect the will. michael@0: UINT systemSpeed; michael@0: if (!::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &systemSpeed, 0)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: // The default vertical scrolling speed is 3, this is defined on the document michael@0: // of SystemParametersInfo in MSDN. michael@0: if (systemSpeed != kSystemDefaultScrollingSpeed) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Only Vista and later, Windows has the system setting of horizontal michael@0: // scrolling by the mouse wheel. michael@0: if (IsVistaOrLater()) { michael@0: if (!::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &systemSpeed, 0)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: // The default horizontal scrolling speed is 3, this is defined on the michael@0: // document of SystemParametersInfo in MSDN. michael@0: if (systemSpeed != kSystemDefaultScrollingSpeed) { michael@0: return NS_OK; michael@0: } michael@0: } michael@0: michael@0: // Limit the overridden delta value from the system settings. The mouse michael@0: // driver might accelerate the scrolling speed already. If so, we shouldn't michael@0: // override the scrolling speed for preventing the unexpected high speed michael@0: // scrolling. michael@0: double absDeltaLimitX, absDeltaLimitY; michael@0: rv = michael@0: nsBaseWidget::OverrideSystemMouseScrollSpeed(kSystemDefaultScrollingSpeed, michael@0: kSystemDefaultScrollingSpeed, michael@0: absDeltaLimitX, michael@0: absDeltaLimitY); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // If the given delta is larger than our computed limitation value, the delta michael@0: // was accelerated by the mouse driver. So, we should do nothing here. michael@0: if (absDeltaLimitX <= absOriginDeltaX || absDeltaLimitY <= absOriginDeltaY) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: aOverriddenDeltaX = std::min(absComputedOverriddenDeltaX, absDeltaLimitX); michael@0: aOverriddenDeltaY = std::min(absComputedOverriddenDeltaY, absDeltaLimitY); michael@0: michael@0: if (aOriginalDeltaX < 0) { michael@0: aOverriddenDeltaX *= -1; michael@0: } michael@0: if (aOriginalDeltaY < 0) { michael@0: aOverriddenDeltaY *= -1; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: mozilla::TemporaryRef michael@0: nsWindow::StartRemoteDrawing() michael@0: { michael@0: MOZ_ASSERT(!mCompositeDC); michael@0: NS_ASSERTION(IsRenderMode(gfxWindowsPlatform::RENDER_DIRECT2D) || michael@0: IsRenderMode(gfxWindowsPlatform::RENDER_GDI), michael@0: "Unexpected render mode for remote drawing"); michael@0: michael@0: HDC dc = (HDC)GetNativeData(NS_NATIVE_GRAPHIC); michael@0: nsRefPtr surf; michael@0: michael@0: if (mTransparencyMode == eTransparencyTransparent) { michael@0: if (!mTransparentSurface) { michael@0: SetupTranslucentWindowMemoryBitmap(mTransparencyMode); michael@0: } michael@0: if (mTransparentSurface) { michael@0: surf = mTransparentSurface; michael@0: } michael@0: } michael@0: michael@0: if (!surf) { michael@0: if (!dc) { michael@0: return nullptr; michael@0: } michael@0: uint32_t flags = (mTransparencyMode == eTransparencyOpaque) ? 0 : michael@0: gfxWindowsSurface::FLAG_IS_TRANSPARENT; michael@0: surf = new gfxWindowsSurface(dc, flags); michael@0: } michael@0: michael@0: mozilla::gfx::IntSize size(surf->GetSize().width, surf->GetSize().height); michael@0: if (size.width <= 0 || size.height <= 0) { michael@0: if (dc) { michael@0: FreeNativeData(dc, NS_NATIVE_GRAPHIC); michael@0: } michael@0: return nullptr; michael@0: } michael@0: michael@0: MOZ_ASSERT(!mCompositeDC); michael@0: mCompositeDC = dc; michael@0: michael@0: return mozilla::gfx::Factory::CreateDrawTargetForCairoSurface(surf->CairoSurface(), size); michael@0: } michael@0: michael@0: void michael@0: nsWindow::EndRemoteDrawing() michael@0: { michael@0: if (mTransparencyMode == eTransparencyTransparent) { michael@0: MOZ_ASSERT(IsRenderMode(gfxWindowsPlatform::RENDER_DIRECT2D) michael@0: || mTransparentSurface); michael@0: UpdateTranslucentWindow(); michael@0: } michael@0: if (mCompositeDC) { michael@0: FreeNativeData(mCompositeDC, NS_NATIVE_GRAPHIC); michael@0: } michael@0: mCompositeDC = nullptr; michael@0: } michael@0: michael@0: void michael@0: nsWindow::UpdateThemeGeometries(const nsTArray& aThemeGeometries) michael@0: { michael@0: nsIntRegion clearRegion; michael@0: for (size_t i = 0; i < aThemeGeometries.Length(); i++) { michael@0: if ((aThemeGeometries[i].mWidgetType == NS_THEME_WINDOW_BUTTON_BOX || michael@0: aThemeGeometries[i].mWidgetType == NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED) && michael@0: nsUXThemeData::CheckForCompositor()) michael@0: { michael@0: nsIntRect bounds = aThemeGeometries[i].mRect; michael@0: clearRegion = nsIntRect(bounds.X(), bounds.Y(), bounds.Width(), bounds.Height() - 2.0); michael@0: clearRegion.Or(clearRegion, nsIntRect(bounds.X() + 1.0, bounds.YMost() - 2.0, bounds.Width() - 1.0, 1.0)); michael@0: clearRegion.Or(clearRegion, nsIntRect(bounds.X() + 2.0, bounds.YMost() - 1.0, bounds.Width() - 3.0, 1.0)); michael@0: } michael@0: } michael@0: michael@0: nsRefPtr layerManager = GetLayerManager(); michael@0: if (layerManager) { michael@0: layerManager->SetRegionToClear(clearRegion); michael@0: } michael@0: } michael@0: michael@0: /************************************************************** michael@0: ************************************************************** michael@0: ** michael@0: ** BLOCK: Moz Events michael@0: ** michael@0: ** Moz GUI event management. michael@0: ** michael@0: ************************************************************** michael@0: **************************************************************/ michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: Mozilla event initialization michael@0: * michael@0: * Helpers for initializing moz events. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: // Event intialization michael@0: void nsWindow::InitEvent(WidgetGUIEvent& event, nsIntPoint* aPoint) michael@0: { michael@0: if (nullptr == aPoint) { // use the point from the event michael@0: // get the message position in client coordinates michael@0: if (mWnd != nullptr) { michael@0: michael@0: DWORD pos = ::GetMessagePos(); michael@0: POINT cpos; michael@0: michael@0: cpos.x = GET_X_LPARAM(pos); michael@0: cpos.y = GET_Y_LPARAM(pos); michael@0: michael@0: ::ScreenToClient(mWnd, &cpos); michael@0: event.refPoint.x = cpos.x; michael@0: event.refPoint.y = cpos.y; michael@0: } else { michael@0: event.refPoint.x = 0; michael@0: event.refPoint.y = 0; michael@0: } michael@0: } michael@0: else { michael@0: // use the point override if provided michael@0: event.refPoint.x = aPoint->x; michael@0: event.refPoint.y = aPoint->y; michael@0: } michael@0: michael@0: event.time = ::GetMessageTime(); michael@0: } michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: Moz event dispatch helpers michael@0: * michael@0: * Helpers for dispatching different types of moz events. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: // Main event dispatch. Invokes callback and ProcessEvent method on michael@0: // Event Listener object. Part of nsIWidget. michael@0: NS_IMETHODIMP nsWindow::DispatchEvent(WidgetGUIEvent* event, michael@0: nsEventStatus& aStatus) michael@0: { michael@0: #ifdef WIDGET_DEBUG_OUTPUT michael@0: debug_DumpEvent(stdout, michael@0: event->widget, michael@0: event, michael@0: nsAutoCString("something"), michael@0: (int32_t) mWnd); michael@0: #endif // WIDGET_DEBUG_OUTPUT michael@0: michael@0: aStatus = nsEventStatus_eIgnore; michael@0: michael@0: // Top level windows can have a view attached which requires events be sent michael@0: // to the underlying base window and the view. Added when we combined the michael@0: // base chrome window with the main content child for nc client area (title michael@0: // bar) rendering. michael@0: if (mAttachedWidgetListener) { michael@0: aStatus = mAttachedWidgetListener->HandleEvent(event, mUseAttachedEvents); michael@0: } michael@0: else if (mWidgetListener) { michael@0: aStatus = mWidgetListener->HandleEvent(event, mUseAttachedEvents); michael@0: } michael@0: michael@0: // the window can be destroyed during processing of seemingly innocuous events like, say, michael@0: // mousedowns due to the magic of scripting. mousedowns will return nsEventStatus_eIgnore, michael@0: // which causes problems with the deleted window. therefore: michael@0: if (mOnDestroyCalled) michael@0: aStatus = nsEventStatus_eConsumeNoDefault; michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool nsWindow::DispatchStandardEvent(uint32_t aMsg) michael@0: { michael@0: WidgetGUIEvent event(true, aMsg, this); michael@0: InitEvent(event); michael@0: michael@0: bool result = DispatchWindowEvent(&event); michael@0: return result; michael@0: } michael@0: michael@0: bool nsWindow::DispatchKeyboardEvent(WidgetGUIEvent* event) michael@0: { michael@0: nsEventStatus status; michael@0: DispatchEvent(event, status); michael@0: return ConvertStatus(status); michael@0: } michael@0: michael@0: bool nsWindow::DispatchScrollEvent(WidgetGUIEvent* event) michael@0: { michael@0: nsEventStatus status; michael@0: DispatchEvent(event, status); michael@0: return ConvertStatus(status); michael@0: } michael@0: michael@0: bool nsWindow::DispatchWindowEvent(WidgetGUIEvent* event) michael@0: { michael@0: nsEventStatus status; michael@0: DispatchEvent(event, status); michael@0: return ConvertStatus(status); michael@0: } michael@0: michael@0: bool nsWindow::DispatchWindowEvent(WidgetGUIEvent* event, michael@0: nsEventStatus& aStatus) michael@0: { michael@0: DispatchEvent(event, aStatus); michael@0: return ConvertStatus(aStatus); michael@0: } michael@0: michael@0: // Recursively dispatch synchronous paints for nsIWidget michael@0: // descendants with invalidated rectangles. michael@0: BOOL CALLBACK nsWindow::DispatchStarvedPaints(HWND aWnd, LPARAM aMsg) michael@0: { michael@0: LONG_PTR proc = ::GetWindowLongPtrW(aWnd, GWLP_WNDPROC); michael@0: if (proc == (LONG_PTR)&nsWindow::WindowProc) { michael@0: // its one of our windows so check to see if it has a michael@0: // invalidated rect. If it does. Dispatch a synchronous michael@0: // paint. michael@0: if (GetUpdateRect(aWnd, nullptr, FALSE)) michael@0: VERIFY(::UpdateWindow(aWnd)); michael@0: } michael@0: return TRUE; michael@0: } michael@0: michael@0: // Check for pending paints and dispatch any pending paint michael@0: // messages for any nsIWidget which is a descendant of the michael@0: // top-level window that *this* window is embedded within. michael@0: // michael@0: // Note: We do not dispatch pending paint messages for non michael@0: // nsIWidget managed windows. michael@0: void nsWindow::DispatchPendingEvents() michael@0: { michael@0: if (mPainting) { michael@0: NS_WARNING("We were asked to dispatch pending events during painting, " michael@0: "denying since that's unsafe."); michael@0: return; michael@0: } michael@0: michael@0: // We need to ensure that reflow events do not get starved. michael@0: // At the same time, we don't want to recurse through here michael@0: // as that would prevent us from dispatching starved paints. michael@0: static int recursionBlocker = 0; michael@0: if (recursionBlocker++ == 0) { michael@0: NS_ProcessPendingEvents(nullptr, PR_MillisecondsToInterval(100)); michael@0: --recursionBlocker; michael@0: } michael@0: michael@0: // Quickly check to see if there are any paint events pending, michael@0: // but only dispatch them if it has been long enough since the michael@0: // last paint completed. michael@0: if (::GetQueueStatus(QS_PAINT) && michael@0: ((TimeStamp::Now() - mLastPaintEndTime).ToMilliseconds() >= 50)) { michael@0: // Find the top level window. michael@0: HWND topWnd = WinUtils::GetTopLevelHWND(mWnd); michael@0: michael@0: // Dispatch pending paints for topWnd and all its descendant windows. michael@0: // Note: EnumChildWindows enumerates all descendant windows not just michael@0: // the children (but not the window itself). michael@0: nsWindow::DispatchStarvedPaints(topWnd, 0); michael@0: ::EnumChildWindows(topWnd, nsWindow::DispatchStarvedPaints, 0); michael@0: } michael@0: } michael@0: michael@0: bool nsWindow::DispatchPluginEvent(UINT aMessage, michael@0: WPARAM aWParam, michael@0: LPARAM aLParam, michael@0: bool aDispatchPendingEvents) michael@0: { michael@0: bool ret = nsWindowBase::DispatchPluginEvent( michael@0: WinUtils::InitMSG(aMessage, aWParam, aLParam, mWnd)); michael@0: if (aDispatchPendingEvents && !Destroyed()) { michael@0: DispatchPendingEvents(); michael@0: } michael@0: return ret; michael@0: } michael@0: michael@0: // Deal with all sort of mouse event michael@0: bool nsWindow::DispatchMouseEvent(uint32_t aEventType, WPARAM wParam, michael@0: LPARAM lParam, bool aIsContextMenuKey, michael@0: int16_t aButton, uint16_t aInputSource) michael@0: { michael@0: bool result = false; michael@0: michael@0: UserActivity(); michael@0: michael@0: if (!mWidgetListener) { michael@0: return result; michael@0: } michael@0: michael@0: switch (aEventType) { michael@0: case NS_MOUSE_BUTTON_DOWN: michael@0: CaptureMouse(true); michael@0: break; michael@0: michael@0: // NS_MOUSE_MOVE and NS_MOUSE_EXIT are here because we need to make sure capture flag michael@0: // isn't left on after a drag where we wouldn't see a button up message (see bug 324131). michael@0: case NS_MOUSE_BUTTON_UP: michael@0: case NS_MOUSE_MOVE: michael@0: case NS_MOUSE_EXIT: michael@0: if (!(wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) && sIsInMouseCapture) michael@0: CaptureMouse(false); michael@0: break; michael@0: michael@0: default: michael@0: break; michael@0: michael@0: } // switch michael@0: michael@0: nsIntPoint eventPoint; michael@0: eventPoint.x = GET_X_LPARAM(lParam); michael@0: eventPoint.y = GET_Y_LPARAM(lParam); michael@0: michael@0: WidgetMouseEvent event(true, aEventType, this, WidgetMouseEvent::eReal, michael@0: aIsContextMenuKey ? WidgetMouseEvent::eContextMenuKey : michael@0: WidgetMouseEvent::eNormal); michael@0: if (aEventType == NS_CONTEXTMENU && aIsContextMenuKey) { michael@0: nsIntPoint zero(0, 0); michael@0: InitEvent(event, &zero); michael@0: } else { michael@0: InitEvent(event, &eventPoint); michael@0: } michael@0: michael@0: ModifierKeyState modifierKeyState; michael@0: modifierKeyState.InitInputEvent(event); michael@0: event.button = aButton; michael@0: event.inputSource = aInputSource; michael@0: // Convert Mouse events generated by pen device or if mouse not generated from touch michael@0: event.convertToPointer = michael@0: aInputSource == nsIDOMMouseEvent::MOZ_SOURCE_PEN || michael@0: !(WinUtils::GetIsMouseFromTouch(aEventType) && mTouchWindow); michael@0: michael@0: nsIntPoint mpScreen = eventPoint + WidgetToScreenOffset(); michael@0: michael@0: // Suppress mouse moves caused by widget creation michael@0: if (aEventType == NS_MOUSE_MOVE) michael@0: { michael@0: if ((sLastMouseMovePoint.x == mpScreen.x) && (sLastMouseMovePoint.y == mpScreen.y)) michael@0: return result; michael@0: sLastMouseMovePoint.x = mpScreen.x; michael@0: sLastMouseMovePoint.y = mpScreen.y; michael@0: } michael@0: michael@0: bool insideMovementThreshold = (DeprecatedAbs(sLastMousePoint.x - eventPoint.x) < (short)::GetSystemMetrics(SM_CXDOUBLECLK)) && michael@0: (DeprecatedAbs(sLastMousePoint.y - eventPoint.y) < (short)::GetSystemMetrics(SM_CYDOUBLECLK)); michael@0: michael@0: BYTE eventButton; michael@0: switch (aButton) { michael@0: case WidgetMouseEvent::eLeftButton: michael@0: eventButton = VK_LBUTTON; michael@0: break; michael@0: case WidgetMouseEvent::eMiddleButton: michael@0: eventButton = VK_MBUTTON; michael@0: break; michael@0: case WidgetMouseEvent::eRightButton: michael@0: eventButton = VK_RBUTTON; michael@0: break; michael@0: default: michael@0: eventButton = 0; michael@0: break; michael@0: } michael@0: michael@0: // Doubleclicks are used to set the click count, then changed to mousedowns michael@0: // We're going to time double-clicks from mouse *up* to next mouse *down* michael@0: LONG curMsgTime = ::GetMessageTime(); michael@0: michael@0: if (aEventType == NS_MOUSE_DOUBLECLICK) { michael@0: event.message = NS_MOUSE_BUTTON_DOWN; michael@0: event.button = aButton; michael@0: sLastClickCount = 2; michael@0: } michael@0: else if (aEventType == NS_MOUSE_BUTTON_UP) { michael@0: // remember when this happened for the next mouse down michael@0: sLastMousePoint.x = eventPoint.x; michael@0: sLastMousePoint.y = eventPoint.y; michael@0: sLastMouseButton = eventButton; michael@0: } michael@0: else if (aEventType == NS_MOUSE_BUTTON_DOWN) { michael@0: // now look to see if we want to convert this to a double- or triple-click michael@0: if (((curMsgTime - sLastMouseDownTime) < (LONG)::GetDoubleClickTime()) && insideMovementThreshold && michael@0: eventButton == sLastMouseButton) { michael@0: sLastClickCount ++; michael@0: } else { michael@0: // reset the click count, to count *this* click michael@0: sLastClickCount = 1; michael@0: } michael@0: // Set last Click time on MouseDown only michael@0: sLastMouseDownTime = curMsgTime; michael@0: } michael@0: else if (aEventType == NS_MOUSE_MOVE && !insideMovementThreshold) { michael@0: sLastClickCount = 0; michael@0: } michael@0: else if (aEventType == NS_MOUSE_EXIT) { michael@0: event.exit = IsTopLevelMouseExit(mWnd) ? michael@0: WidgetMouseEvent::eTopLevel : WidgetMouseEvent::eChild; michael@0: } michael@0: event.clickCount = sLastClickCount; michael@0: michael@0: #ifdef NS_DEBUG_XX michael@0: PR_LOG(gWindowsLog, PR_LOG_ALWAYS, michael@0: ("Msg Time: %d Click Count: %d\n", curMsgTime, event.clickCount)); michael@0: #endif michael@0: michael@0: NPEvent pluginEvent; michael@0: michael@0: switch (aEventType) michael@0: { michael@0: case NS_MOUSE_BUTTON_DOWN: michael@0: switch (aButton) { michael@0: case WidgetMouseEvent::eLeftButton: michael@0: pluginEvent.event = WM_LBUTTONDOWN; michael@0: break; michael@0: case WidgetMouseEvent::eMiddleButton: michael@0: pluginEvent.event = WM_MBUTTONDOWN; michael@0: break; michael@0: case WidgetMouseEvent::eRightButton: michael@0: pluginEvent.event = WM_RBUTTONDOWN; michael@0: break; michael@0: default: michael@0: break; michael@0: } michael@0: break; michael@0: case NS_MOUSE_BUTTON_UP: michael@0: switch (aButton) { michael@0: case WidgetMouseEvent::eLeftButton: michael@0: pluginEvent.event = WM_LBUTTONUP; michael@0: break; michael@0: case WidgetMouseEvent::eMiddleButton: michael@0: pluginEvent.event = WM_MBUTTONUP; michael@0: break; michael@0: case WidgetMouseEvent::eRightButton: michael@0: pluginEvent.event = WM_RBUTTONUP; michael@0: break; michael@0: default: michael@0: break; michael@0: } michael@0: break; michael@0: case NS_MOUSE_DOUBLECLICK: michael@0: switch (aButton) { michael@0: case WidgetMouseEvent::eLeftButton: michael@0: pluginEvent.event = WM_LBUTTONDBLCLK; michael@0: break; michael@0: case WidgetMouseEvent::eMiddleButton: michael@0: pluginEvent.event = WM_MBUTTONDBLCLK; michael@0: break; michael@0: case WidgetMouseEvent::eRightButton: michael@0: pluginEvent.event = WM_RBUTTONDBLCLK; michael@0: break; michael@0: default: michael@0: break; michael@0: } michael@0: break; michael@0: case NS_MOUSE_MOVE: michael@0: pluginEvent.event = WM_MOUSEMOVE; michael@0: break; michael@0: case NS_MOUSE_EXIT: michael@0: pluginEvent.event = WM_MOUSELEAVE; michael@0: break; michael@0: default: michael@0: pluginEvent.event = WM_NULL; michael@0: break; michael@0: } michael@0: michael@0: pluginEvent.wParam = wParam; // plugins NEED raw OS event flags! michael@0: pluginEvent.lParam = lParam; michael@0: michael@0: event.pluginEvent = (void *)&pluginEvent; michael@0: michael@0: // call the event callback michael@0: if (mWidgetListener) { michael@0: if (nsToolkit::gMouseTrailer) michael@0: nsToolkit::gMouseTrailer->Disable(); michael@0: if (aEventType == NS_MOUSE_MOVE) { michael@0: if (nsToolkit::gMouseTrailer && !sIsInMouseCapture) { michael@0: nsToolkit::gMouseTrailer->SetMouseTrailerWindow(mWnd); michael@0: } michael@0: nsIntRect rect; michael@0: GetBounds(rect); michael@0: rect.x = 0; michael@0: rect.y = 0; michael@0: michael@0: if (rect.Contains(LayoutDeviceIntPoint::ToUntyped(event.refPoint))) { michael@0: if (sCurrentWindow == nullptr || sCurrentWindow != this) { michael@0: if ((nullptr != sCurrentWindow) && (!sCurrentWindow->mInDtor)) { michael@0: LPARAM pos = sCurrentWindow->lParamToClient(lParamToScreen(lParam)); michael@0: sCurrentWindow->DispatchMouseEvent(NS_MOUSE_EXIT, wParam, pos, false, michael@0: WidgetMouseEvent::eLeftButton, michael@0: aInputSource); michael@0: } michael@0: sCurrentWindow = this; michael@0: if (!mInDtor) { michael@0: LPARAM pos = sCurrentWindow->lParamToClient(lParamToScreen(lParam)); michael@0: sCurrentWindow->DispatchMouseEvent(NS_MOUSE_ENTER, wParam, pos, false, michael@0: WidgetMouseEvent::eLeftButton, michael@0: aInputSource); michael@0: } michael@0: } michael@0: } michael@0: } else if (aEventType == NS_MOUSE_EXIT) { michael@0: if (sCurrentWindow == this) { michael@0: sCurrentWindow = nullptr; michael@0: } michael@0: } michael@0: michael@0: result = DispatchWindowEvent(&event); michael@0: michael@0: if (nsToolkit::gMouseTrailer) michael@0: nsToolkit::gMouseTrailer->Enable(); michael@0: michael@0: // Release the widget with NS_IF_RELEASE() just in case michael@0: // the context menu key code in EventListenerManager::HandleEvent() michael@0: // released it already. michael@0: return result; michael@0: } michael@0: michael@0: return result; michael@0: } michael@0: michael@0: void nsWindow::DispatchFocusToTopLevelWindow(bool aIsActivate) michael@0: { michael@0: if (aIsActivate) michael@0: sJustGotActivate = false; michael@0: sJustGotDeactivate = false; michael@0: michael@0: // retrive the toplevel window or dialog michael@0: HWND curWnd = mWnd; michael@0: HWND toplevelWnd = nullptr; michael@0: while (curWnd) { michael@0: toplevelWnd = curWnd; michael@0: michael@0: nsWindow *win = WinUtils::GetNSWindowPtr(curWnd); michael@0: if (win) { michael@0: nsWindowType wintype = win->WindowType(); michael@0: if (wintype == eWindowType_toplevel || wintype == eWindowType_dialog) michael@0: break; michael@0: } michael@0: michael@0: curWnd = ::GetParent(curWnd); // Parent or owner (if has no parent) michael@0: } michael@0: michael@0: if (toplevelWnd) { michael@0: nsWindow *win = WinUtils::GetNSWindowPtr(toplevelWnd); michael@0: if (win && win->mWidgetListener) { michael@0: if (aIsActivate) { michael@0: win->mWidgetListener->WindowActivated(); michael@0: } else { michael@0: if (!win->BlurEventsSuppressed()) { michael@0: win->mWidgetListener->WindowDeactivated(); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: bool nsWindow::IsTopLevelMouseExit(HWND aWnd) michael@0: { michael@0: DWORD pos = ::GetMessagePos(); michael@0: POINT mp; michael@0: mp.x = GET_X_LPARAM(pos); michael@0: mp.y = GET_Y_LPARAM(pos); michael@0: HWND mouseWnd = ::WindowFromPoint(mp); michael@0: michael@0: // WinUtils::GetTopLevelHWND() will return a HWND for the window frame michael@0: // (which includes the non-client area). If the mouse has moved into michael@0: // the non-client area, we should treat it as a top-level exit. michael@0: HWND mouseTopLevel = WinUtils::GetTopLevelHWND(mouseWnd); michael@0: if (mouseWnd == mouseTopLevel) michael@0: return true; michael@0: michael@0: return WinUtils::GetTopLevelHWND(aWnd) != mouseTopLevel; michael@0: } michael@0: michael@0: bool nsWindow::BlurEventsSuppressed() michael@0: { michael@0: // are they suppressed in this window? michael@0: if (mBlurSuppressLevel > 0) michael@0: return true; michael@0: michael@0: // are they suppressed by any container widget? michael@0: HWND parentWnd = ::GetParent(mWnd); michael@0: if (parentWnd) { michael@0: nsWindow *parent = WinUtils::GetNSWindowPtr(parentWnd); michael@0: if (parent) michael@0: return parent->BlurEventsSuppressed(); michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: // In some circumstances (opening dependent windows) it makes more sense michael@0: // (and fixes a crash bug) to not blur the parent window. Called from michael@0: // nsFilePicker. michael@0: void nsWindow::SuppressBlurEvents(bool aSuppress) michael@0: { michael@0: if (aSuppress) michael@0: ++mBlurSuppressLevel; // for this widget michael@0: else { michael@0: NS_ASSERTION(mBlurSuppressLevel > 0, "unbalanced blur event suppression"); michael@0: if (mBlurSuppressLevel > 0) michael@0: --mBlurSuppressLevel; michael@0: } michael@0: } michael@0: michael@0: bool nsWindow::ConvertStatus(nsEventStatus aStatus) michael@0: { michael@0: return aStatus == nsEventStatus_eConsumeNoDefault; michael@0: } michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: IPC michael@0: * michael@0: * IPC related helpers. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: // static michael@0: bool michael@0: nsWindow::IsAsyncResponseEvent(UINT aMsg, LRESULT& aResult) michael@0: { michael@0: switch(aMsg) { michael@0: case WM_SETFOCUS: michael@0: case WM_KILLFOCUS: michael@0: case WM_ENABLE: michael@0: case WM_WINDOWPOSCHANGING: michael@0: case WM_WINDOWPOSCHANGED: michael@0: case WM_PARENTNOTIFY: michael@0: case WM_ACTIVATEAPP: michael@0: case WM_NCACTIVATE: michael@0: case WM_ACTIVATE: michael@0: case WM_CHILDACTIVATE: michael@0: case WM_IME_SETCONTEXT: michael@0: case WM_IME_NOTIFY: michael@0: case WM_SHOWWINDOW: michael@0: case WM_CANCELMODE: michael@0: case WM_MOUSEACTIVATE: michael@0: case WM_CONTEXTMENU: michael@0: aResult = 0; michael@0: return true; michael@0: michael@0: case WM_SETTINGCHANGE: michael@0: case WM_SETCURSOR: michael@0: return false; michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: char szBuf[200]; michael@0: sprintf(szBuf, michael@0: "An unhandled ISMEX_SEND message was received during spin loop! (%X)", aMsg); michael@0: NS_WARNING(szBuf); michael@0: #endif michael@0: michael@0: return false; michael@0: } michael@0: michael@0: void michael@0: nsWindow::IPCWindowProcHandler(UINT& msg, WPARAM& wParam, LPARAM& lParam) michael@0: { michael@0: NS_ASSERTION(!mozilla::ipc::MessageChannel::IsPumpingMessages(), michael@0: "Failed to prevent a nonqueued message from running!"); michael@0: michael@0: // Modal UI being displayed in windowless plugins. michael@0: if (mozilla::ipc::MessageChannel::IsSpinLoopActive() && michael@0: (InSendMessageEx(nullptr) & (ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) { michael@0: LRESULT res; michael@0: if (IsAsyncResponseEvent(msg, res)) { michael@0: ReplyMessage(res); michael@0: } michael@0: return; michael@0: } michael@0: michael@0: // Handle certain sync plugin events sent to the parent which michael@0: // trigger ipc calls that result in deadlocks. michael@0: michael@0: DWORD dwResult = 0; michael@0: bool handled = false; michael@0: michael@0: switch(msg) { michael@0: // Windowless flash sending WM_ACTIVATE events to the main window michael@0: // via calls to ShowWindow. michael@0: case WM_ACTIVATE: michael@0: if (lParam != 0 && LOWORD(wParam) == WA_ACTIVE && michael@0: IsWindow((HWND)lParam)) { michael@0: // Check for Adobe Reader X sync activate message from their michael@0: // helper window and ignore. Fixes an annoying focus problem. michael@0: if ((InSendMessageEx(nullptr) & (ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) { michael@0: wchar_t szClass[10]; michael@0: HWND focusWnd = (HWND)lParam; michael@0: if (IsWindowVisible(focusWnd) && michael@0: GetClassNameW(focusWnd, szClass, michael@0: sizeof(szClass)/sizeof(char16_t)) && michael@0: !wcscmp(szClass, L"Edit") && michael@0: !WinUtils::IsOurProcessWindow(focusWnd)) { michael@0: break; michael@0: } michael@0: } michael@0: handled = true; michael@0: } michael@0: break; michael@0: // Plugins taking or losing focus triggering focus app messages. michael@0: case WM_SETFOCUS: michael@0: case WM_KILLFOCUS: michael@0: // Windowed plugins that pass sys key events to defwndproc generate michael@0: // WM_SYSCOMMAND events to the main window. michael@0: case WM_SYSCOMMAND: michael@0: // Windowed plugins that fire context menu selection events to parent michael@0: // windows. michael@0: case WM_CONTEXTMENU: michael@0: // IME events fired as a result of synchronous focus changes michael@0: case WM_IME_SETCONTEXT: michael@0: handled = true; michael@0: break; michael@0: } michael@0: michael@0: if (handled && michael@0: (InSendMessageEx(nullptr) & (ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) { michael@0: ReplyMessage(dwResult); michael@0: } michael@0: } michael@0: michael@0: /************************************************************** michael@0: ************************************************************** michael@0: ** michael@0: ** BLOCK: Native events michael@0: ** michael@0: ** Main Windows message handlers and OnXXX handlers for michael@0: ** Windows event handling. michael@0: ** michael@0: ************************************************************** michael@0: **************************************************************/ michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: Wind proc. michael@0: * michael@0: * The main Windows event procedures and associated michael@0: * message processing methods. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: static bool michael@0: DisplaySystemMenu(HWND hWnd, nsSizeMode sizeMode, bool isRtl, int32_t x, int32_t y) michael@0: { michael@0: HMENU hMenu = GetSystemMenu(hWnd, FALSE); michael@0: if (hMenu) { michael@0: MENUITEMINFO mii; michael@0: mii.cbSize = sizeof(MENUITEMINFO); michael@0: mii.fMask = MIIM_STATE; michael@0: mii.fType = 0; michael@0: michael@0: // update the options michael@0: mii.fState = MF_ENABLED; michael@0: SetMenuItemInfo(hMenu, SC_RESTORE, FALSE, &mii); michael@0: SetMenuItemInfo(hMenu, SC_SIZE, FALSE, &mii); michael@0: SetMenuItemInfo(hMenu, SC_MOVE, FALSE, &mii); michael@0: SetMenuItemInfo(hMenu, SC_MAXIMIZE, FALSE, &mii); michael@0: SetMenuItemInfo(hMenu, SC_MINIMIZE, FALSE, &mii); michael@0: michael@0: mii.fState = MF_GRAYED; michael@0: switch(sizeMode) { michael@0: case nsSizeMode_Fullscreen: michael@0: SetMenuItemInfo(hMenu, SC_RESTORE, FALSE, &mii); michael@0: // intentional fall through michael@0: case nsSizeMode_Maximized: michael@0: SetMenuItemInfo(hMenu, SC_SIZE, FALSE, &mii); michael@0: SetMenuItemInfo(hMenu, SC_MOVE, FALSE, &mii); michael@0: SetMenuItemInfo(hMenu, SC_MAXIMIZE, FALSE, &mii); michael@0: break; michael@0: case nsSizeMode_Minimized: michael@0: SetMenuItemInfo(hMenu, SC_MINIMIZE, FALSE, &mii); michael@0: break; michael@0: case nsSizeMode_Normal: michael@0: SetMenuItemInfo(hMenu, SC_RESTORE, FALSE, &mii); michael@0: break; michael@0: } michael@0: LPARAM cmd = michael@0: TrackPopupMenu(hMenu, michael@0: (TPM_LEFTBUTTON|TPM_RIGHTBUTTON| michael@0: TPM_RETURNCMD|TPM_TOPALIGN| michael@0: (isRtl ? TPM_RIGHTALIGN : TPM_LEFTALIGN)), michael@0: x, y, 0, hWnd, nullptr); michael@0: if (cmd) { michael@0: PostMessage(hWnd, WM_SYSCOMMAND, cmd, 0); michael@0: return true; michael@0: } michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: inline static mozilla::HangMonitor::ActivityType ActivityTypeForMessage(UINT msg) michael@0: { michael@0: if ((msg >= WM_KEYFIRST && msg <= WM_IME_KEYLAST) || michael@0: (msg >= WM_MOUSEFIRST && msg <= WM_MOUSELAST) || michael@0: (msg >= MOZ_WM_MOUSEWHEEL_FIRST && msg <= MOZ_WM_MOUSEWHEEL_LAST) || michael@0: (msg >= NS_WM_IMEFIRST && msg <= NS_WM_IMELAST)) { michael@0: return mozilla::HangMonitor::kUIActivity; michael@0: } michael@0: michael@0: // This may not actually be right, but we don't want to reset the timer if michael@0: // we're not actually processing a UI message. michael@0: return mozilla::HangMonitor::kActivityUIAVail; michael@0: } michael@0: michael@0: // The WndProc procedure for all nsWindows in this toolkit. This merely catches michael@0: // exceptions and passes the real work to WindowProcInternal. See bug 587406 michael@0: // and http://msdn.microsoft.com/en-us/library/ms633573%28VS.85%29.aspx michael@0: LRESULT CALLBACK nsWindow::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) michael@0: { michael@0: HangMonitor::NotifyActivity(ActivityTypeForMessage(msg)); michael@0: michael@0: return mozilla::CallWindowProcCrashProtected(WindowProcInternal, hWnd, msg, wParam, lParam); michael@0: } michael@0: michael@0: LRESULT CALLBACK nsWindow::WindowProcInternal(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) michael@0: { michael@0: if (::GetWindowLongPtrW(hWnd, GWLP_ID) == eFakeTrackPointScrollableID) { michael@0: // This message was sent to the FAKETRACKPOINTSCROLLABLE. michael@0: if (msg == WM_HSCROLL) { michael@0: // Route WM_HSCROLL messages to the main window. michael@0: hWnd = ::GetParent(::GetParent(hWnd)); michael@0: } else { michael@0: // Handle all other messages with its original window procedure. michael@0: WNDPROC prevWindowProc = (WNDPROC)::GetWindowLongPtr(hWnd, GWLP_USERDATA); michael@0: return ::CallWindowProcW(prevWindowProc, hWnd, msg, wParam, lParam); michael@0: } michael@0: } michael@0: michael@0: if (msg == MOZ_WM_TRACE) { michael@0: // This is a tracer event for measuring event loop latency. michael@0: // See WidgetTraceEvent.cpp for more details. michael@0: mozilla::SignalTracerThread(); michael@0: return 0; michael@0: } michael@0: michael@0: // Get the window which caused the event and ask it to process the message michael@0: nsWindow *targetWindow = WinUtils::GetNSWindowPtr(hWnd); michael@0: NS_ASSERTION(targetWindow, "nsWindow* is null!"); michael@0: if (!targetWindow) michael@0: return ::DefWindowProcW(hWnd, msg, wParam, lParam); michael@0: michael@0: // Hold the window for the life of this method, in case it gets michael@0: // destroyed during processing, unless we're in the dtor already. michael@0: nsCOMPtr kungFuDeathGrip; michael@0: if (!targetWindow->mInDtor) michael@0: kungFuDeathGrip = do_QueryInterface((nsBaseWidget*)targetWindow); michael@0: michael@0: targetWindow->IPCWindowProcHandler(msg, wParam, lParam); michael@0: michael@0: // Create this here so that we store the last rolled up popup until after michael@0: // the event has been processed. michael@0: nsAutoRollup autoRollup; michael@0: michael@0: LRESULT popupHandlingResult; michael@0: if (DealWithPopups(hWnd, msg, wParam, lParam, &popupHandlingResult)) michael@0: return popupHandlingResult; michael@0: michael@0: // Call ProcessMessage michael@0: LRESULT retValue; michael@0: if (targetWindow->ProcessMessage(msg, wParam, lParam, &retValue)) { michael@0: return retValue; michael@0: } michael@0: michael@0: LRESULT res = ::CallWindowProcW(targetWindow->GetPrevWindowProc(), michael@0: hWnd, msg, wParam, lParam); michael@0: michael@0: return res; michael@0: } michael@0: michael@0: // The main windows message processing method for plugins. michael@0: // The result means whether this method processed the native michael@0: // event for plugin. If false, the native event should be michael@0: // processed by the caller self. michael@0: bool michael@0: nsWindow::ProcessMessageForPlugin(const MSG &aMsg, michael@0: MSGResult& aResult) michael@0: { michael@0: aResult.mResult = 0; michael@0: aResult.mConsumed = true; michael@0: michael@0: bool eventDispatched = false; michael@0: switch (aMsg.message) { michael@0: case WM_CHAR: michael@0: case WM_SYSCHAR: michael@0: aResult.mResult = ProcessCharMessage(aMsg, &eventDispatched); michael@0: break; michael@0: michael@0: case WM_KEYUP: michael@0: case WM_SYSKEYUP: michael@0: aResult.mResult = ProcessKeyUpMessage(aMsg, &eventDispatched); michael@0: break; michael@0: michael@0: case WM_KEYDOWN: michael@0: case WM_SYSKEYDOWN: michael@0: aResult.mResult = ProcessKeyDownMessage(aMsg, &eventDispatched); michael@0: break; michael@0: michael@0: case WM_DEADCHAR: michael@0: case WM_SYSDEADCHAR: michael@0: michael@0: case WM_CUT: michael@0: case WM_COPY: michael@0: case WM_PASTE: michael@0: case WM_CLEAR: michael@0: case WM_UNDO: michael@0: break; michael@0: michael@0: default: michael@0: return false; michael@0: } michael@0: michael@0: if (!eventDispatched) { michael@0: aResult.mConsumed = nsWindowBase::DispatchPluginEvent(aMsg); michael@0: } michael@0: if (!Destroyed()) { michael@0: DispatchPendingEvents(); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: static void ForceFontUpdate() michael@0: { michael@0: // update device context font cache michael@0: // Dirty but easiest way: michael@0: // Changing nsIPrefBranch entry which triggers callbacks michael@0: // and flows into calling mDeviceContext->FlushFontCache() michael@0: // to update the font cache in all the instance of Browsers michael@0: static const char kPrefName[] = "font.internaluseonly.changed"; michael@0: bool fontInternalChange = michael@0: Preferences::GetBool(kPrefName, false); michael@0: Preferences::SetBool(kPrefName, !fontInternalChange); michael@0: } michael@0: michael@0: static bool CleartypeSettingChanged() michael@0: { michael@0: static int currentQuality = -1; michael@0: BYTE quality = cairo_win32_get_system_text_quality(); michael@0: michael@0: if (currentQuality == quality) michael@0: return false; michael@0: michael@0: if (currentQuality < 0) { michael@0: currentQuality = quality; michael@0: return false; michael@0: } michael@0: currentQuality = quality; michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: nsWindow::ExternalHandlerProcessMessage(UINT aMessage, michael@0: WPARAM& aWParam, michael@0: LPARAM& aLParam, michael@0: MSGResult& aResult) michael@0: { michael@0: if (mWindowHook.Notify(mWnd, aMessage, aWParam, aLParam, aResult)) { michael@0: return true; michael@0: } michael@0: michael@0: if (IMEHandler::ProcessMessage(this, aMessage, aWParam, aLParam, aResult)) { michael@0: return true; michael@0: } michael@0: michael@0: if (MouseScrollHandler::ProcessMessage(this, aMessage, aWParam, aLParam, michael@0: aResult)) { michael@0: return true; michael@0: } michael@0: michael@0: if (PluginHasFocus()) { michael@0: MSG nativeMsg = WinUtils::InitMSG(aMessage, aWParam, aLParam, mWnd); michael@0: if (ProcessMessageForPlugin(nativeMsg, aResult)) { michael@0: return true; michael@0: } michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: // The main windows message processing method. michael@0: bool michael@0: nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam, michael@0: LRESULT *aRetValue) michael@0: { michael@0: #if defined(EVENT_DEBUG_OUTPUT) michael@0: // First param shows all events, second param indicates whether michael@0: // to show mouse move events. See nsWindowDbg for details. michael@0: PrintEvent(msg, SHOW_REPEAT_EVENTS, SHOW_MOUSEMOVE_EVENTS); michael@0: #endif michael@0: michael@0: MSGResult msgResult(aRetValue); michael@0: if (ExternalHandlerProcessMessage(msg, wParam, lParam, msgResult)) { michael@0: return (msgResult.mConsumed || !mWnd); michael@0: } michael@0: michael@0: bool result = false; // call the default nsWindow proc michael@0: *aRetValue = 0; michael@0: michael@0: // Glass hit testing w/custom transparent margins michael@0: LRESULT dwmHitResult; michael@0: if (mCustomNonClient && michael@0: nsUXThemeData::CheckForCompositor() && michael@0: WinUtils::dwmDwmDefWindowProcPtr(mWnd, msg, wParam, lParam, &dwmHitResult)) { michael@0: *aRetValue = dwmHitResult; michael@0: return true; michael@0: } michael@0: michael@0: // (Large blocks of code should be broken out into OnEvent handlers.) michael@0: switch (msg) { michael@0: // WM_QUERYENDSESSION must be handled by all windows. michael@0: // Otherwise Windows thinks the window can just be killed at will. michael@0: case WM_QUERYENDSESSION: michael@0: if (sCanQuit == TRI_UNKNOWN) michael@0: { michael@0: // Ask if it's ok to quit, and store the answer until we michael@0: // get WM_ENDSESSION signaling the round is complete. michael@0: nsCOMPtr obsServ = michael@0: mozilla::services::GetObserverService(); michael@0: nsCOMPtr cancelQuit = michael@0: do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID); michael@0: cancelQuit->SetData(false); michael@0: obsServ->NotifyObservers(cancelQuit, "quit-application-requested", nullptr); michael@0: michael@0: bool abortQuit; michael@0: cancelQuit->GetData(&abortQuit); michael@0: sCanQuit = abortQuit ? TRI_FALSE : TRI_TRUE; michael@0: } michael@0: *aRetValue = sCanQuit ? TRUE : FALSE; michael@0: result = true; michael@0: break; michael@0: michael@0: case WM_ENDSESSION: michael@0: case MOZ_WM_APP_QUIT: michael@0: if (msg == MOZ_WM_APP_QUIT || (wParam == TRUE && sCanQuit == TRI_TRUE)) michael@0: { michael@0: // Let's fake a shutdown sequence without actually closing windows etc. michael@0: // to avoid Windows killing us in the middle. A proper shutdown would michael@0: // require having a chance to pump some messages. Unfortunately michael@0: // Windows won't let us do that. Bug 212316. michael@0: nsCOMPtr obsServ = michael@0: mozilla::services::GetObserverService(); michael@0: NS_NAMED_LITERAL_STRING(context, "shutdown-persist"); michael@0: obsServ->NotifyObservers(nullptr, "quit-application-granted", nullptr); michael@0: obsServ->NotifyObservers(nullptr, "quit-application-forced", nullptr); michael@0: obsServ->NotifyObservers(nullptr, "quit-application", nullptr); michael@0: obsServ->NotifyObservers(nullptr, "profile-change-net-teardown", context.get()); michael@0: obsServ->NotifyObservers(nullptr, "profile-change-teardown", context.get()); michael@0: obsServ->NotifyObservers(nullptr, "profile-before-change", context.get()); michael@0: obsServ->NotifyObservers(nullptr, "profile-before-change2", context.get()); michael@0: // Then a controlled but very quick exit. michael@0: _exit(0); michael@0: } michael@0: sCanQuit = TRI_UNKNOWN; michael@0: result = true; michael@0: break; michael@0: michael@0: case WM_SYSCOLORCHANGE: michael@0: OnSysColorChanged(); michael@0: break; michael@0: michael@0: case WM_THEMECHANGED: michael@0: { michael@0: // Update non-client margin offsets michael@0: UpdateNonClientMargins(); michael@0: nsUXThemeData::InitTitlebarInfo(); michael@0: nsUXThemeData::UpdateNativeThemeInfo(); michael@0: michael@0: NotifyThemeChanged(); michael@0: michael@0: // Invalidate the window so that the repaint will michael@0: // pick up the new theme. michael@0: Invalidate(true, true, true); michael@0: } michael@0: break; michael@0: michael@0: case WM_FONTCHANGE: michael@0: { michael@0: // We only handle this message for the hidden window, michael@0: // as we only need to update the (global) font list once michael@0: // for any given change, not once per window! michael@0: if (mWindowType != eWindowType_invisible) { michael@0: break; michael@0: } michael@0: michael@0: nsresult rv; michael@0: bool didChange = false; michael@0: michael@0: // update the global font list michael@0: nsCOMPtr fontEnum = do_GetService("@mozilla.org/gfx/fontenumerator;1", &rv); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: fontEnum->UpdateFontList(&didChange); michael@0: ForceFontUpdate(); michael@0: } //if (NS_SUCCEEDED(rv)) michael@0: } michael@0: break; michael@0: michael@0: case WM_NCCALCSIZE: michael@0: { michael@0: if (mCustomNonClient) { michael@0: // If `wParam` is `FALSE`, `lParam` points to a `RECT` that contains michael@0: // the proposed window rectangle for our window. During our michael@0: // processing of the `WM_NCCALCSIZE` message, we are expected to michael@0: // modify the `RECT` that `lParam` points to, so that its value upon michael@0: // our return is the new client area. We must return 0 if `wParam` michael@0: // is `FALSE`. michael@0: // michael@0: // If `wParam` is `TRUE`, `lParam` points to a `NCCALCSIZE_PARAMS` michael@0: // struct. This struct contains an array of 3 `RECT`s, the first of michael@0: // which has the exact same meaning as the `RECT` that is pointed to michael@0: // by `lParam` when `wParam` is `FALSE`. The remaining `RECT`s, in michael@0: // conjunction with our return value, can michael@0: // be used to specify portions of the source and destination window michael@0: // rectangles that are valid and should be preserved. We opt not to michael@0: // implement an elaborate client-area preservation technique, and michael@0: // simply return 0, which means "preserve the entire old client area michael@0: // and align it with the upper-left corner of our new client area". michael@0: RECT *clientRect = wParam michael@0: ? &(reinterpret_cast(lParam))->rgrc[0] michael@0: : (reinterpret_cast(lParam)); michael@0: clientRect->top += (mCaptionHeight - mNonClientOffset.top); michael@0: clientRect->left += (mHorResizeMargin - mNonClientOffset.left); michael@0: clientRect->right -= (mHorResizeMargin - mNonClientOffset.right); michael@0: clientRect->bottom -= (mVertResizeMargin - mNonClientOffset.bottom); michael@0: michael@0: result = true; michael@0: *aRetValue = 0; michael@0: } michael@0: break; michael@0: } michael@0: michael@0: case WM_NCHITTEST: michael@0: { michael@0: if (mMouseTransparent) { michael@0: // Treat this window as transparent. michael@0: *aRetValue = HTTRANSPARENT; michael@0: result = true; michael@0: break; michael@0: } michael@0: michael@0: /* michael@0: * If an nc client area margin has been moved, we are responsible michael@0: * for calculating where the resize margins are and returning the michael@0: * appropriate set of hit test constants. DwmDefWindowProc (above) michael@0: * will handle hit testing on it's command buttons if we are on a michael@0: * composited desktop. michael@0: */ michael@0: michael@0: if (!mCustomNonClient) michael@0: break; michael@0: michael@0: *aRetValue = michael@0: ClientMarginHitTestPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); michael@0: result = true; michael@0: break; michael@0: } michael@0: michael@0: case WM_SETTEXT: michael@0: /* michael@0: * WM_SETTEXT paints the titlebar area. Avoid this if we have a michael@0: * custom titlebar we paint ourselves. michael@0: */ michael@0: michael@0: if (!mCustomNonClient || mNonClientMargins.top == -1) michael@0: break; michael@0: michael@0: { michael@0: // From msdn, the way around this is to disable the visible state michael@0: // temporarily. We need the text to be set but we don't want the michael@0: // redraw to occur. michael@0: DWORD style = GetWindowLong(mWnd, GWL_STYLE); michael@0: SetWindowLong(mWnd, GWL_STYLE, style & ~WS_VISIBLE); michael@0: *aRetValue = CallWindowProcW(GetPrevWindowProc(), mWnd, michael@0: msg, wParam, lParam); michael@0: SetWindowLong(mWnd, GWL_STYLE, style); michael@0: return true; michael@0: } michael@0: michael@0: case WM_NCACTIVATE: michael@0: { michael@0: /* michael@0: * WM_NCACTIVATE paints nc areas. Avoid this and re-route painting michael@0: * through WM_NCPAINT via InvalidateNonClientRegion. michael@0: */ michael@0: UpdateGetWindowInfoCaptionStatus(FALSE != wParam); michael@0: michael@0: if (!mCustomNonClient) michael@0: break; michael@0: michael@0: // let the dwm handle nc painting on glass michael@0: if(nsUXThemeData::CheckForCompositor()) michael@0: break; michael@0: michael@0: if (wParam == TRUE) { michael@0: // going active michael@0: *aRetValue = FALSE; // ignored michael@0: result = true; michael@0: // invalidate to trigger a paint michael@0: InvalidateNonClientRegion(); michael@0: break; michael@0: } else { michael@0: // going inactive michael@0: *aRetValue = TRUE; // go ahead and deactive michael@0: result = true; michael@0: // invalidate to trigger a paint michael@0: InvalidateNonClientRegion(); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: case WM_NCPAINT: michael@0: { michael@0: /* michael@0: * Reset the non-client paint region so that it excludes the michael@0: * non-client areas we paint manually. Then call defwndproc michael@0: * to do the actual painting. michael@0: */ michael@0: michael@0: if (!mCustomNonClient) michael@0: break; michael@0: michael@0: // let the dwm handle nc painting on glass michael@0: if(nsUXThemeData::CheckForCompositor()) michael@0: break; michael@0: michael@0: HRGN paintRgn = ExcludeNonClientFromPaintRegion((HRGN)wParam); michael@0: LRESULT res = CallWindowProcW(GetPrevWindowProc(), mWnd, michael@0: msg, (WPARAM)paintRgn, lParam); michael@0: if (paintRgn != (HRGN)wParam) michael@0: DeleteObject(paintRgn); michael@0: *aRetValue = res; michael@0: result = true; michael@0: } michael@0: break; michael@0: michael@0: case WM_POWERBROADCAST: michael@0: switch (wParam) michael@0: { michael@0: case PBT_APMSUSPEND: michael@0: PostSleepWakeNotification(true); michael@0: break; michael@0: case PBT_APMRESUMEAUTOMATIC: michael@0: case PBT_APMRESUMECRITICAL: michael@0: case PBT_APMRESUMESUSPEND: michael@0: PostSleepWakeNotification(false); michael@0: break; michael@0: } michael@0: break; michael@0: michael@0: case WM_CLOSE: // close request michael@0: if (mWidgetListener) michael@0: mWidgetListener->RequestWindowClose(this); michael@0: result = true; // abort window closure michael@0: break; michael@0: michael@0: case WM_DESTROY: michael@0: // clean up. michael@0: OnDestroy(); michael@0: result = true; michael@0: break; michael@0: michael@0: case WM_PAINT: michael@0: if (CleartypeSettingChanged()) { michael@0: ForceFontUpdate(); michael@0: gfxFontCache *fc = gfxFontCache::GetCache(); michael@0: if (fc) { michael@0: fc->Flush(); michael@0: } michael@0: } michael@0: *aRetValue = (int) OnPaint(nullptr, 0); michael@0: result = true; michael@0: break; michael@0: michael@0: case WM_PRINTCLIENT: michael@0: result = OnPaint((HDC) wParam, 0); michael@0: break; michael@0: michael@0: case WM_HOTKEY: michael@0: result = OnHotKey(wParam, lParam); michael@0: break; michael@0: michael@0: case WM_SYSCHAR: michael@0: case WM_CHAR: michael@0: { michael@0: MSG nativeMsg = WinUtils::InitMSG(msg, wParam, lParam, mWnd); michael@0: result = ProcessCharMessage(nativeMsg, nullptr); michael@0: DispatchPendingEvents(); michael@0: } michael@0: break; michael@0: michael@0: case WM_SYSKEYUP: michael@0: case WM_KEYUP: michael@0: { michael@0: MSG nativeMsg = WinUtils::InitMSG(msg, wParam, lParam, mWnd); michael@0: nativeMsg.time = ::GetMessageTime(); michael@0: result = ProcessKeyUpMessage(nativeMsg, nullptr); michael@0: DispatchPendingEvents(); michael@0: } michael@0: break; michael@0: michael@0: case WM_SYSKEYDOWN: michael@0: case WM_KEYDOWN: michael@0: { michael@0: MSG nativeMsg = WinUtils::InitMSG(msg, wParam, lParam, mWnd); michael@0: result = ProcessKeyDownMessage(nativeMsg, nullptr); michael@0: DispatchPendingEvents(); michael@0: } michael@0: break; michael@0: michael@0: // say we've dealt with erase background if widget does michael@0: // not need auto-erasing michael@0: case WM_ERASEBKGND: michael@0: if (!AutoErase((HDC)wParam)) { michael@0: *aRetValue = 1; michael@0: result = true; michael@0: } michael@0: break; michael@0: michael@0: case WM_MOUSEMOVE: michael@0: { michael@0: mMousePresent = true; michael@0: michael@0: // Suppress dispatch of pending events michael@0: // when mouse moves are generated by widget michael@0: // creation instead of user input. michael@0: LPARAM lParamScreen = lParamToScreen(lParam); michael@0: POINT mp; michael@0: mp.x = GET_X_LPARAM(lParamScreen); michael@0: mp.y = GET_Y_LPARAM(lParamScreen); michael@0: bool userMovedMouse = false; michael@0: if ((sLastMouseMovePoint.x != mp.x) || (sLastMouseMovePoint.y != mp.y)) { michael@0: userMovedMouse = true; michael@0: } michael@0: michael@0: result = DispatchMouseEvent(NS_MOUSE_MOVE, wParam, lParam, michael@0: false, WidgetMouseEvent::eLeftButton, michael@0: MOUSE_INPUT_SOURCE()); michael@0: if (userMovedMouse) { michael@0: DispatchPendingEvents(); michael@0: } michael@0: } michael@0: break; michael@0: michael@0: case WM_NCMOUSEMOVE: michael@0: // If we receive a mouse move event on non-client chrome, make sure and michael@0: // send an NS_MOUSE_EXIT event as well. michael@0: if (mMousePresent && !sIsInMouseCapture) michael@0: SendMessage(mWnd, WM_MOUSELEAVE, 0, 0); michael@0: break; michael@0: michael@0: case WM_LBUTTONDOWN: michael@0: { michael@0: result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam, michael@0: false, WidgetMouseEvent::eLeftButton, michael@0: MOUSE_INPUT_SOURCE()); michael@0: DispatchPendingEvents(); michael@0: } michael@0: break; michael@0: michael@0: case WM_LBUTTONUP: michael@0: { michael@0: result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, lParam, michael@0: false, WidgetMouseEvent::eLeftButton, michael@0: MOUSE_INPUT_SOURCE()); michael@0: DispatchPendingEvents(); michael@0: } michael@0: break; michael@0: michael@0: case WM_MOUSELEAVE: michael@0: { michael@0: if (!mMousePresent) michael@0: break; michael@0: mMousePresent = false; michael@0: michael@0: // We need to check mouse button states and put them in for michael@0: // wParam. michael@0: WPARAM mouseState = (GetKeyState(VK_LBUTTON) ? MK_LBUTTON : 0) michael@0: | (GetKeyState(VK_MBUTTON) ? MK_MBUTTON : 0) michael@0: | (GetKeyState(VK_RBUTTON) ? MK_RBUTTON : 0); michael@0: // Synthesize an event position because we don't get one from michael@0: // WM_MOUSELEAVE. michael@0: LPARAM pos = lParamToClient(::GetMessagePos()); michael@0: DispatchMouseEvent(NS_MOUSE_EXIT, mouseState, pos, false, michael@0: WidgetMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE()); michael@0: } michael@0: break; michael@0: michael@0: case WM_CONTEXTMENU: michael@0: { michael@0: // if the context menu is brought up from the keyboard, |lParam| michael@0: // will be -1. michael@0: LPARAM pos; michael@0: bool contextMenukey = false; michael@0: if (lParam == -1) michael@0: { michael@0: contextMenukey = true; michael@0: pos = lParamToClient(GetMessagePos()); michael@0: } michael@0: else michael@0: { michael@0: pos = lParamToClient(lParam); michael@0: } michael@0: michael@0: result = DispatchMouseEvent(NS_CONTEXTMENU, wParam, pos, contextMenukey, michael@0: contextMenukey ? michael@0: WidgetMouseEvent::eLeftButton : michael@0: WidgetMouseEvent::eRightButton, michael@0: MOUSE_INPUT_SOURCE()); michael@0: if (lParam != -1 && !result && mCustomNonClient) { michael@0: WidgetMouseEvent event(true, NS_MOUSE_MOZHITTEST, this, michael@0: WidgetMouseEvent::eReal, michael@0: WidgetMouseEvent::eNormal); michael@0: event.refPoint = LayoutDeviceIntPoint(GET_X_LPARAM(pos), GET_Y_LPARAM(pos)); michael@0: event.inputSource = MOUSE_INPUT_SOURCE(); michael@0: event.mFlags.mOnlyChromeDispatch = true; michael@0: if (DispatchWindowEvent(&event)) { michael@0: // Blank area hit, throw up the system menu. michael@0: DisplaySystemMenu(mWnd, mSizeMode, mIsRTL, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); michael@0: result = true; michael@0: } michael@0: } michael@0: } michael@0: break; michael@0: michael@0: case WM_LBUTTONDBLCLK: michael@0: result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam, michael@0: lParam, false, michael@0: WidgetMouseEvent::eLeftButton, michael@0: MOUSE_INPUT_SOURCE()); michael@0: DispatchPendingEvents(); michael@0: break; michael@0: michael@0: case WM_MBUTTONDOWN: michael@0: result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, michael@0: lParam, false, michael@0: WidgetMouseEvent::eMiddleButton, michael@0: MOUSE_INPUT_SOURCE()); michael@0: DispatchPendingEvents(); michael@0: break; michael@0: michael@0: case WM_MBUTTONUP: michael@0: result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, michael@0: lParam, false, michael@0: WidgetMouseEvent::eMiddleButton, michael@0: MOUSE_INPUT_SOURCE()); michael@0: DispatchPendingEvents(); michael@0: break; michael@0: michael@0: case WM_MBUTTONDBLCLK: michael@0: result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam, michael@0: lParam, false, michael@0: WidgetMouseEvent::eMiddleButton, michael@0: MOUSE_INPUT_SOURCE()); michael@0: DispatchPendingEvents(); michael@0: break; michael@0: michael@0: case WM_NCMBUTTONDOWN: michael@0: result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, 0, michael@0: lParamToClient(lParam), false, michael@0: WidgetMouseEvent::eMiddleButton, michael@0: MOUSE_INPUT_SOURCE()); michael@0: DispatchPendingEvents(); michael@0: break; michael@0: michael@0: case WM_NCMBUTTONUP: michael@0: result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, 0, michael@0: lParamToClient(lParam), false, michael@0: WidgetMouseEvent::eMiddleButton, michael@0: MOUSE_INPUT_SOURCE()); michael@0: DispatchPendingEvents(); michael@0: break; michael@0: michael@0: case WM_NCMBUTTONDBLCLK: michael@0: result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, 0, michael@0: lParamToClient(lParam), false, michael@0: WidgetMouseEvent::eMiddleButton, michael@0: MOUSE_INPUT_SOURCE()); michael@0: DispatchPendingEvents(); michael@0: break; michael@0: michael@0: case WM_RBUTTONDOWN: michael@0: result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, michael@0: lParam, false, michael@0: WidgetMouseEvent::eRightButton, michael@0: MOUSE_INPUT_SOURCE()); michael@0: DispatchPendingEvents(); michael@0: break; michael@0: michael@0: case WM_RBUTTONUP: michael@0: result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, wParam, michael@0: lParam, false, michael@0: WidgetMouseEvent::eRightButton, michael@0: MOUSE_INPUT_SOURCE()); michael@0: DispatchPendingEvents(); michael@0: break; michael@0: michael@0: case WM_RBUTTONDBLCLK: michael@0: result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, wParam, michael@0: lParam, false, michael@0: WidgetMouseEvent::eRightButton, michael@0: MOUSE_INPUT_SOURCE()); michael@0: DispatchPendingEvents(); michael@0: break; michael@0: michael@0: case WM_NCRBUTTONDOWN: michael@0: result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, 0, michael@0: lParamToClient(lParam), false, michael@0: WidgetMouseEvent::eRightButton, michael@0: MOUSE_INPUT_SOURCE()); michael@0: DispatchPendingEvents(); michael@0: break; michael@0: michael@0: case WM_NCRBUTTONUP: michael@0: result = DispatchMouseEvent(NS_MOUSE_BUTTON_UP, 0, michael@0: lParamToClient(lParam), false, michael@0: WidgetMouseEvent::eRightButton, michael@0: MOUSE_INPUT_SOURCE()); michael@0: DispatchPendingEvents(); michael@0: break; michael@0: michael@0: case WM_NCRBUTTONDBLCLK: michael@0: result = DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, 0, michael@0: lParamToClient(lParam), false, michael@0: WidgetMouseEvent::eRightButton, michael@0: MOUSE_INPUT_SOURCE()); michael@0: DispatchPendingEvents(); michael@0: break; michael@0: michael@0: case WM_EXITSIZEMOVE: michael@0: if (!sIsInMouseCapture) { michael@0: NotifySizeMoveDone(); michael@0: } michael@0: break; michael@0: michael@0: case WM_NCLBUTTONDBLCLK: michael@0: DispatchMouseEvent(NS_MOUSE_DOUBLECLICK, 0, lParamToClient(lParam), michael@0: false, WidgetMouseEvent::eLeftButton, michael@0: MOUSE_INPUT_SOURCE()); michael@0: result = michael@0: DispatchMouseEvent(NS_MOUSE_BUTTON_UP, 0, lParamToClient(lParam), michael@0: false, WidgetMouseEvent::eLeftButton, michael@0: MOUSE_INPUT_SOURCE()); michael@0: DispatchPendingEvents(); michael@0: break; michael@0: michael@0: case WM_APPCOMMAND: michael@0: result = HandleAppCommandMsg(wParam, lParam, aRetValue); michael@0: break; michael@0: michael@0: // The WM_ACTIVATE event is fired when a window is raised or lowered, michael@0: // and the loword of wParam specifies which. But we don't want to tell michael@0: // the focus system about this until the WM_SETFOCUS or WM_KILLFOCUS michael@0: // events are fired. Instead, set either the sJustGotActivate or michael@0: // gJustGotDeactivate flags and activate/deactivate once the focus michael@0: // events arrive. michael@0: case WM_ACTIVATE: michael@0: if (mWidgetListener) { michael@0: int32_t fActive = LOWORD(wParam); michael@0: michael@0: if (WA_INACTIVE == fActive) { michael@0: // when minimizing a window, the deactivation and focus events will michael@0: // be fired in the reverse order. Instead, just deactivate right away. michael@0: if (HIWORD(wParam)) michael@0: DispatchFocusToTopLevelWindow(false); michael@0: else michael@0: sJustGotDeactivate = true; michael@0: michael@0: if (mIsTopWidgetWindow) michael@0: mLastKeyboardLayout = KeyboardLayout::GetInstance()->GetLayout(); michael@0: michael@0: } else { michael@0: StopFlashing(); michael@0: michael@0: sJustGotActivate = true; michael@0: WidgetMouseEvent event(true, NS_MOUSE_ACTIVATE, this, michael@0: WidgetMouseEvent::eReal); michael@0: InitEvent(event); michael@0: ModifierKeyState modifierKeyState; michael@0: modifierKeyState.InitInputEvent(event); michael@0: DispatchWindowEvent(&event); michael@0: if (sSwitchKeyboardLayout && mLastKeyboardLayout) michael@0: ActivateKeyboardLayout(mLastKeyboardLayout, 0); michael@0: } michael@0: } michael@0: break; michael@0: michael@0: case WM_MOUSEACTIVATE: michael@0: // A popup with a parent owner should not be activated when clicked but michael@0: // should still allow the mouse event to be fired, so the return value michael@0: // is set to MA_NOACTIVATE. But if the owner isn't the frontmost window, michael@0: // just use default processing so that the window is activated. michael@0: if (IsPopup() && IsOwnerForegroundWindow()) { michael@0: *aRetValue = MA_NOACTIVATE; michael@0: result = true; michael@0: } michael@0: break; michael@0: michael@0: case WM_WINDOWPOSCHANGING: michael@0: { michael@0: LPWINDOWPOS info = (LPWINDOWPOS)lParam; michael@0: OnWindowPosChanging(info); michael@0: result = true; michael@0: } michael@0: break; michael@0: michael@0: case WM_GETMINMAXINFO: michael@0: { michael@0: MINMAXINFO* mmi = (MINMAXINFO*)lParam; michael@0: // Set the constraints. The minimum size should also be constrained to the michael@0: // default window maximum size so that it fits on screen. michael@0: mmi->ptMinTrackSize.x = michael@0: std::min((int32_t)mmi->ptMaxTrackSize.x, michael@0: std::max((int32_t)mmi->ptMinTrackSize.x, mSizeConstraints.mMinSize.width)); michael@0: mmi->ptMinTrackSize.y = michael@0: std::min((int32_t)mmi->ptMaxTrackSize.y, michael@0: std::max((int32_t)mmi->ptMinTrackSize.y, mSizeConstraints.mMinSize.height)); michael@0: mmi->ptMaxTrackSize.x = std::min((int32_t)mmi->ptMaxTrackSize.x, mSizeConstraints.mMaxSize.width); michael@0: mmi->ptMaxTrackSize.y = std::min((int32_t)mmi->ptMaxTrackSize.y, mSizeConstraints.mMaxSize.height); michael@0: } michael@0: break; michael@0: michael@0: case WM_SETFOCUS: michael@0: // If previous focused window isn't ours, it must have received the michael@0: // redirected message. So, we should forget it. michael@0: if (!WinUtils::IsOurProcessWindow(HWND(wParam))) { michael@0: RedirectedKeyDownMessageManager::Forget(); michael@0: } michael@0: if (sJustGotActivate) { michael@0: DispatchFocusToTopLevelWindow(true); michael@0: } michael@0: break; michael@0: michael@0: case WM_KILLFOCUS: michael@0: if (sJustGotDeactivate) { michael@0: DispatchFocusToTopLevelWindow(false); michael@0: } michael@0: break; michael@0: michael@0: case WM_WINDOWPOSCHANGED: michael@0: { michael@0: WINDOWPOS* wp = (LPWINDOWPOS)lParam; michael@0: OnWindowPosChanged(wp); michael@0: result = true; michael@0: } michael@0: break; michael@0: michael@0: case WM_INPUTLANGCHANGEREQUEST: michael@0: *aRetValue = TRUE; michael@0: result = false; michael@0: break; michael@0: michael@0: case WM_INPUTLANGCHANGE: michael@0: KeyboardLayout::GetInstance()-> michael@0: OnLayoutChange(reinterpret_cast(lParam)); michael@0: result = false; // always pass to child window michael@0: break; michael@0: michael@0: case WM_DESTROYCLIPBOARD: michael@0: { michael@0: nsIClipboard* clipboard; michael@0: nsresult rv = CallGetService(kCClipboardCID, &clipboard); michael@0: if(NS_SUCCEEDED(rv)) { michael@0: clipboard->EmptyClipboard(nsIClipboard::kGlobalClipboard); michael@0: NS_RELEASE(clipboard); michael@0: } michael@0: } michael@0: break; michael@0: michael@0: #ifdef ACCESSIBILITY michael@0: case WM_GETOBJECT: michael@0: { michael@0: *aRetValue = 0; michael@0: // Do explicit casting to make it working on 64bit systems (see bug 649236 michael@0: // for details). michael@0: DWORD objId = static_cast(lParam); michael@0: if (objId == OBJID_CLIENT) { // oleacc.dll will be loaded dynamically michael@0: a11y::Accessible* rootAccessible = GetAccessible(); // Held by a11y cache michael@0: if (rootAccessible) { michael@0: IAccessible *msaaAccessible = nullptr; michael@0: rootAccessible->GetNativeInterface((void**)&msaaAccessible); // does an addref michael@0: if (msaaAccessible) { michael@0: *aRetValue = LresultFromObject(IID_IAccessible, wParam, msaaAccessible); // does an addref michael@0: msaaAccessible->Release(); // release extra addref michael@0: result = true; // We handled the WM_GETOBJECT message michael@0: } michael@0: } michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: case WM_SYSCOMMAND: michael@0: { michael@0: WPARAM filteredWParam = (wParam &0xFFF0); michael@0: // prevent Windows from trimming the working set. bug 76831 michael@0: if (!sTrimOnMinimize && filteredWParam == SC_MINIMIZE) { michael@0: ::ShowWindow(mWnd, SW_SHOWMINIMIZED); michael@0: result = true; michael@0: } michael@0: michael@0: // Handle the system menu manually when we're in full screen mode michael@0: // so we can set the appropriate options. michael@0: if (filteredWParam == SC_KEYMENU && lParam == VK_SPACE && michael@0: mSizeMode == nsSizeMode_Fullscreen) { michael@0: DisplaySystemMenu(mWnd, mSizeMode, mIsRTL, michael@0: MOZ_SYSCONTEXT_X_POS, michael@0: MOZ_SYSCONTEXT_Y_POS); michael@0: result = true; michael@0: } michael@0: } michael@0: break; michael@0: michael@0: case WM_DWMCOMPOSITIONCHANGED: michael@0: // First, update the compositor state to latest one. All other methods michael@0: // should use same state as here for consistency painting. michael@0: nsUXThemeData::CheckForCompositor(true); michael@0: michael@0: UpdateNonClientMargins(); michael@0: BroadcastMsg(mWnd, WM_DWMCOMPOSITIONCHANGED); michael@0: NotifyThemeChanged(); michael@0: UpdateGlass(); michael@0: Invalidate(true, true, true); michael@0: break; michael@0: michael@0: case WM_UPDATEUISTATE: michael@0: { michael@0: // If the UI state has changed, fire an event so the UI updates the michael@0: // keyboard cues based on the system setting and how the window was michael@0: // opened. For example, a dialog opened via a keyboard press on a button michael@0: // should enable cues, whereas the same dialog opened via a mouse click of michael@0: // the button should not. michael@0: int32_t action = LOWORD(wParam); michael@0: if (action == UIS_SET || action == UIS_CLEAR) { michael@0: int32_t flags = HIWORD(wParam); michael@0: UIStateChangeType showAccelerators = UIStateChangeType_NoChange; michael@0: UIStateChangeType showFocusRings = UIStateChangeType_NoChange; michael@0: if (flags & UISF_HIDEACCEL) michael@0: showAccelerators = (action == UIS_SET) ? UIStateChangeType_Clear : UIStateChangeType_Set; michael@0: if (flags & UISF_HIDEFOCUS) michael@0: showFocusRings = (action == UIS_SET) ? UIStateChangeType_Clear : UIStateChangeType_Set; michael@0: NotifyUIStateChanged(showAccelerators, showFocusRings); michael@0: } michael@0: michael@0: break; michael@0: } michael@0: michael@0: /* Gesture support events */ michael@0: case WM_TABLET_QUERYSYSTEMGESTURESTATUS: michael@0: // According to MS samples, this must be handled to enable michael@0: // rotational support in multi-touch drivers. michael@0: result = true; michael@0: *aRetValue = TABLET_ROTATE_GESTURE_ENABLE; michael@0: break; michael@0: michael@0: case WM_TOUCH: michael@0: result = OnTouch(wParam, lParam); michael@0: if (result) { michael@0: *aRetValue = 0; michael@0: } michael@0: break; michael@0: michael@0: case WM_GESTURE: michael@0: result = OnGesture(wParam, lParam); michael@0: break; michael@0: michael@0: case WM_GESTURENOTIFY: michael@0: { michael@0: if (mWindowType != eWindowType_invisible && michael@0: mWindowType != eWindowType_plugin) { michael@0: // A GestureNotify event is dispatched to decide which single-finger panning michael@0: // direction should be active (including none) and if pan feedback should michael@0: // be displayed. Java and plugin windows can make their own calls. michael@0: if (gIsPointerEventsEnabled) { michael@0: result = false; michael@0: break; michael@0: } michael@0: michael@0: GESTURENOTIFYSTRUCT * gestureinfo = (GESTURENOTIFYSTRUCT*)lParam; michael@0: nsPointWin touchPoint; michael@0: touchPoint = gestureinfo->ptsLocation; michael@0: touchPoint.ScreenToClient(mWnd); michael@0: WidgetGestureNotifyEvent gestureNotifyEvent(true, michael@0: NS_GESTURENOTIFY_EVENT_START, this); michael@0: gestureNotifyEvent.refPoint = LayoutDeviceIntPoint::FromUntyped(touchPoint); michael@0: nsEventStatus status; michael@0: DispatchEvent(&gestureNotifyEvent, status); michael@0: mDisplayPanFeedback = gestureNotifyEvent.displayPanFeedback; michael@0: if (!mTouchWindow) michael@0: mGesture.SetWinGestureSupport(mWnd, gestureNotifyEvent.panDirection); michael@0: } michael@0: result = false; //should always bubble to DefWindowProc michael@0: } michael@0: break; michael@0: michael@0: case WM_CLEAR: michael@0: { michael@0: WidgetContentCommandEvent command(true, NS_CONTENT_COMMAND_DELETE, this); michael@0: DispatchWindowEvent(&command); michael@0: result = true; michael@0: } michael@0: break; michael@0: michael@0: case WM_CUT: michael@0: { michael@0: WidgetContentCommandEvent command(true, NS_CONTENT_COMMAND_CUT, this); michael@0: DispatchWindowEvent(&command); michael@0: result = true; michael@0: } michael@0: break; michael@0: michael@0: case WM_COPY: michael@0: { michael@0: WidgetContentCommandEvent command(true, NS_CONTENT_COMMAND_COPY, this); michael@0: DispatchWindowEvent(&command); michael@0: result = true; michael@0: } michael@0: break; michael@0: michael@0: case WM_PASTE: michael@0: { michael@0: WidgetContentCommandEvent command(true, NS_CONTENT_COMMAND_PASTE, this); michael@0: DispatchWindowEvent(&command); michael@0: result = true; michael@0: } michael@0: break; michael@0: michael@0: case EM_UNDO: michael@0: { michael@0: WidgetContentCommandEvent command(true, NS_CONTENT_COMMAND_UNDO, this); michael@0: DispatchWindowEvent(&command); michael@0: *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled); michael@0: result = true; michael@0: } michael@0: break; michael@0: michael@0: case EM_REDO: michael@0: { michael@0: WidgetContentCommandEvent command(true, NS_CONTENT_COMMAND_REDO, this); michael@0: DispatchWindowEvent(&command); michael@0: *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled); michael@0: result = true; michael@0: } michael@0: break; michael@0: michael@0: case EM_CANPASTE: michael@0: { michael@0: // Support EM_CANPASTE message only when wParam isn't specified or michael@0: // is plain text format. michael@0: if (wParam == 0 || wParam == CF_TEXT || wParam == CF_UNICODETEXT) { michael@0: WidgetContentCommandEvent command(true, NS_CONTENT_COMMAND_PASTE, michael@0: this, true); michael@0: DispatchWindowEvent(&command); michael@0: *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled); michael@0: result = true; michael@0: } michael@0: } michael@0: break; michael@0: michael@0: case EM_CANUNDO: michael@0: { michael@0: WidgetContentCommandEvent command(true, NS_CONTENT_COMMAND_UNDO, michael@0: this, true); michael@0: DispatchWindowEvent(&command); michael@0: *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled); michael@0: result = true; michael@0: } michael@0: break; michael@0: michael@0: case EM_CANREDO: michael@0: { michael@0: WidgetContentCommandEvent command(true, NS_CONTENT_COMMAND_REDO, michael@0: this, true); michael@0: DispatchWindowEvent(&command); michael@0: *aRetValue = (LRESULT)(command.mSucceeded && command.mIsEnabled); michael@0: result = true; michael@0: } michael@0: break; michael@0: michael@0: default: michael@0: { michael@0: if (msg == nsAppShell::GetTaskbarButtonCreatedMessage()) michael@0: SetHasTaskbarIconBeenCreated(); michael@0: if (msg == sOOPPPluginFocusEvent) { michael@0: if (wParam == 1) { michael@0: // With OOPP, the plugin window exists in another process and is a child of michael@0: // this window. This window is a placeholder plugin window for the dom. We michael@0: // receive this event when the child window receives focus. (sent from michael@0: // PluginInstanceParent.cpp) michael@0: ::SendMessage(mWnd, WM_MOUSEACTIVATE, 0, 0); // See nsPluginNativeWindowWin.cpp michael@0: } else { michael@0: // WM_KILLFOCUS was received by the child process. michael@0: if (sJustGotDeactivate) { michael@0: DispatchFocusToTopLevelWindow(false); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: break; michael@0: case WM_SETTINGCHANGE: michael@0: if (IsWin8OrLater() && lParam && michael@0: !wcsicmp(L"ConvertibleSlateMode", (wchar_t*)lParam)) { michael@0: // If we're switching into slate mode, switch to Metro for hardware michael@0: // that supports this feature if the pref is set. michael@0: if (GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0 && michael@0: Preferences::GetBool("browser.shell.desktop-auto-switch-enabled", michael@0: false)) { michael@0: nsCOMPtr appStartup(do_GetService(NS_APPSTARTUP_CONTRACTID)); michael@0: if (appStartup) { michael@0: appStartup->Quit(nsIAppStartup::eForceQuit | michael@0: nsIAppStartup::eRestartTouchEnvironment); michael@0: } michael@0: } michael@0: } michael@0: break; michael@0: michael@0: } michael@0: michael@0: //*aRetValue = result; michael@0: if (mWnd) { michael@0: return result; michael@0: } michael@0: else { michael@0: //Events which caused mWnd destruction and aren't consumed michael@0: //will crash during the Windows default processing. michael@0: return true; michael@0: } michael@0: } michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: Broadcast messaging michael@0: * michael@0: * Broadcast messages to all windows. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: // Enumerate all child windows sending aMsg to each of them michael@0: BOOL CALLBACK nsWindow::BroadcastMsgToChildren(HWND aWnd, LPARAM aMsg) michael@0: { michael@0: WNDPROC winProc = (WNDPROC)::GetWindowLongPtrW(aWnd, GWLP_WNDPROC); michael@0: if (winProc == &nsWindow::WindowProc) { michael@0: // it's one of our windows so go ahead and send a message to it michael@0: ::CallWindowProcW(winProc, aWnd, aMsg, 0, 0); michael@0: } michael@0: return TRUE; michael@0: } michael@0: michael@0: // Enumerate all top level windows specifying that the children of each michael@0: // top level window should be enumerated. Do *not* send the message to michael@0: // each top level window since it is assumed that the toolkit will send michael@0: // aMsg to them directly. michael@0: BOOL CALLBACK nsWindow::BroadcastMsg(HWND aTopWindow, LPARAM aMsg) michael@0: { michael@0: // Iterate each of aTopWindows child windows sending the aMsg michael@0: // to each of them. michael@0: ::EnumChildWindows(aTopWindow, nsWindow::BroadcastMsgToChildren, aMsg); michael@0: return TRUE; michael@0: } michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: Event processing helpers michael@0: * michael@0: * Special processing for certain event types and michael@0: * synthesized events. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: int32_t michael@0: nsWindow::ClientMarginHitTestPoint(int32_t mx, int32_t my) michael@0: { michael@0: if (mSizeMode == nsSizeMode_Minimized || michael@0: mSizeMode == nsSizeMode_Fullscreen) { michael@0: return HTCLIENT; michael@0: } michael@0: michael@0: // Calculations are done in screen coords michael@0: RECT winRect; michael@0: GetWindowRect(mWnd, &winRect); michael@0: michael@0: // hit return constants: michael@0: // HTBORDER - non-resizable border michael@0: // HTBOTTOM, HTLEFT, HTRIGHT, HTTOP - resizable border michael@0: // HTBOTTOMLEFT, HTBOTTOMRIGHT - resizable corner michael@0: // HTTOPLEFT, HTTOPRIGHT - resizable corner michael@0: // HTCAPTION - general title bar area michael@0: // HTCLIENT - area considered the client michael@0: // HTCLOSE - hovering over the close button michael@0: // HTMAXBUTTON - maximize button michael@0: // HTMINBUTTON - minimize button michael@0: michael@0: int32_t testResult = HTCLIENT; michael@0: michael@0: bool isResizable = (mBorderStyle & (eBorderStyle_all | michael@0: eBorderStyle_resizeh | michael@0: eBorderStyle_default)) > 0 ? true : false; michael@0: if (mSizeMode == nsSizeMode_Maximized) michael@0: isResizable = false; michael@0: michael@0: // Ensure being accessible to borders of window. Even if contents are in michael@0: // this area, the area must behave as border. michael@0: nsIntMargin nonClientSize(std::max(mCaptionHeight - mNonClientOffset.top, michael@0: kResizableBorderMinSize), michael@0: std::max(mHorResizeMargin - mNonClientOffset.right, michael@0: kResizableBorderMinSize), michael@0: std::max(mVertResizeMargin - mNonClientOffset.bottom, michael@0: kResizableBorderMinSize), michael@0: std::max(mHorResizeMargin - mNonClientOffset.left, michael@0: kResizableBorderMinSize)); michael@0: michael@0: bool allowContentOverride = mSizeMode == nsSizeMode_Maximized || michael@0: (mx >= winRect.left + nonClientSize.left && michael@0: mx <= winRect.right - nonClientSize.right && michael@0: my >= winRect.top + nonClientSize.top && michael@0: my <= winRect.bottom - nonClientSize.bottom); michael@0: michael@0: // The border size. If there is no content under mouse cursor, the border michael@0: // size should be larger than the values in system settings. Otherwise, michael@0: // contents under the mouse cursor should be able to override the behavior. michael@0: // E.g., user must expect that Firefox button always opens the popup menu michael@0: // even when the user clicks on the above edge of it. michael@0: nsIntMargin borderSize(std::max(nonClientSize.top, mVertResizeMargin), michael@0: std::max(nonClientSize.right, mHorResizeMargin), michael@0: std::max(nonClientSize.bottom, mVertResizeMargin), michael@0: std::max(nonClientSize.left, mHorResizeMargin)); michael@0: michael@0: bool top = false; michael@0: bool bottom = false; michael@0: bool left = false; michael@0: bool right = false; michael@0: michael@0: if (my >= winRect.top && my < winRect.top + borderSize.top) { michael@0: top = true; michael@0: } else if (my <= winRect.bottom && my > winRect.bottom - borderSize.bottom) { michael@0: bottom = true; michael@0: } michael@0: michael@0: // (the 2x case here doubles the resize area for corners) michael@0: int multiplier = (top || bottom) ? 2 : 1; michael@0: if (mx >= winRect.left && michael@0: mx < winRect.left + (multiplier * borderSize.left)) { michael@0: left = true; michael@0: } else if (mx <= winRect.right && michael@0: mx > winRect.right - (multiplier * borderSize.right)) { michael@0: right = true; michael@0: } michael@0: michael@0: if (isResizable) { michael@0: if (top) { michael@0: testResult = HTTOP; michael@0: if (left) michael@0: testResult = HTTOPLEFT; michael@0: else if (right) michael@0: testResult = HTTOPRIGHT; michael@0: } else if (bottom) { michael@0: testResult = HTBOTTOM; michael@0: if (left) michael@0: testResult = HTBOTTOMLEFT; michael@0: else if (right) michael@0: testResult = HTBOTTOMRIGHT; michael@0: } else { michael@0: if (left) michael@0: testResult = HTLEFT; michael@0: if (right) michael@0: testResult = HTRIGHT; michael@0: } michael@0: } else { michael@0: if (top) michael@0: testResult = HTCAPTION; michael@0: else if (bottom || left || right) michael@0: testResult = HTBORDER; michael@0: } michael@0: michael@0: if (!sIsInMouseCapture && allowContentOverride) { michael@0: POINT pt = { mx, my }; michael@0: ::ScreenToClient(mWnd, &pt); michael@0: if (pt.x == mCachedHitTestPoint.x && pt.y == mCachedHitTestPoint.y && michael@0: TimeStamp::Now() - mCachedHitTestTime < TimeDuration::FromMilliseconds(HITTEST_CACHE_LIFETIME_MS)) { michael@0: testResult = mCachedHitTestResult; michael@0: } else { michael@0: WidgetMouseEvent event(true, NS_MOUSE_MOZHITTEST, this, michael@0: WidgetMouseEvent::eReal, michael@0: WidgetMouseEvent::eNormal); michael@0: event.refPoint = LayoutDeviceIntPoint(pt.x, pt.y); michael@0: event.inputSource = MOUSE_INPUT_SOURCE(); michael@0: event.mFlags.mOnlyChromeDispatch = true; michael@0: bool result = DispatchWindowEvent(&event); michael@0: if (result) { michael@0: // The mouse is over a blank area michael@0: testResult = testResult == HTCLIENT ? HTCAPTION : testResult; michael@0: michael@0: } else { michael@0: // There's content over the mouse pointer. Set HTCLIENT michael@0: // to possibly override a resizer border. michael@0: testResult = HTCLIENT; michael@0: } michael@0: mCachedHitTestPoint = pt; michael@0: mCachedHitTestTime = TimeStamp::Now(); michael@0: mCachedHitTestResult = testResult; michael@0: } michael@0: } michael@0: michael@0: return testResult; michael@0: } michael@0: michael@0: void nsWindow::PostSleepWakeNotification(const bool aIsSleepMode) michael@0: { michael@0: if (aIsSleepMode == gIsSleepMode) michael@0: return; michael@0: michael@0: gIsSleepMode = aIsSleepMode; michael@0: michael@0: nsCOMPtr observerService = michael@0: mozilla::services::GetObserverService(); michael@0: if (observerService) michael@0: observerService->NotifyObservers(nullptr, michael@0: aIsSleepMode ? NS_WIDGET_SLEEP_OBSERVER_TOPIC : michael@0: NS_WIDGET_WAKE_OBSERVER_TOPIC, nullptr); michael@0: } michael@0: michael@0: LRESULT nsWindow::ProcessCharMessage(const MSG &aMsg, bool *aEventDispatched) michael@0: { michael@0: if (IMEHandler::IsComposingOn(this)) { michael@0: IMEHandler::NotifyIME(this, REQUEST_TO_COMMIT_COMPOSITION); michael@0: } michael@0: // These must be checked here too as a lone WM_CHAR could be received michael@0: // if a child window didn't handle it (for example Alt+Space in a content michael@0: // window) michael@0: ModifierKeyState modKeyState; michael@0: NativeKey nativeKey(this, aMsg, modKeyState); michael@0: return static_cast(nativeKey.HandleCharMessage(aMsg, michael@0: aEventDispatched)); michael@0: } michael@0: michael@0: LRESULT nsWindow::ProcessKeyUpMessage(const MSG &aMsg, bool *aEventDispatched) michael@0: { michael@0: if (IMEHandler::IsComposingOn(this)) { michael@0: return 0; michael@0: } michael@0: michael@0: ModifierKeyState modKeyState; michael@0: NativeKey nativeKey(this, aMsg, modKeyState); michael@0: return static_cast(nativeKey.HandleKeyUpMessage(aEventDispatched)); michael@0: } michael@0: michael@0: LRESULT nsWindow::ProcessKeyDownMessage(const MSG &aMsg, michael@0: bool *aEventDispatched) michael@0: { michael@0: // If this method doesn't call NativeKey::HandleKeyDownMessage(), this method michael@0: // must clean up the redirected message information itself. For more michael@0: // information, see above comment of michael@0: // RedirectedKeyDownMessageManager::AutoFlusher class definition in michael@0: // KeyboardLayout.h. michael@0: RedirectedKeyDownMessageManager::AutoFlusher redirectedMsgFlusher(this, aMsg); michael@0: michael@0: ModifierKeyState modKeyState; michael@0: michael@0: LRESULT result = 0; michael@0: if (!IMEHandler::IsComposingOn(this)) { michael@0: NativeKey nativeKey(this, aMsg, modKeyState); michael@0: result = michael@0: static_cast(nativeKey.HandleKeyDownMessage(aEventDispatched)); michael@0: // HandleKeyDownMessage cleaned up the redirected message information michael@0: // itself, so, we should do nothing. michael@0: redirectedMsgFlusher.Cancel(); michael@0: } michael@0: michael@0: if (aMsg.wParam == VK_MENU || michael@0: (aMsg.wParam == VK_F10 && !modKeyState.IsShift())) { michael@0: // We need to let Windows handle this keypress, michael@0: // by returning false, if there's a native menu michael@0: // bar somewhere in our containing window hierarchy. michael@0: // Otherwise we handle the keypress and don't pass michael@0: // it on to Windows, by returning true. michael@0: bool hasNativeMenu = false; michael@0: HWND hWnd = mWnd; michael@0: while (hWnd) { michael@0: if (::GetMenu(hWnd)) { michael@0: hasNativeMenu = true; michael@0: break; michael@0: } michael@0: hWnd = ::GetParent(hWnd); michael@0: } michael@0: result = !hasNativeMenu; michael@0: } michael@0: michael@0: return result; michael@0: } michael@0: michael@0: nsresult michael@0: nsWindow::SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout, michael@0: int32_t aNativeKeyCode, michael@0: uint32_t aModifierFlags, michael@0: const nsAString& aCharacters, michael@0: const nsAString& aUnmodifiedCharacters) michael@0: { michael@0: KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance(); michael@0: return keyboardLayout->SynthesizeNativeKeyEvent( michael@0: this, aNativeKeyboardLayout, aNativeKeyCode, aModifierFlags, michael@0: aCharacters, aUnmodifiedCharacters); michael@0: } michael@0: michael@0: nsresult michael@0: nsWindow::SynthesizeNativeMouseEvent(nsIntPoint aPoint, michael@0: uint32_t aNativeMessage, michael@0: uint32_t aModifierFlags) michael@0: { michael@0: ::SetCursorPos(aPoint.x, aPoint.y); michael@0: michael@0: INPUT input; michael@0: memset(&input, 0, sizeof(input)); michael@0: michael@0: input.type = INPUT_MOUSE; michael@0: input.mi.dwFlags = aNativeMessage; michael@0: ::SendInput(1, &input, sizeof(INPUT)); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsWindow::SynthesizeNativeMouseScrollEvent(nsIntPoint aPoint, michael@0: uint32_t aNativeMessage, michael@0: double aDeltaX, michael@0: double aDeltaY, michael@0: double aDeltaZ, michael@0: uint32_t aModifierFlags, michael@0: uint32_t aAdditionalFlags) michael@0: { michael@0: return MouseScrollHandler::SynthesizeNativeMouseScrollEvent( michael@0: this, aPoint, aNativeMessage, michael@0: (aNativeMessage == WM_MOUSEWHEEL || aNativeMessage == WM_VSCROLL) ? michael@0: static_cast(aDeltaY) : static_cast(aDeltaX), michael@0: aModifierFlags, aAdditionalFlags); michael@0: } michael@0: michael@0: /************************************************************** michael@0: * michael@0: * SECTION: OnXXX message handlers michael@0: * michael@0: * For message handlers that need to be broken out or michael@0: * implemented in specific platform code. michael@0: * michael@0: **************************************************************/ michael@0: michael@0: void nsWindow::OnWindowPosChanged(WINDOWPOS* wp) michael@0: { michael@0: if (wp == nullptr) michael@0: return; michael@0: michael@0: #ifdef WINSTATE_DEBUG_OUTPUT michael@0: if (mWnd == WinUtils::GetTopLevelHWND(mWnd)) { michael@0: PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("*** OnWindowPosChanged: [ top] ")); michael@0: } else { michael@0: PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("*** OnWindowPosChanged: [child] ")); michael@0: } michael@0: PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("WINDOWPOS flags:")); michael@0: if (wp->flags & SWP_FRAMECHANGED) { michael@0: PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("SWP_FRAMECHANGED ")); michael@0: } michael@0: if (wp->flags & SWP_SHOWWINDOW) { michael@0: PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("SWP_SHOWWINDOW ")); michael@0: } michael@0: if (wp->flags & SWP_NOSIZE) { michael@0: PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("SWP_NOSIZE ")); michael@0: } michael@0: if (wp->flags & SWP_HIDEWINDOW) { michael@0: PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("SWP_HIDEWINDOW ")); michael@0: } michael@0: if (wp->flags & SWP_NOZORDER) { michael@0: PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("SWP_NOZORDER ")); michael@0: } michael@0: if (wp->flags & SWP_NOACTIVATE) { michael@0: PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("SWP_NOACTIVATE ")); michael@0: } michael@0: PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("\n")); michael@0: #endif michael@0: michael@0: // Handle window size mode changes michael@0: if (wp->flags & SWP_FRAMECHANGED && mSizeMode != nsSizeMode_Fullscreen) { michael@0: michael@0: // Bug 566135 - Windows theme code calls show window on SW_SHOWMINIMIZED michael@0: // windows when fullscreen games disable desktop composition. If we're michael@0: // minimized and not being activated, ignore the event and let windows michael@0: // handle it. michael@0: if (mSizeMode == nsSizeMode_Minimized && (wp->flags & SWP_NOACTIVATE)) michael@0: return; michael@0: michael@0: WINDOWPLACEMENT pl; michael@0: pl.length = sizeof(pl); michael@0: ::GetWindowPlacement(mWnd, &pl); michael@0: michael@0: // Windows has just changed the size mode of this window. The call to michael@0: // SizeModeChanged will trigger a call into SetSizeMode where we will michael@0: // set the min/max window state again or for nsSizeMode_Normal, call michael@0: // SetWindow with a parameter of SW_RESTORE. There's no need however as michael@0: // this window's mode has already changed. Updating mSizeMode here michael@0: // insures the SetSizeMode call is a no-op. Addresses a bug on Win7 related michael@0: // to window docking. (bug 489258) michael@0: if (pl.showCmd == SW_SHOWMAXIMIZED) michael@0: mSizeMode = (mFullscreenMode ? nsSizeMode_Fullscreen : nsSizeMode_Maximized); michael@0: else if (pl.showCmd == SW_SHOWMINIMIZED) michael@0: mSizeMode = nsSizeMode_Minimized; michael@0: else if (mFullscreenMode) michael@0: mSizeMode = nsSizeMode_Fullscreen; michael@0: else michael@0: mSizeMode = nsSizeMode_Normal; michael@0: michael@0: // If !sTrimOnMinimize, we minimize windows using SW_SHOWMINIMIZED (See michael@0: // SetSizeMode for internal calls, and WM_SYSCOMMAND for external). This michael@0: // prevents the working set from being trimmed but keeps the window active. michael@0: // After the window is minimized, we need to do some touch up work on the michael@0: // active window. (bugs 76831 & 499816) michael@0: if (!sTrimOnMinimize && nsSizeMode_Minimized == mSizeMode) michael@0: ActivateOtherWindowHelper(mWnd); michael@0: michael@0: #ifdef WINSTATE_DEBUG_OUTPUT michael@0: switch (mSizeMode) { michael@0: case nsSizeMode_Normal: michael@0: PR_LOG(gWindowsLog, PR_LOG_ALWAYS, michael@0: ("*** mSizeMode: nsSizeMode_Normal\n")); michael@0: break; michael@0: case nsSizeMode_Minimized: michael@0: PR_LOG(gWindowsLog, PR_LOG_ALWAYS, michael@0: ("*** mSizeMode: nsSizeMode_Minimized\n")); michael@0: break; michael@0: case nsSizeMode_Maximized: michael@0: PR_LOG(gWindowsLog, PR_LOG_ALWAYS, michael@0: ("*** mSizeMode: nsSizeMode_Maximized\n")); michael@0: break; michael@0: default: michael@0: PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("*** mSizeMode: ??????\n")); michael@0: break; michael@0: }; michael@0: #endif michael@0: michael@0: if (mWidgetListener) michael@0: mWidgetListener->SizeModeChanged(mSizeMode); michael@0: michael@0: // If window was restored, window activation was bypassed during the michael@0: // SetSizeMode call originating from OnWindowPosChanging to avoid saving michael@0: // pre-restore attributes. Force activation now to get correct attributes. michael@0: if (mLastSizeMode != nsSizeMode_Normal && mSizeMode == nsSizeMode_Normal) michael@0: DispatchFocusToTopLevelWindow(true); michael@0: michael@0: // Skip window size change events below on minimization. michael@0: if (mSizeMode == nsSizeMode_Minimized) michael@0: return; michael@0: } michael@0: michael@0: // Handle window position changes michael@0: if (!(wp->flags & SWP_NOMOVE)) { michael@0: mBounds.x = wp->x; michael@0: mBounds.y = wp->y; michael@0: michael@0: NotifyWindowMoved(wp->x, wp->y); michael@0: } michael@0: michael@0: // Handle window size changes michael@0: if (!(wp->flags & SWP_NOSIZE)) { michael@0: RECT r; michael@0: int32_t newWidth, newHeight; michael@0: michael@0: ::GetWindowRect(mWnd, &r); michael@0: michael@0: newWidth = r.right - r.left; michael@0: newHeight = r.bottom - r.top; michael@0: nsIntRect rect(wp->x, wp->y, newWidth, newHeight); michael@0: michael@0: #ifdef MOZ_XUL michael@0: if (eTransparencyTransparent == mTransparencyMode) michael@0: ResizeTranslucentWindow(newWidth, newHeight); michael@0: #endif michael@0: michael@0: if (newWidth > mLastSize.width) michael@0: { michael@0: RECT drect; michael@0: michael@0: // getting wider michael@0: drect.left = wp->x + mLastSize.width; michael@0: drect.top = wp->y; michael@0: drect.right = drect.left + (newWidth - mLastSize.width); michael@0: drect.bottom = drect.top + newHeight; michael@0: michael@0: ::RedrawWindow(mWnd, &drect, nullptr, michael@0: RDW_INVALIDATE | michael@0: RDW_NOERASE | michael@0: RDW_NOINTERNALPAINT | michael@0: RDW_ERASENOW | michael@0: RDW_ALLCHILDREN); michael@0: } michael@0: if (newHeight > mLastSize.height) michael@0: { michael@0: RECT drect; michael@0: michael@0: // getting taller michael@0: drect.left = wp->x; michael@0: drect.top = wp->y + mLastSize.height; michael@0: drect.right = drect.left + newWidth; michael@0: drect.bottom = drect.top + (newHeight - mLastSize.height); michael@0: michael@0: ::RedrawWindow(mWnd, &drect, nullptr, michael@0: RDW_INVALIDATE | michael@0: RDW_NOERASE | michael@0: RDW_NOINTERNALPAINT | michael@0: RDW_ERASENOW | michael@0: RDW_ALLCHILDREN); michael@0: } michael@0: michael@0: mBounds.width = newWidth; michael@0: mBounds.height = newHeight; michael@0: mLastSize.width = newWidth; michael@0: mLastSize.height = newHeight; michael@0: michael@0: #ifdef WINSTATE_DEBUG_OUTPUT michael@0: PR_LOG(gWindowsLog, PR_LOG_ALWAYS, michael@0: ("*** Resize window: %d x %d x %d x %d\n", wp->x, wp->y, michael@0: newWidth, newHeight)); michael@0: #endif michael@0: michael@0: // If a maximized window is resized, recalculate the non-client margins. michael@0: if (mSizeMode == nsSizeMode_Maximized) { michael@0: if (UpdateNonClientMargins(nsSizeMode_Maximized, true)) { michael@0: // gecko resize event already sent by UpdateNonClientMargins. michael@0: return; michael@0: } michael@0: } michael@0: michael@0: // Recalculate the width and height based on the client area for gecko events. michael@0: if (::GetClientRect(mWnd, &r)) { michael@0: rect.width = r.right - r.left; michael@0: rect.height = r.bottom - r.top; michael@0: } michael@0: michael@0: // Send a gecko resize event michael@0: OnResize(rect); michael@0: } michael@0: } michael@0: michael@0: // static michael@0: void nsWindow::ActivateOtherWindowHelper(HWND aWnd) michael@0: { michael@0: // Find the next window that is enabled, visible, and not minimized. michael@0: HWND hwndBelow = ::GetNextWindow(aWnd, GW_HWNDNEXT); michael@0: while (hwndBelow && (!::IsWindowEnabled(hwndBelow) || !::IsWindowVisible(hwndBelow) || michael@0: ::IsIconic(hwndBelow))) { michael@0: hwndBelow = ::GetNextWindow(hwndBelow, GW_HWNDNEXT); michael@0: } michael@0: michael@0: // Push ourselves to the bottom of the stack, then activate the michael@0: // next window. michael@0: ::SetWindowPos(aWnd, HWND_BOTTOM, 0, 0, 0, 0, michael@0: SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); michael@0: if (hwndBelow) michael@0: ::SetForegroundWindow(hwndBelow); michael@0: michael@0: // Play the minimize sound while we're here, since that is also michael@0: // forgotten when we use SW_SHOWMINIMIZED. michael@0: nsCOMPtr sound(do_CreateInstance("@mozilla.org/sound;1")); michael@0: if (sound) { michael@0: sound->PlaySystemSound(NS_LITERAL_STRING("Minimize")); michael@0: } michael@0: } michael@0: michael@0: void nsWindow::OnWindowPosChanging(LPWINDOWPOS& info) michael@0: { michael@0: // Update non-client margins if the frame size is changing, and let the michael@0: // browser know we are changing size modes, so alternative css can kick in. michael@0: // If we're going into fullscreen mode, ignore this, since it'll reset michael@0: // margins to normal mode. michael@0: if ((info->flags & SWP_FRAMECHANGED && !(info->flags & SWP_NOSIZE)) && michael@0: mSizeMode != nsSizeMode_Fullscreen) { michael@0: WINDOWPLACEMENT pl; michael@0: pl.length = sizeof(pl); michael@0: ::GetWindowPlacement(mWnd, &pl); michael@0: nsSizeMode sizeMode; michael@0: if (pl.showCmd == SW_SHOWMAXIMIZED) michael@0: sizeMode = (mFullscreenMode ? nsSizeMode_Fullscreen : nsSizeMode_Maximized); michael@0: else if (pl.showCmd == SW_SHOWMINIMIZED) michael@0: sizeMode = nsSizeMode_Minimized; michael@0: else if (mFullscreenMode) michael@0: sizeMode = nsSizeMode_Fullscreen; michael@0: else michael@0: sizeMode = nsSizeMode_Normal; michael@0: michael@0: if (mWidgetListener) michael@0: mWidgetListener->SizeModeChanged(sizeMode); michael@0: michael@0: UpdateNonClientMargins(sizeMode, false); michael@0: } michael@0: michael@0: // enforce local z-order rules michael@0: if (!(info->flags & SWP_NOZORDER)) { michael@0: HWND hwndAfter = info->hwndInsertAfter; michael@0: michael@0: nsWindow *aboveWindow = 0; michael@0: nsWindowZ placement; michael@0: michael@0: if (hwndAfter == HWND_BOTTOM) michael@0: placement = nsWindowZBottom; michael@0: else if (hwndAfter == HWND_TOP || hwndAfter == HWND_TOPMOST || hwndAfter == HWND_NOTOPMOST) michael@0: placement = nsWindowZTop; michael@0: else { michael@0: placement = nsWindowZRelative; michael@0: aboveWindow = WinUtils::GetNSWindowPtr(hwndAfter); michael@0: } michael@0: michael@0: if (mWidgetListener) { michael@0: nsCOMPtr actualBelow = nullptr; michael@0: if (mWidgetListener->ZLevelChanged(false, &placement, michael@0: aboveWindow, getter_AddRefs(actualBelow))) { michael@0: if (placement == nsWindowZBottom) michael@0: info->hwndInsertAfter = HWND_BOTTOM; michael@0: else if (placement == nsWindowZTop) michael@0: info->hwndInsertAfter = HWND_TOP; michael@0: else { michael@0: info->hwndInsertAfter = (HWND)actualBelow->GetNativeData(NS_NATIVE_WINDOW); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: // prevent rude external programs from making hidden window visible michael@0: if (mWindowType == eWindowType_invisible) michael@0: info->flags &= ~SWP_SHOWWINDOW; michael@0: } michael@0: michael@0: void nsWindow::UserActivity() michael@0: { michael@0: // Check if we have the idle service, if not we try to get it. michael@0: if (!mIdleService) { michael@0: mIdleService = do_GetService("@mozilla.org/widget/idleservice;1"); michael@0: } michael@0: michael@0: // Check that we now have the idle service. michael@0: if (mIdleService) { michael@0: mIdleService->ResetIdleTimeOut(0); michael@0: } michael@0: } michael@0: michael@0: bool nsWindow::OnTouch(WPARAM wParam, LPARAM lParam) michael@0: { michael@0: uint32_t cInputs = LOWORD(wParam); michael@0: PTOUCHINPUT pInputs = new TOUCHINPUT[cInputs]; michael@0: michael@0: if (mGesture.GetTouchInputInfo((HTOUCHINPUT)lParam, cInputs, pInputs)) { michael@0: WidgetTouchEvent* touchEventToSend = nullptr; michael@0: WidgetTouchEvent* touchEndEventToSend = nullptr; michael@0: nsEventStatus status; michael@0: michael@0: // Walk across the touch point array processing each contact point michael@0: for (uint32_t i = 0; i < cInputs; i++) { michael@0: uint32_t msg; michael@0: michael@0: if (pInputs[i].dwFlags & (TOUCHEVENTF_DOWN | TOUCHEVENTF_MOVE)) { michael@0: // Create a standard touch event to send michael@0: if (!touchEventToSend) { michael@0: touchEventToSend = new WidgetTouchEvent(true, NS_TOUCH_MOVE, this); michael@0: touchEventToSend->time = ::GetMessageTime(); michael@0: ModifierKeyState modifierKeyState; michael@0: modifierKeyState.InitInputEvent(*touchEventToSend); michael@0: } michael@0: michael@0: // Pres shell expects this event to be a NS_TOUCH_START if new contact michael@0: // points have been added since the last event sent. michael@0: if (pInputs[i].dwFlags & TOUCHEVENTF_DOWN) { michael@0: touchEventToSend->message = msg = NS_TOUCH_START; michael@0: } else { michael@0: msg = NS_TOUCH_MOVE; michael@0: } michael@0: } else if (pInputs[i].dwFlags & TOUCHEVENTF_UP) { michael@0: // Pres shell expects removed contacts points to be delivered in a michael@0: // separate NS_TOUCH_END event containing only the contact points michael@0: // that were removed. michael@0: if (!touchEndEventToSend) { michael@0: touchEndEventToSend = new WidgetTouchEvent(true, NS_TOUCH_END, this); michael@0: touchEndEventToSend->time = ::GetMessageTime(); michael@0: ModifierKeyState modifierKeyState; michael@0: modifierKeyState.InitInputEvent(*touchEndEventToSend); michael@0: } michael@0: msg = NS_TOUCH_END; michael@0: } else { michael@0: // Filter out spurious Windows events we don't understand, like palm michael@0: // contact. michael@0: continue; michael@0: } michael@0: michael@0: // Setup the touch point we'll append to the touch event array michael@0: nsPointWin touchPoint; michael@0: touchPoint.x = TOUCH_COORD_TO_PIXEL(pInputs[i].x); michael@0: touchPoint.y = TOUCH_COORD_TO_PIXEL(pInputs[i].y); michael@0: touchPoint.ScreenToClient(mWnd); michael@0: nsRefPtr touch = michael@0: new Touch(pInputs[i].dwID, michael@0: touchPoint, michael@0: /* radius, if known */ michael@0: pInputs[i].dwFlags & TOUCHINPUTMASKF_CONTACTAREA ? michael@0: nsIntPoint( michael@0: TOUCH_COORD_TO_PIXEL(pInputs[i].cxContact) / 2, michael@0: TOUCH_COORD_TO_PIXEL(pInputs[i].cyContact) / 2) : michael@0: nsIntPoint(1,1), michael@0: /* rotation angle and force */ michael@0: 0.0f, 0.0f); michael@0: michael@0: // Append to the appropriate event michael@0: if (msg == NS_TOUCH_START || msg == NS_TOUCH_MOVE) { michael@0: touchEventToSend->touches.AppendElement(touch); michael@0: } else { michael@0: touchEndEventToSend->touches.AppendElement(touch); michael@0: } michael@0: } michael@0: michael@0: // Dispatch touch start and move event if we have one. michael@0: if (touchEventToSend) { michael@0: DispatchEvent(touchEventToSend, status); michael@0: delete touchEventToSend; michael@0: } michael@0: michael@0: // Dispatch touch end event if we have one. michael@0: if (touchEndEventToSend) { michael@0: DispatchEvent(touchEndEventToSend, status); michael@0: delete touchEndEventToSend; michael@0: } michael@0: } michael@0: michael@0: delete [] pInputs; michael@0: mGesture.CloseTouchInputHandle((HTOUCHINPUT)lParam); michael@0: return true; michael@0: } michael@0: michael@0: static int32_t RoundDown(double aDouble) michael@0: { michael@0: return aDouble > 0 ? static_cast(floor(aDouble)) : michael@0: static_cast(ceil(aDouble)); michael@0: } michael@0: michael@0: // Gesture event processing. Handles WM_GESTURE events. michael@0: bool nsWindow::OnGesture(WPARAM wParam, LPARAM lParam) michael@0: { michael@0: if (gIsPointerEventsEnabled) { michael@0: return false; michael@0: } michael@0: michael@0: // Treatment for pan events which translate into scroll events: michael@0: if (mGesture.IsPanEvent(lParam)) { michael@0: if ( !mGesture.ProcessPanMessage(mWnd, wParam, lParam) ) michael@0: return false; // ignore michael@0: michael@0: nsEventStatus status; michael@0: michael@0: WidgetWheelEvent wheelEvent(true, NS_WHEEL_WHEEL, this); michael@0: michael@0: ModifierKeyState modifierKeyState; michael@0: modifierKeyState.InitInputEvent(wheelEvent); michael@0: michael@0: wheelEvent.button = 0; michael@0: wheelEvent.time = ::GetMessageTime(); michael@0: wheelEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH; michael@0: michael@0: bool endFeedback = true; michael@0: michael@0: if (mGesture.PanDeltaToPixelScroll(wheelEvent)) { michael@0: DispatchEvent(&wheelEvent, status); michael@0: } michael@0: michael@0: if (mDisplayPanFeedback) { michael@0: mGesture.UpdatePanFeedbackX(mWnd, michael@0: DeprecatedAbs(RoundDown(wheelEvent.overflowDeltaX)), michael@0: endFeedback); michael@0: mGesture.UpdatePanFeedbackY(mWnd, michael@0: DeprecatedAbs(RoundDown(wheelEvent.overflowDeltaY)), michael@0: endFeedback); michael@0: mGesture.PanFeedbackFinalize(mWnd, endFeedback); michael@0: } michael@0: michael@0: mGesture.CloseGestureInfoHandle((HGESTUREINFO)lParam); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: // Other gestures translate into simple gesture events: michael@0: WidgetSimpleGestureEvent event(true, 0, this); michael@0: if ( !mGesture.ProcessGestureMessage(mWnd, wParam, lParam, event) ) { michael@0: return false; // fall through to DefWndProc michael@0: } michael@0: michael@0: // Polish up and send off the new event michael@0: ModifierKeyState modifierKeyState; michael@0: modifierKeyState.InitInputEvent(event); michael@0: event.button = 0; michael@0: event.time = ::GetMessageTime(); michael@0: event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH; michael@0: michael@0: nsEventStatus status; michael@0: DispatchEvent(&event, status); michael@0: if (status == nsEventStatus_eIgnore) { michael@0: return false; // Ignored, fall through michael@0: } michael@0: michael@0: // Only close this if we process and return true. michael@0: mGesture.CloseGestureInfoHandle((HGESTUREINFO)lParam); michael@0: michael@0: return true; // Handled michael@0: } michael@0: michael@0: static BOOL WINAPI EnumFirstChild(HWND hwnd, LPARAM lParam) michael@0: { michael@0: *((HWND*)lParam) = hwnd; michael@0: return FALSE; michael@0: } michael@0: michael@0: static void InvalidatePluginAsWorkaround(nsWindow *aWindow, const nsIntRect &aRect) michael@0: { michael@0: aWindow->Invalidate(aRect); michael@0: michael@0: // XXX - Even more evil workaround!! See bug 762948, flash's bottom michael@0: // level sandboxed window doesn't seem to get our invalidate. We send michael@0: // an invalidate to it manually. This is totally specialized for this michael@0: // bug, for other child window structures this will just be a more or michael@0: // less bogus invalidate but since that should not have any bad michael@0: // side-effects this will have to do for now. michael@0: HWND current = (HWND)aWindow->GetNativeData(NS_NATIVE_WINDOW); michael@0: michael@0: RECT windowRect; michael@0: RECT parentRect; michael@0: michael@0: ::GetWindowRect(current, &parentRect); michael@0: michael@0: HWND next = current; michael@0: michael@0: do { michael@0: current = next; michael@0: michael@0: ::EnumChildWindows(current, &EnumFirstChild, (LPARAM)&next); michael@0: michael@0: ::GetWindowRect(next, &windowRect); michael@0: // This is relative to the screen, adjust it to be relative to the michael@0: // window we're reconfiguring. michael@0: windowRect.left -= parentRect.left; michael@0: windowRect.top -= parentRect.top; michael@0: } while (next != current && windowRect.top == 0 && windowRect.left == 0); michael@0: michael@0: if (windowRect.top == 0 && windowRect.left == 0) { michael@0: RECT rect; michael@0: rect.left = aRect.x; michael@0: rect.top = aRect.y; michael@0: rect.right = aRect.XMost(); michael@0: rect.bottom = aRect.YMost(); michael@0: michael@0: ::InvalidateRect(next, &rect, FALSE); michael@0: } michael@0: } michael@0: michael@0: nsresult michael@0: nsWindow::ConfigureChildren(const nsTArray& aConfigurations) michael@0: { michael@0: // XXXroc we could use BeginDeferWindowPos/DeferWindowPos/EndDeferWindowPos michael@0: // here, if that helps in some situations. So far I haven't seen a michael@0: // need. michael@0: for (uint32_t i = 0; i < aConfigurations.Length(); ++i) { michael@0: const Configuration& configuration = aConfigurations[i]; michael@0: nsWindow* w = static_cast(configuration.mChild); michael@0: NS_ASSERTION(w->GetParent() == this, michael@0: "Configured widget is not a child"); michael@0: nsresult rv = w->SetWindowClipRegion(configuration.mClipRegion, true); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: nsIntRect bounds; michael@0: w->GetBounds(bounds); michael@0: if (bounds.Size() != configuration.mBounds.Size()) { michael@0: w->Resize(configuration.mBounds.x, configuration.mBounds.y, michael@0: configuration.mBounds.width, configuration.mBounds.height, michael@0: true); michael@0: } else if (bounds.TopLeft() != configuration.mBounds.TopLeft()) { michael@0: w->Move(configuration.mBounds.x, configuration.mBounds.y); michael@0: michael@0: michael@0: if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() == michael@0: gfxWindowsPlatform::RENDER_DIRECT2D || michael@0: GetLayerManager()->GetBackendType() != LayersBackend::LAYERS_BASIC) { michael@0: // XXX - Workaround for Bug 587508. This will invalidate the part of the michael@0: // plugin window that might be touched by moving content somehow. The michael@0: // underlying problem should be found and fixed! michael@0: nsIntRegion r; michael@0: r.Sub(bounds, configuration.mBounds); michael@0: r.MoveBy(-bounds.x, michael@0: -bounds.y); michael@0: nsIntRect toInvalidate = r.GetBounds(); michael@0: michael@0: InvalidatePluginAsWorkaround(w, toInvalidate); michael@0: } michael@0: } michael@0: rv = w->SetWindowClipRegion(configuration.mClipRegion, false); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: static HRGN michael@0: CreateHRGNFromArray(const nsTArray& aRects) michael@0: { michael@0: int32_t size = sizeof(RGNDATAHEADER) + sizeof(RECT)*aRects.Length(); michael@0: nsAutoTArray buf; michael@0: buf.SetLength(size); michael@0: RGNDATA* data = reinterpret_cast(buf.Elements()); michael@0: RECT* rects = reinterpret_cast(data->Buffer); michael@0: data->rdh.dwSize = sizeof(data->rdh); michael@0: data->rdh.iType = RDH_RECTANGLES; michael@0: data->rdh.nCount = aRects.Length(); michael@0: nsIntRect bounds; michael@0: for (uint32_t i = 0; i < aRects.Length(); ++i) { michael@0: const nsIntRect& r = aRects[i]; michael@0: bounds.UnionRect(bounds, r); michael@0: ::SetRect(&rects[i], r.x, r.y, r.XMost(), r.YMost()); michael@0: } michael@0: ::SetRect(&data->rdh.rcBound, bounds.x, bounds.y, bounds.XMost(), bounds.YMost()); michael@0: return ::ExtCreateRegion(nullptr, buf.Length(), data); michael@0: } michael@0: michael@0: static void michael@0: ArrayFromRegion(const nsIntRegion& aRegion, nsTArray& aRects) michael@0: { michael@0: const nsIntRect* r; michael@0: for (nsIntRegionRectIterator iter(aRegion); (r = iter.Next());) { michael@0: aRects.AppendElement(*r); michael@0: } michael@0: } michael@0: michael@0: nsresult michael@0: nsWindow::SetWindowClipRegion(const nsTArray& aRects, michael@0: bool aIntersectWithExisting) michael@0: { michael@0: if (!aIntersectWithExisting) { michael@0: if (!StoreWindowClipRegion(aRects)) michael@0: return NS_OK; michael@0: } else { michael@0: // In this case still early return if nothing changed. michael@0: if (mClipRects && mClipRectCount == aRects.Length() && michael@0: memcmp(mClipRects, michael@0: aRects.Elements(), michael@0: sizeof(nsIntRect)*mClipRectCount) == 0) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: // get current rects michael@0: nsTArray currentRects; michael@0: GetWindowClipRegion(¤tRects); michael@0: // create region from them michael@0: nsIntRegion currentRegion = RegionFromArray(currentRects); michael@0: // create region from new rects michael@0: nsIntRegion newRegion = RegionFromArray(aRects); michael@0: // intersect regions michael@0: nsIntRegion intersection; michael@0: intersection.And(currentRegion, newRegion); michael@0: // create int rect array from intersection michael@0: nsTArray rects; michael@0: ArrayFromRegion(intersection, rects); michael@0: // store michael@0: if (!StoreWindowClipRegion(rects)) michael@0: return NS_OK; michael@0: } michael@0: michael@0: HRGN dest = CreateHRGNFromArray(aRects); michael@0: if (!dest) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: if (aIntersectWithExisting) { michael@0: HRGN current = ::CreateRectRgn(0, 0, 0, 0); michael@0: if (current) { michael@0: if (::GetWindowRgn(mWnd, current) != 0 /*ERROR*/) { michael@0: ::CombineRgn(dest, dest, current, RGN_AND); michael@0: } michael@0: ::DeleteObject(current); michael@0: } michael@0: } michael@0: michael@0: // If a plugin is not visible, especially if it is in a background tab, michael@0: // it should not be able to steal keyboard focus. This code checks whether michael@0: // the region that the plugin is being clipped to is NULLREGION. If it is, michael@0: // the plugin window gets disabled. michael@0: if(mWindowType == eWindowType_plugin) { michael@0: if(NULLREGION == ::CombineRgn(dest, dest, dest, RGN_OR)) { michael@0: ::ShowWindow(mWnd, SW_HIDE); michael@0: ::EnableWindow(mWnd, FALSE); michael@0: } else { michael@0: ::EnableWindow(mWnd, TRUE); michael@0: ::ShowWindow(mWnd, SW_SHOW); michael@0: } michael@0: } michael@0: if (!::SetWindowRgn(mWnd, dest, TRUE)) { michael@0: ::DeleteObject(dest); michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: // WM_DESTROY event handler michael@0: void nsWindow::OnDestroy() michael@0: { michael@0: mOnDestroyCalled = true; michael@0: michael@0: // Make sure we don't get destroyed in the process of tearing down. michael@0: nsCOMPtr kungFuDeathGrip(this); michael@0: michael@0: // Dispatch the destroy notification. michael@0: if (!mInDtor) michael@0: NotifyWindowDestroyed(); michael@0: michael@0: // Prevent the widget from sending additional events. michael@0: mWidgetListener = nullptr; michael@0: mAttachedWidgetListener = nullptr; michael@0: michael@0: // Free our subclass and clear |this| stored in the window props. We will no longer michael@0: // receive events from Windows after this point. michael@0: SubclassWindow(FALSE); michael@0: michael@0: // Once mWidgetListener is cleared and the subclass is reset, sCurrentWindow can be michael@0: // cleared. (It's used in tracking windows for mouse events.) michael@0: if (sCurrentWindow == this) michael@0: sCurrentWindow = nullptr; michael@0: michael@0: // Disconnects us from our parent, will call our GetParent(). michael@0: nsBaseWidget::Destroy(); michael@0: michael@0: // Release references to children, device context, toolkit, and app shell. michael@0: nsBaseWidget::OnDestroy(); michael@0: michael@0: // Clear our native parent handle. michael@0: // XXX Windows will take care of this in the proper order, and SetParent(nullptr)'s michael@0: // remove child on the parent already took place in nsBaseWidget's Destroy call above. michael@0: //SetParent(nullptr); michael@0: mParent = nullptr; michael@0: michael@0: // We have to destroy the native drag target before we null out our window pointer. michael@0: EnableDragDrop(false); michael@0: michael@0: // If we're going away and for some reason we're still the rollup widget, rollup and michael@0: // turn off capture. michael@0: nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener(); michael@0: nsCOMPtr rollupWidget; michael@0: if (rollupListener) { michael@0: rollupWidget = rollupListener->GetRollupWidget(); michael@0: } michael@0: if (this == rollupWidget) { michael@0: if ( rollupListener ) michael@0: rollupListener->Rollup(0, nullptr, nullptr); michael@0: CaptureRollupEvents(nullptr, false); michael@0: } michael@0: michael@0: IMEHandler::OnDestroyWindow(this); michael@0: michael@0: // Turn off mouse trails if enabled. michael@0: MouseTrailer* mtrailer = nsToolkit::gMouseTrailer; michael@0: if (mtrailer) { michael@0: if (mtrailer->GetMouseTrailerWindow() == mWnd) michael@0: mtrailer->DestroyTimer(); michael@0: michael@0: if (mtrailer->GetCaptureWindow() == mWnd) michael@0: mtrailer->SetCaptureWindow(nullptr); michael@0: } michael@0: michael@0: // Free GDI window class objects michael@0: if (mBrush) { michael@0: VERIFY(::DeleteObject(mBrush)); michael@0: mBrush = nullptr; michael@0: } michael@0: michael@0: michael@0: // Destroy any custom cursor resources. michael@0: if (mCursor == -1) michael@0: SetCursor(eCursor_standard); michael@0: michael@0: #ifdef MOZ_XUL michael@0: // Reset transparency michael@0: if (eTransparencyTransparent == mTransparencyMode) michael@0: SetupTranslucentWindowMemoryBitmap(eTransparencyOpaque); michael@0: #endif michael@0: michael@0: // Finalize panning feedback to possibly restore window displacement michael@0: mGesture.PanFeedbackFinalize(mWnd, true); michael@0: michael@0: // Clear the main HWND. michael@0: mWnd = nullptr; michael@0: } michael@0: michael@0: // Send a resize message to the listener michael@0: bool nsWindow::OnResize(nsIntRect &aWindowRect) michael@0: { michael@0: bool result = mWidgetListener ? michael@0: mWidgetListener->WindowResized(this, aWindowRect.width, aWindowRect.height) : false; michael@0: michael@0: // If there is an attached view, inform it as well as the normal widget listener. michael@0: if (mAttachedWidgetListener) { michael@0: return mAttachedWidgetListener->WindowResized(this, aWindowRect.width, aWindowRect.height); michael@0: } michael@0: michael@0: return result; michael@0: } michael@0: michael@0: bool nsWindow::OnHotKey(WPARAM wParam, LPARAM lParam) michael@0: { michael@0: return true; michael@0: } michael@0: michael@0: // Can be overriden. Controls auto-erase of background. michael@0: bool nsWindow::AutoErase(HDC dc) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: void michael@0: nsWindow::AllowD3D9Callback(nsWindow *aWindow) michael@0: { michael@0: if (aWindow->mLayerManager && !aWindow->ShouldUseOffMainThreadCompositing()) { michael@0: aWindow->mLayerManager->Destroy(); michael@0: aWindow->mLayerManager = nullptr; michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsWindow::AllowD3D9WithReinitializeCallback(nsWindow *aWindow) michael@0: { michael@0: if (aWindow->mLayerManager && !aWindow->ShouldUseOffMainThreadCompositing()) { michael@0: aWindow->mLayerManager->Destroy(); michael@0: aWindow->mLayerManager = nullptr; michael@0: (void) aWindow->GetLayerManager(); michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsWindow::StartAllowingD3D9(bool aReinitialize) michael@0: { michael@0: sAllowD3D9 = true; michael@0: michael@0: LayerManagerPrefs prefs; michael@0: GetLayerManagerPrefs(&prefs); michael@0: if (prefs.mDisableAcceleration) { michael@0: // The guarantee here is, if there's *any* chance that after we michael@0: // throw out our layer managers we'd create at least one new, michael@0: // accelerated one, we *will* throw out all the current layer michael@0: // managers. We early-return here because currently, if michael@0: // |disableAcceleration|, we will always use basic managers and michael@0: // it's a waste to recreate them. If we're using OMTC we don't want to michael@0: // recreate out layer manager and its compositor either. This is even michael@0: // more wasteful. michael@0: // michael@0: // NB: the above implies that it's eminently possible for us to michael@0: // skip this early return but still recreate basic managers. michael@0: // That's OK. It's *not* OK to take this early return when we michael@0: // *might* have created an accelerated manager. michael@0: return; michael@0: } michael@0: michael@0: if (aReinitialize) { michael@0: EnumAllWindows(AllowD3D9WithReinitializeCallback); michael@0: } else { michael@0: EnumAllWindows(AllowD3D9Callback); michael@0: } michael@0: } michael@0: michael@0: bool michael@0: nsWindow::ShouldUseOffMainThreadCompositing() michael@0: { michael@0: // We don't currently support using an accelerated layer manager with michael@0: // transparent windows so don't even try. I'm also not sure if we even michael@0: // want to support this case. See bug 593471 michael@0: if (mTransparencyMode == eTransparencyTransparent) { michael@0: return false; michael@0: } michael@0: michael@0: return nsBaseWidget::ShouldUseOffMainThreadCompositing(); michael@0: } michael@0: michael@0: void michael@0: nsWindow::GetPreferredCompositorBackends(nsTArray& aHints) michael@0: { michael@0: LayerManagerPrefs prefs; michael@0: GetLayerManagerPrefs(&prefs); michael@0: michael@0: // We don't currently support using an accelerated layer manager with michael@0: // transparent windows so don't even try. I'm also not sure if we even michael@0: // want to support this case. See bug 593471 michael@0: if (!(prefs.mDisableAcceleration || michael@0: mTransparencyMode == eTransparencyTransparent)) { michael@0: if (prefs.mPreferOpenGL) { michael@0: aHints.AppendElement(LayersBackend::LAYERS_OPENGL); michael@0: } michael@0: if (!prefs.mPreferD3D9) { michael@0: aHints.AppendElement(LayersBackend::LAYERS_D3D11); michael@0: } michael@0: aHints.AppendElement(LayersBackend::LAYERS_D3D9); michael@0: } michael@0: aHints.AppendElement(LayersBackend::LAYERS_BASIC); michael@0: } michael@0: michael@0: void michael@0: nsWindow::WindowUsesOMTC() michael@0: { michael@0: ULONG_PTR style = ::GetClassLongPtr(mWnd, GCL_STYLE); michael@0: if (!style) { michael@0: NS_WARNING("Could not get window class style"); michael@0: return; michael@0: } michael@0: style |= CS_HREDRAW | CS_VREDRAW; michael@0: DebugOnly result = ::SetClassLongPtr(mWnd, GCL_STYLE, style); michael@0: NS_WARN_IF_FALSE(result, "Could not reset window class style"); michael@0: } michael@0: michael@0: bool michael@0: nsWindow::HasBogusPopupsDropShadowOnMultiMonitor() { michael@0: if (sHasBogusPopupsDropShadowOnMultiMonitor == TRI_UNKNOWN) { michael@0: // Since any change in the preferences requires a restart, this can be michael@0: // done just once. michael@0: // Check for Direct2D first. michael@0: sHasBogusPopupsDropShadowOnMultiMonitor = michael@0: gfxWindowsPlatform::GetPlatform()->GetRenderMode() == michael@0: gfxWindowsPlatform::RENDER_DIRECT2D ? TRI_TRUE : TRI_FALSE; michael@0: if (!sHasBogusPopupsDropShadowOnMultiMonitor) { michael@0: // Otherwise check if Direct3D 9 may be used. michael@0: LayerManagerPrefs prefs; michael@0: GetLayerManagerPrefs(&prefs); michael@0: if (!prefs.mDisableAcceleration && !prefs.mPreferOpenGL) { michael@0: nsCOMPtr gfxInfo = do_GetService("@mozilla.org/gfx/info;1"); michael@0: if (gfxInfo) { michael@0: int32_t status; michael@0: if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, &status))) { michael@0: if (status == nsIGfxInfo::FEATURE_NO_INFO || prefs.mForceAcceleration) michael@0: { michael@0: sHasBogusPopupsDropShadowOnMultiMonitor = TRI_TRUE; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: return !!sHasBogusPopupsDropShadowOnMultiMonitor; michael@0: } michael@0: michael@0: void michael@0: nsWindow::OnSysColorChanged() michael@0: { michael@0: if (mWindowType == eWindowType_invisible) { michael@0: ::EnumThreadWindows(GetCurrentThreadId(), nsWindow::BroadcastMsg, WM_SYSCOLORCHANGE); michael@0: } michael@0: else { michael@0: // Note: This is sent for child windows as well as top-level windows. michael@0: // The Win32 toolkit normally only sends these events to top-level windows. michael@0: // But we cycle through all of the childwindows and send it to them as well michael@0: // so all presentations get notified properly. michael@0: // See nsWindow::GlobalMsgWindowProc. michael@0: NotifySysColorChanged(); michael@0: } michael@0: } michael@0: michael@0: /************************************************************** michael@0: ************************************************************** michael@0: ** michael@0: ** BLOCK: IME management and accessibility michael@0: ** michael@0: ** Handles managing IME input and accessibility. michael@0: ** michael@0: ************************************************************** michael@0: **************************************************************/ michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::NotifyIME(const IMENotification& aIMENotification) michael@0: { michael@0: return IMEHandler::NotifyIME(this, aIMENotification); michael@0: } michael@0: michael@0: NS_IMETHODIMP_(void) michael@0: nsWindow::SetInputContext(const InputContext& aContext, michael@0: const InputContextAction& aAction) michael@0: { michael@0: InputContext newInputContext = aContext; michael@0: IMEHandler::SetInputContext(this, newInputContext, aAction); michael@0: mInputContext = newInputContext; michael@0: } michael@0: michael@0: NS_IMETHODIMP_(InputContext) michael@0: nsWindow::GetInputContext() michael@0: { michael@0: mInputContext.mIMEState.mOpen = IMEState::CLOSED; michael@0: if (WinUtils::IsIMEEnabled(mInputContext) && IMEHandler::GetOpenState(this)) { michael@0: mInputContext.mIMEState.mOpen = IMEState::OPEN; michael@0: } else { michael@0: mInputContext.mIMEState.mOpen = IMEState::CLOSED; michael@0: } michael@0: return mInputContext; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsWindow::GetToggledKeyState(uint32_t aKeyCode, bool* aLEDState) michael@0: { michael@0: #ifdef DEBUG_KBSTATE michael@0: PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("GetToggledKeyState\n")); michael@0: #endif michael@0: NS_ENSURE_ARG_POINTER(aLEDState); michael@0: *aLEDState = (::GetKeyState(aKeyCode) & 1) != 0; michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsIMEUpdatePreference michael@0: nsWindow::GetIMEUpdatePreference() michael@0: { michael@0: return IMEHandler::GetUpdatePreference(); michael@0: } michael@0: michael@0: #ifdef ACCESSIBILITY michael@0: #ifdef DEBUG michael@0: #define NS_LOG_WMGETOBJECT(aWnd, aHwnd, aAcc) \ michael@0: if (a11y::logging::IsEnabled(a11y::logging::ePlatforms)) { \ michael@0: printf("Get the window:\n {\n HWND: %d, parent HWND: %d, wndobj: %p,\n",\ michael@0: aHwnd, ::GetParent(aHwnd), aWnd); \ michael@0: printf(" acc: %p", aAcc); \ michael@0: if (aAcc) { \ michael@0: nsAutoString name; \ michael@0: aAcc->Name(name); \ michael@0: printf(", accname: %s", NS_ConvertUTF16toUTF8(name).get()); \ michael@0: } \ michael@0: printf("\n }\n"); \ michael@0: } michael@0: michael@0: #else michael@0: #define NS_LOG_WMGETOBJECT(aWnd, aHwnd, aAcc) michael@0: #endif michael@0: michael@0: a11y::Accessible* michael@0: nsWindow::GetAccessible() michael@0: { michael@0: // If the pref was ePlatformIsDisabled, return null here, disabling a11y. michael@0: if (a11y::PlatformDisabledState() == a11y::ePlatformIsDisabled) michael@0: return nullptr; michael@0: michael@0: if (mInDtor || mOnDestroyCalled || mWindowType == eWindowType_invisible) { michael@0: return nullptr; michael@0: } michael@0: michael@0: // In case of popup window return a popup accessible. michael@0: nsView* view = nsView::GetViewFor(this); michael@0: if (view) { michael@0: nsIFrame* frame = view->GetFrame(); michael@0: if (frame && nsLayoutUtils::IsPopup(frame)) { michael@0: nsCOMPtr accService = michael@0: services::GetAccessibilityService(); michael@0: if (accService) { michael@0: a11y::DocAccessible* docAcc = michael@0: GetAccService()->GetDocAccessible(frame->PresContext()->PresShell()); michael@0: if (docAcc) { michael@0: NS_LOG_WMGETOBJECT(this, mWnd, michael@0: docAcc->GetAccessibleOrDescendant(frame->GetContent())); michael@0: return docAcc->GetAccessibleOrDescendant(frame->GetContent()); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: // otherwise root document accessible. michael@0: NS_LOG_WMGETOBJECT(this, mWnd, GetRootAccessible()); michael@0: return GetRootAccessible(); michael@0: } michael@0: #endif michael@0: michael@0: /************************************************************** michael@0: ************************************************************** michael@0: ** michael@0: ** BLOCK: Transparency michael@0: ** michael@0: ** Window transparency helpers. michael@0: ** michael@0: ************************************************************** michael@0: **************************************************************/ michael@0: michael@0: #ifdef MOZ_XUL michael@0: michael@0: void nsWindow::ResizeTranslucentWindow(int32_t aNewWidth, int32_t aNewHeight, bool force) michael@0: { michael@0: if (!force && aNewWidth == mBounds.width && aNewHeight == mBounds.height) michael@0: return; michael@0: michael@0: nsRefPtr newSurface = michael@0: new gfxWindowsSurface(gfxIntSize(aNewWidth, aNewHeight), gfxImageFormat::ARGB32); michael@0: mTransparentSurface = newSurface; michael@0: mMemoryDC = newSurface->GetDC(); michael@0: } michael@0: michael@0: void nsWindow::SetWindowTranslucencyInner(nsTransparencyMode aMode) michael@0: { michael@0: if (aMode == mTransparencyMode) michael@0: return; michael@0: michael@0: // stop on dialogs and popups! michael@0: HWND hWnd = WinUtils::GetTopLevelHWND(mWnd, true); michael@0: nsWindow* parent = WinUtils::GetNSWindowPtr(hWnd); michael@0: michael@0: if (!parent) michael@0: { michael@0: NS_WARNING("Trying to use transparent chrome in an embedded context"); michael@0: return; michael@0: } michael@0: michael@0: if (parent != this) { michael@0: NS_WARNING("Setting SetWindowTranslucencyInner on a parent this is not us!"); michael@0: } michael@0: michael@0: if (aMode == eTransparencyTransparent) { michael@0: // If we're switching to the use of a transparent window, hide the chrome michael@0: // on our parent. michael@0: HideWindowChrome(true); michael@0: } else if (mHideChrome && mTransparencyMode == eTransparencyTransparent) { michael@0: // if we're switching out of transparent, re-enable our parent's chrome. michael@0: HideWindowChrome(false); michael@0: } michael@0: michael@0: LONG_PTR style = ::GetWindowLongPtrW(hWnd, GWL_STYLE), michael@0: exStyle = ::GetWindowLongPtr(hWnd, GWL_EXSTYLE); michael@0: michael@0: if (parent->mIsVisible) michael@0: style |= WS_VISIBLE; michael@0: if (parent->mSizeMode == nsSizeMode_Maximized) michael@0: style |= WS_MAXIMIZE; michael@0: else if (parent->mSizeMode == nsSizeMode_Minimized) michael@0: style |= WS_MINIMIZE; michael@0: michael@0: if (aMode == eTransparencyTransparent) michael@0: exStyle |= WS_EX_LAYERED; michael@0: else michael@0: exStyle &= ~WS_EX_LAYERED; michael@0: michael@0: VERIFY_WINDOW_STYLE(style); michael@0: ::SetWindowLongPtrW(hWnd, GWL_STYLE, style); michael@0: ::SetWindowLongPtrW(hWnd, GWL_EXSTYLE, exStyle); michael@0: michael@0: if (HasGlass()) michael@0: memset(&mGlassMargins, 0, sizeof mGlassMargins); michael@0: mTransparencyMode = aMode; michael@0: michael@0: SetupTranslucentWindowMemoryBitmap(aMode); michael@0: UpdateGlass(); michael@0: } michael@0: michael@0: void nsWindow::SetupTranslucentWindowMemoryBitmap(nsTransparencyMode aMode) michael@0: { michael@0: if (eTransparencyTransparent == aMode) { michael@0: ResizeTranslucentWindow(mBounds.width, mBounds.height, true); michael@0: } else { michael@0: mTransparentSurface = nullptr; michael@0: mMemoryDC = nullptr; michael@0: } michael@0: } michael@0: michael@0: void nsWindow::ClearTranslucentWindow() michael@0: { michael@0: if (mTransparentSurface) { michael@0: nsRefPtr thebesContext = new gfxContext(mTransparentSurface); michael@0: thebesContext->SetOperator(gfxContext::OPERATOR_CLEAR); michael@0: thebesContext->Paint(); michael@0: UpdateTranslucentWindow(); michael@0: } michael@0: } michael@0: michael@0: nsresult nsWindow::UpdateTranslucentWindow() michael@0: { michael@0: if (mBounds.IsEmpty()) michael@0: return NS_OK; michael@0: michael@0: ::GdiFlush(); michael@0: michael@0: BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA }; michael@0: SIZE winSize = { mBounds.width, mBounds.height }; michael@0: POINT srcPos = { 0, 0 }; michael@0: HWND hWnd = WinUtils::GetTopLevelHWND(mWnd, true); michael@0: RECT winRect; michael@0: ::GetWindowRect(hWnd, &winRect); michael@0: michael@0: // perform the alpha blend michael@0: bool updateSuccesful = michael@0: ::UpdateLayeredWindow(hWnd, nullptr, (POINT*)&winRect, &winSize, mMemoryDC, michael@0: &srcPos, 0, &bf, ULW_ALPHA); michael@0: michael@0: if (!updateSuccesful) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: #endif //MOZ_XUL michael@0: michael@0: /************************************************************** michael@0: ************************************************************** michael@0: ** michael@0: ** BLOCK: Popup rollup hooks michael@0: ** michael@0: ** Deals with CaptureRollup on popup windows. michael@0: ** michael@0: ************************************************************** michael@0: **************************************************************/ michael@0: michael@0: // Schedules a timer for a window, so we can rollup after processing the hook event michael@0: void nsWindow::ScheduleHookTimer(HWND aWnd, UINT aMsgId) michael@0: { michael@0: // In some cases multiple hooks may be scheduled michael@0: // so ignore any other requests once one timer is scheduled michael@0: if (sHookTimerId == 0) { michael@0: // Remember the window handle and the message ID to be used later michael@0: sRollupMsgId = aMsgId; michael@0: sRollupMsgWnd = aWnd; michael@0: // Schedule native timer for doing the rollup after michael@0: // this event is done being processed michael@0: sHookTimerId = ::SetTimer(nullptr, 0, 0, (TIMERPROC)HookTimerForPopups); michael@0: NS_ASSERTION(sHookTimerId, "Timer couldn't be created."); michael@0: } michael@0: } michael@0: michael@0: #ifdef POPUP_ROLLUP_DEBUG_OUTPUT michael@0: int gLastMsgCode = 0; michael@0: extern MSGFEventMsgInfo gMSGFEvents[]; michael@0: #endif michael@0: michael@0: // Process Menu messages, rollup when popup is clicked. michael@0: LRESULT CALLBACK nsWindow::MozSpecialMsgFilter(int code, WPARAM wParam, LPARAM lParam) michael@0: { michael@0: #ifdef POPUP_ROLLUP_DEBUG_OUTPUT michael@0: if (sProcessHook) { michael@0: MSG* pMsg = (MSG*)lParam; michael@0: michael@0: int inx = 0; michael@0: while (gMSGFEvents[inx].mId != code && gMSGFEvents[inx].mStr != nullptr) { michael@0: inx++; michael@0: } michael@0: if (code != gLastMsgCode) { michael@0: if (gMSGFEvents[inx].mId == code) { michael@0: #ifdef DEBUG michael@0: PR_LOG(gWindowsLog, PR_LOG_ALWAYS, michael@0: ("MozSpecialMessageProc - code: 0x%X - %s hw: %p\n", michael@0: code, gMSGFEvents[inx].mStr, pMsg->hwnd)); michael@0: #endif michael@0: } else { michael@0: #ifdef DEBUG michael@0: PR_LOG(gWindowsLog, PR_LOG_ALWAYS, michael@0: ("MozSpecialMessageProc - code: 0x%X - %d hw: %p\n", michael@0: code, gMSGFEvents[inx].mId, pMsg->hwnd)); michael@0: #endif michael@0: } michael@0: gLastMsgCode = code; michael@0: } michael@0: PrintEvent(pMsg->message, FALSE, FALSE); michael@0: } michael@0: #endif // #ifdef POPUP_ROLLUP_DEBUG_OUTPUT michael@0: michael@0: if (sProcessHook && code == MSGF_MENU) { michael@0: MSG* pMsg = (MSG*)lParam; michael@0: ScheduleHookTimer( pMsg->hwnd, pMsg->message); michael@0: } michael@0: michael@0: return ::CallNextHookEx(sMsgFilterHook, code, wParam, lParam); michael@0: } michael@0: michael@0: // Process all mouse messages. Roll up when a click is in a native window michael@0: // that doesn't have an nsIWidget. michael@0: LRESULT CALLBACK nsWindow::MozSpecialMouseProc(int code, WPARAM wParam, LPARAM lParam) michael@0: { michael@0: if (sProcessHook) { michael@0: switch (WinUtils::GetNativeMessage(wParam)) { michael@0: case WM_LBUTTONDOWN: michael@0: case WM_RBUTTONDOWN: michael@0: case WM_MBUTTONDOWN: michael@0: case WM_MOUSEWHEEL: michael@0: case WM_MOUSEHWHEEL: michael@0: { michael@0: MOUSEHOOKSTRUCT* ms = (MOUSEHOOKSTRUCT*)lParam; michael@0: nsIWidget* mozWin = WinUtils::GetNSWindowPtr(ms->hwnd); michael@0: if (mozWin) { michael@0: // If this window is windowed plugin window, the mouse events are not michael@0: // sent to us. michael@0: if (static_cast(mozWin)->mWindowType == eWindowType_plugin) michael@0: ScheduleHookTimer(ms->hwnd, (UINT)wParam); michael@0: } else { michael@0: ScheduleHookTimer(ms->hwnd, (UINT)wParam); michael@0: } michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: return ::CallNextHookEx(sCallMouseHook, code, wParam, lParam); michael@0: } michael@0: michael@0: // Process all messages. Roll up when the window is moving, or michael@0: // is resizing or when maximized or mininized. michael@0: LRESULT CALLBACK nsWindow::MozSpecialWndProc(int code, WPARAM wParam, LPARAM lParam) michael@0: { michael@0: #ifdef POPUP_ROLLUP_DEBUG_OUTPUT michael@0: if (sProcessHook) { michael@0: CWPSTRUCT* cwpt = (CWPSTRUCT*)lParam; michael@0: PrintEvent(cwpt->message, FALSE, FALSE); michael@0: } michael@0: #endif michael@0: michael@0: if (sProcessHook) { michael@0: CWPSTRUCT* cwpt = (CWPSTRUCT*)lParam; michael@0: if (cwpt->message == WM_MOVING || michael@0: cwpt->message == WM_SIZING || michael@0: cwpt->message == WM_GETMINMAXINFO) { michael@0: ScheduleHookTimer(cwpt->hwnd, (UINT)cwpt->message); michael@0: } michael@0: } michael@0: michael@0: return ::CallNextHookEx(sCallProcHook, code, wParam, lParam); michael@0: } michael@0: michael@0: // Register the special "hooks" for dropdown processing. michael@0: void nsWindow::RegisterSpecialDropdownHooks() michael@0: { michael@0: NS_ASSERTION(!sMsgFilterHook, "sMsgFilterHook must be NULL!"); michael@0: NS_ASSERTION(!sCallProcHook, "sCallProcHook must be NULL!"); michael@0: michael@0: DISPLAY_NMM_PRT("***************** Installing Msg Hooks ***************\n"); michael@0: michael@0: // Install msg hook for moving the window and resizing michael@0: if (!sMsgFilterHook) { michael@0: DISPLAY_NMM_PRT("***** Hooking sMsgFilterHook!\n"); michael@0: sMsgFilterHook = SetWindowsHookEx(WH_MSGFILTER, MozSpecialMsgFilter, michael@0: nullptr, GetCurrentThreadId()); michael@0: #ifdef POPUP_ROLLUP_DEBUG_OUTPUT michael@0: if (!sMsgFilterHook) { michael@0: PR_LOG(gWindowsLog, PR_LOG_ALWAYS, michael@0: ("***** SetWindowsHookEx is NOT installed for WH_MSGFILTER!\n")); michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: // Install msg hook for menus michael@0: if (!sCallProcHook) { michael@0: DISPLAY_NMM_PRT("***** Hooking sCallProcHook!\n"); michael@0: sCallProcHook = SetWindowsHookEx(WH_CALLWNDPROC, MozSpecialWndProc, michael@0: nullptr, GetCurrentThreadId()); michael@0: #ifdef POPUP_ROLLUP_DEBUG_OUTPUT michael@0: if (!sCallProcHook) { michael@0: PR_LOG(gWindowsLog, PR_LOG_ALWAYS, michael@0: ("***** SetWindowsHookEx is NOT installed for WH_CALLWNDPROC!\n")); michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: // Install msg hook for the mouse michael@0: if (!sCallMouseHook) { michael@0: DISPLAY_NMM_PRT("***** Hooking sCallMouseHook!\n"); michael@0: sCallMouseHook = SetWindowsHookEx(WH_MOUSE, MozSpecialMouseProc, michael@0: nullptr, GetCurrentThreadId()); michael@0: #ifdef POPUP_ROLLUP_DEBUG_OUTPUT michael@0: if (!sCallMouseHook) { michael@0: PR_LOG(gWindowsLog, PR_LOG_ALWAYS, michael@0: ("***** SetWindowsHookEx is NOT installed for WH_MOUSE!\n")); michael@0: } michael@0: #endif michael@0: } michael@0: } michael@0: michael@0: // Unhook special message hooks for dropdowns. michael@0: void nsWindow::UnregisterSpecialDropdownHooks() michael@0: { michael@0: DISPLAY_NMM_PRT("***************** De-installing Msg Hooks ***************\n"); michael@0: michael@0: if (sCallProcHook) { michael@0: DISPLAY_NMM_PRT("***** Unhooking sCallProcHook!\n"); michael@0: if (!::UnhookWindowsHookEx(sCallProcHook)) { michael@0: DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallProcHook!\n"); michael@0: } michael@0: sCallProcHook = nullptr; michael@0: } michael@0: michael@0: if (sMsgFilterHook) { michael@0: DISPLAY_NMM_PRT("***** Unhooking sMsgFilterHook!\n"); michael@0: if (!::UnhookWindowsHookEx(sMsgFilterHook)) { michael@0: DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sMsgFilterHook!\n"); michael@0: } michael@0: sMsgFilterHook = nullptr; michael@0: } michael@0: michael@0: if (sCallMouseHook) { michael@0: DISPLAY_NMM_PRT("***** Unhooking sCallMouseHook!\n"); michael@0: if (!::UnhookWindowsHookEx(sCallMouseHook)) { michael@0: DISPLAY_NMM_PRT("***** UnhookWindowsHookEx failed for sCallMouseHook!\n"); michael@0: } michael@0: sCallMouseHook = nullptr; michael@0: } michael@0: } michael@0: michael@0: // This timer is designed to only fire one time at most each time a "hook" function michael@0: // is used to rollup the dropdown. In some cases, the timer may be scheduled from the michael@0: // hook, but that hook event or a subsequent event may roll up the dropdown before michael@0: // this timer function is executed. michael@0: // michael@0: // For example, if an MFC control takes focus, the combobox will lose focus and rollup michael@0: // before this function fires. michael@0: VOID CALLBACK nsWindow::HookTimerForPopups(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime) michael@0: { michael@0: if (sHookTimerId != 0) { michael@0: // if the window is nullptr then we need to use the ID to kill the timer michael@0: BOOL status = ::KillTimer(nullptr, sHookTimerId); michael@0: NS_ASSERTION(status, "Hook Timer was not killed."); michael@0: sHookTimerId = 0; michael@0: } michael@0: michael@0: if (sRollupMsgId != 0) { michael@0: // Note: DealWithPopups does the check to make sure that the rollup widget is set. michael@0: LRESULT popupHandlingResult; michael@0: nsAutoRollup autoRollup; michael@0: DealWithPopups(sRollupMsgWnd, sRollupMsgId, 0, 0, &popupHandlingResult); michael@0: sRollupMsgId = 0; michael@0: sRollupMsgWnd = nullptr; michael@0: } michael@0: } michael@0: michael@0: BOOL CALLBACK nsWindow::ClearResourcesCallback(HWND aWnd, LPARAM aMsg) michael@0: { michael@0: nsWindow *window = WinUtils::GetNSWindowPtr(aWnd); michael@0: if (window) { michael@0: window->ClearCachedResources(); michael@0: } michael@0: return TRUE; michael@0: } michael@0: michael@0: void michael@0: nsWindow::ClearCachedResources() michael@0: { michael@0: if (mLayerManager && michael@0: mLayerManager->GetBackendType() == LayersBackend::LAYERS_BASIC) { michael@0: mLayerManager->ClearCachedResources(); michael@0: } michael@0: ::EnumChildWindows(mWnd, nsWindow::ClearResourcesCallback, 0); michael@0: } michael@0: michael@0: static bool IsDifferentThreadWindow(HWND aWnd) michael@0: { michael@0: return ::GetCurrentThreadId() != ::GetWindowThreadProcessId(aWnd, nullptr); michael@0: } michael@0: michael@0: // static michael@0: bool michael@0: nsWindow::EventIsInsideWindow(nsWindow* aWindow) michael@0: { michael@0: RECT r; michael@0: ::GetWindowRect(aWindow->mWnd, &r); michael@0: DWORD pos = ::GetMessagePos(); michael@0: POINT mp; michael@0: mp.x = GET_X_LPARAM(pos); michael@0: mp.y = GET_Y_LPARAM(pos); michael@0: michael@0: // was the event inside this window? michael@0: return static_cast(::PtInRect(&r, mp)); michael@0: } michael@0: michael@0: // static michael@0: bool michael@0: nsWindow::GetPopupsToRollup(nsIRollupListener* aRollupListener, michael@0: uint32_t* aPopupsToRollup) michael@0: { michael@0: // If we're dealing with menus, we probably have submenus and we don't want michael@0: // to rollup some of them if the click is in a parent menu of the current michael@0: // submenu. michael@0: *aPopupsToRollup = UINT32_MAX; michael@0: nsAutoTArray widgetChain; michael@0: uint32_t sameTypeCount = michael@0: aRollupListener->GetSubmenuWidgetChain(&widgetChain); michael@0: for (uint32_t i = 0; i < widgetChain.Length(); ++i) { michael@0: nsIWidget* widget = widgetChain[i]; michael@0: if (EventIsInsideWindow(static_cast(widget))) { michael@0: // Don't roll up if the mouse event occurred within a menu of the michael@0: // same type. If the mouse event occurred in a menu higher than that, michael@0: // roll up, but pass the number of popups to Rollup so that only those michael@0: // of the same type close up. michael@0: if (i < sameTypeCount) { michael@0: return false; michael@0: } michael@0: michael@0: *aPopupsToRollup = sameTypeCount; michael@0: break; michael@0: } michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: // static michael@0: bool michael@0: nsWindow::NeedsToHandleNCActivateDelayed(HWND aWnd) michael@0: { michael@0: // While popup is open, popup window might be activated by other application. michael@0: // At this time, we need to take back focus to the previous window but it michael@0: // causes flickering its nonclient area because WM_NCACTIVATE comes before michael@0: // WM_ACTIVATE and we cannot know which window will take focus at receiving michael@0: // WM_NCACTIVATE. Therefore, we need a hack for preventing the flickerling. michael@0: // michael@0: // If non-popup window receives WM_NCACTIVATE at deactivating, default michael@0: // wndproc shouldn't handle it as deactivating. Instead, at receiving michael@0: // WM_ACTIVIATE after that, WM_NCACTIVATE should be sent again manually. michael@0: // This returns true if the window needs to handle WM_NCACTIVATE later. michael@0: michael@0: nsWindow* window = WinUtils::GetNSWindowPtr(aWnd); michael@0: return window && !window->IsPopup(); michael@0: } michael@0: michael@0: // static michael@0: bool michael@0: nsWindow::DealWithPopups(HWND aWnd, UINT aMessage, michael@0: WPARAM aWParam, LPARAM aLParam, LRESULT* aResult) michael@0: { michael@0: NS_ASSERTION(aResult, "Bad outResult"); michael@0: michael@0: // XXX Why do we use the return value of WM_MOUSEACTIVATE for all messages? michael@0: *aResult = MA_NOACTIVATE; michael@0: michael@0: if (!::IsWindowVisible(aWnd)) { michael@0: return false; michael@0: } michael@0: michael@0: nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener(); michael@0: NS_ENSURE_TRUE(rollupListener, false); michael@0: michael@0: nsCOMPtr popup = rollupListener->GetRollupWidget(); michael@0: if (!popup) { michael@0: return false; michael@0: } michael@0: michael@0: static bool sSendingNCACTIVATE = false; michael@0: static bool sPendingNCACTIVATE = false; michael@0: uint32_t popupsToRollup = UINT32_MAX; michael@0: michael@0: nsWindow* popupWindow = static_cast(popup.get()); michael@0: UINT nativeMessage = WinUtils::GetNativeMessage(aMessage); michael@0: switch (nativeMessage) { michael@0: case WM_LBUTTONDOWN: michael@0: case WM_RBUTTONDOWN: michael@0: case WM_MBUTTONDOWN: michael@0: case WM_NCLBUTTONDOWN: michael@0: case WM_NCRBUTTONDOWN: michael@0: case WM_NCMBUTTONDOWN: michael@0: if (!EventIsInsideWindow(popupWindow) && michael@0: GetPopupsToRollup(rollupListener, &popupsToRollup)) { michael@0: break; michael@0: } michael@0: return false; michael@0: michael@0: case WM_MOUSEWHEEL: michael@0: case WM_MOUSEHWHEEL: michael@0: // We need to check if the popup thinks that it should cause closing michael@0: // itself when mouse wheel events are fired outside the rollup widget. michael@0: if (!EventIsInsideWindow(popupWindow)) { michael@0: *aResult = MA_ACTIVATE; michael@0: if (rollupListener->ShouldRollupOnMouseWheelEvent() && michael@0: GetPopupsToRollup(rollupListener, &popupsToRollup)) { michael@0: break; michael@0: } michael@0: } michael@0: return false; michael@0: michael@0: case WM_ACTIVATEAPP: michael@0: break; michael@0: michael@0: case WM_ACTIVATE: michael@0: // NOTE: Don't handle WA_INACTIVE for preventing popup taking focus michael@0: // because we cannot distinguish it's caused by mouse or not. michael@0: if (LOWORD(aWParam) == WA_ACTIVE && aLParam) { michael@0: nsWindow* window = WinUtils::GetNSWindowPtr(aWnd); michael@0: if (window && window->IsPopup()) { michael@0: // Cancel notifying widget listeners of deactivating the previous michael@0: // active window (see WM_KILLFOCUS case in ProcessMessage()). michael@0: sJustGotDeactivate = false; michael@0: // Reactivate the window later. michael@0: ::PostMessageW(aWnd, MOZ_WM_REACTIVATE, aWParam, aLParam); michael@0: return true; michael@0: } michael@0: // Don't rollup the popup when focus moves back to the parent window michael@0: // from a popup because such case is caused by strange mouse drivers. michael@0: nsWindow* prevWindow = michael@0: WinUtils::GetNSWindowPtr(reinterpret_cast(aLParam)); michael@0: if (prevWindow && prevWindow->IsPopup()) { michael@0: return false; michael@0: } michael@0: } else if (LOWORD(aWParam) == WA_INACTIVE) { michael@0: nsWindow* activeWindow = michael@0: WinUtils::GetNSWindowPtr(reinterpret_cast(aLParam)); michael@0: if (sPendingNCACTIVATE && NeedsToHandleNCActivateDelayed(aWnd)) { michael@0: // If focus moves to non-popup widget or focusable popup, the window michael@0: // needs to update its nonclient area. michael@0: if (!activeWindow || !activeWindow->IsPopup()) { michael@0: sSendingNCACTIVATE = true; michael@0: ::SendMessageW(aWnd, WM_NCACTIVATE, false, 0); michael@0: sSendingNCACTIVATE = false; michael@0: } michael@0: sPendingNCACTIVATE = false; michael@0: } michael@0: // If focus moves from/to popup, we don't need to rollup the popup michael@0: // because such case is caused by strange mouse drivers. michael@0: if (activeWindow) { michael@0: if (activeWindow->IsPopup()) { michael@0: return false; michael@0: } michael@0: nsWindow* deactiveWindow = WinUtils::GetNSWindowPtr(aWnd); michael@0: if (deactiveWindow && deactiveWindow->IsPopup()) { michael@0: return false; michael@0: } michael@0: } michael@0: } else if (LOWORD(aWParam) == WA_CLICKACTIVE) { michael@0: // If the WM_ACTIVATE message is caused by a click in a popup, michael@0: // we should not rollup any popups. michael@0: if (EventIsInsideWindow(popupWindow) || michael@0: !GetPopupsToRollup(rollupListener, &popupsToRollup)) { michael@0: return false; michael@0: } michael@0: } michael@0: break; michael@0: michael@0: case MOZ_WM_REACTIVATE: michael@0: // The previous active window should take back focus. michael@0: if (::IsWindow(reinterpret_cast(aLParam))) { michael@0: ::SetForegroundWindow(reinterpret_cast(aLParam)); michael@0: } michael@0: return true; michael@0: michael@0: case WM_NCACTIVATE: michael@0: if (!aWParam && !sSendingNCACTIVATE && michael@0: NeedsToHandleNCActivateDelayed(aWnd)) { michael@0: // Don't just consume WM_NCACTIVATE. It doesn't handle only the michael@0: // nonclient area state change. michael@0: ::DefWindowProcW(aWnd, aMessage, TRUE, aLParam); michael@0: // Accept the deactivating because it's necessary to receive following michael@0: // WM_ACTIVATE. michael@0: *aResult = TRUE; michael@0: sPendingNCACTIVATE = true; michael@0: return true; michael@0: } michael@0: return false; michael@0: michael@0: case WM_MOUSEACTIVATE: michael@0: if (!EventIsInsideWindow(popupWindow) && michael@0: GetPopupsToRollup(rollupListener, &popupsToRollup)) { michael@0: // WM_MOUSEACTIVATE may be caused by moving the mouse (e.g., X-mouse michael@0: // of TweakUI is enabled. Then, check if the popup should be rolled up michael@0: // with rollup listener. If not, just consume the message. michael@0: if (HIWORD(aLParam) == WM_MOUSEMOVE && michael@0: !rollupListener->ShouldRollupOnMouseActivate()) { michael@0: return true; michael@0: } michael@0: // Otherwise, it should be handled by wndproc. michael@0: return false; michael@0: } michael@0: michael@0: // Prevent the click inside the popup from causing a change in window michael@0: // activation. Since the popup is shown non-activated, we need to eat any michael@0: // requests to activate the window while it is displayed. Windows will michael@0: // automatically activate the popup on the mousedown otherwise. michael@0: return true; michael@0: michael@0: case WM_KILLFOCUS: michael@0: // If focus moves to other window created in different process/thread, michael@0: // e.g., a plugin window, popups should be rolled up. michael@0: if (IsDifferentThreadWindow(reinterpret_cast(aWParam))) { michael@0: break; michael@0: } michael@0: return false; michael@0: michael@0: case WM_MOVING: michael@0: case WM_SIZING: michael@0: case WM_MENUSELECT: michael@0: break; michael@0: michael@0: default: michael@0: return false; michael@0: } michael@0: michael@0: // Only need to deal with the last rollup for left mouse down events. michael@0: NS_ASSERTION(!mLastRollup, "mLastRollup is null"); michael@0: michael@0: bool consumeRollupEvent; michael@0: if (nativeMessage == WM_LBUTTONDOWN) { michael@0: POINT pt; michael@0: pt.x = GET_X_LPARAM(aLParam); michael@0: pt.y = GET_Y_LPARAM(aLParam); michael@0: ::ClientToScreen(aWnd, &pt); michael@0: nsIntPoint pos(pt.x, pt.y); michael@0: michael@0: consumeRollupEvent = michael@0: rollupListener->Rollup(popupsToRollup, &pos, &mLastRollup); michael@0: NS_IF_ADDREF(mLastRollup); michael@0: } else { michael@0: consumeRollupEvent = michael@0: rollupListener->Rollup(popupsToRollup, nullptr, nullptr); michael@0: } michael@0: michael@0: // Tell hook to stop processing messages michael@0: sProcessHook = false; michael@0: sRollupMsgId = 0; michael@0: sRollupMsgWnd = nullptr; michael@0: michael@0: // If we are NOT supposed to be consuming events, let it go through michael@0: if (consumeRollupEvent && nativeMessage != WM_RBUTTONDOWN) { michael@0: *aResult = MA_ACTIVATE; michael@0: return true; michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: /************************************************************** michael@0: ************************************************************** michael@0: ** michael@0: ** BLOCK: Misc. utility methods and functions. michael@0: ** michael@0: ** General use. michael@0: ** michael@0: ************************************************************** michael@0: **************************************************************/ michael@0: michael@0: // Note that the result of GetTopLevelWindow method can be different from the michael@0: // result of WinUtils::GetTopLevelHWND(). The result can be non-floating michael@0: // window. Because our top level window may be contained in another window michael@0: // which is not managed by us. michael@0: nsWindow* nsWindow::GetTopLevelWindow(bool aStopOnDialogOrPopup) michael@0: { michael@0: nsWindow* curWindow = this; michael@0: michael@0: while (true) { michael@0: if (aStopOnDialogOrPopup) { michael@0: switch (curWindow->mWindowType) { michael@0: case eWindowType_dialog: michael@0: case eWindowType_popup: michael@0: return curWindow; michael@0: default: michael@0: break; michael@0: } michael@0: } michael@0: michael@0: // Retrieve the top level parent or owner window michael@0: nsWindow* parentWindow = curWindow->GetParentWindow(true); michael@0: michael@0: if (!parentWindow) michael@0: return curWindow; michael@0: michael@0: curWindow = parentWindow; michael@0: } michael@0: } michael@0: michael@0: static BOOL CALLBACK gEnumWindowsProc(HWND hwnd, LPARAM lParam) michael@0: { michael@0: DWORD pid; michael@0: ::GetWindowThreadProcessId(hwnd, &pid); michael@0: if (pid == GetCurrentProcessId() && ::IsWindowVisible(hwnd)) michael@0: { michael@0: gWindowsVisible = true; michael@0: return FALSE; michael@0: } michael@0: return TRUE; michael@0: } michael@0: michael@0: bool nsWindow::CanTakeFocus() michael@0: { michael@0: gWindowsVisible = false; michael@0: EnumWindows(gEnumWindowsProc, 0); michael@0: if (!gWindowsVisible) { michael@0: return true; michael@0: } else { michael@0: HWND fgWnd = ::GetForegroundWindow(); michael@0: if (!fgWnd) { michael@0: return true; michael@0: } michael@0: DWORD pid; michael@0: GetWindowThreadProcessId(fgWnd, &pid); michael@0: if (pid == GetCurrentProcessId()) { michael@0: return true; michael@0: } michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: void nsWindow::GetMainWindowClass(nsAString& aClass) michael@0: { michael@0: NS_PRECONDITION(aClass.IsEmpty(), "aClass should be empty string"); michael@0: nsresult rv = Preferences::GetString("ui.window_class_override", &aClass); michael@0: if (NS_FAILED(rv) || aClass.IsEmpty()) { michael@0: aClass.AssignASCII(sDefaultMainWindowClass); michael@0: } michael@0: } michael@0: michael@0: LPARAM nsWindow::lParamToScreen(LPARAM lParam) michael@0: { michael@0: POINT pt; michael@0: pt.x = GET_X_LPARAM(lParam); michael@0: pt.y = GET_Y_LPARAM(lParam); michael@0: ::ClientToScreen(mWnd, &pt); michael@0: return MAKELPARAM(pt.x, pt.y); michael@0: } michael@0: michael@0: LPARAM nsWindow::lParamToClient(LPARAM lParam) michael@0: { michael@0: POINT pt; michael@0: pt.x = GET_X_LPARAM(lParam); michael@0: pt.y = GET_Y_LPARAM(lParam); michael@0: ::ScreenToClient(mWnd, &pt); michael@0: return MAKELPARAM(pt.x, pt.y); michael@0: } michael@0: michael@0: void nsWindow::PickerOpen() michael@0: { michael@0: mPickerDisplayCount++; michael@0: } michael@0: michael@0: void nsWindow::PickerClosed() michael@0: { michael@0: NS_ASSERTION(mPickerDisplayCount > 0, "mPickerDisplayCount out of sync!"); michael@0: if (!mPickerDisplayCount) michael@0: return; michael@0: mPickerDisplayCount--; michael@0: if (!mPickerDisplayCount && mDestroyCalled) { michael@0: Destroy(); michael@0: } michael@0: } michael@0: michael@0: /************************************************************** michael@0: ************************************************************** michael@0: ** michael@0: ** BLOCK: ChildWindow impl. michael@0: ** michael@0: ** Child window overrides. michael@0: ** michael@0: ************************************************************** michael@0: **************************************************************/ michael@0: michael@0: // return the style for a child nsWindow michael@0: DWORD ChildWindow::WindowStyle() michael@0: { michael@0: DWORD style = WS_CLIPCHILDREN | nsWindow::WindowStyle(); michael@0: if (!(style & WS_POPUP)) michael@0: style |= WS_CHILD; // WS_POPUP and WS_CHILD are mutually exclusive. michael@0: VERIFY_WINDOW_STYLE(style); michael@0: return style; michael@0: }